/*
Simulation of a network of Izhikevich neurons, coupled by chemical synapses,
receiving uncorrelated, random input spiketrains.

The simulation was written by Ekkehard Ullner in 2013.

This is a modified version of E.U.'s original, stand-alone program,
for use e.g. via the ctypes ffi in Python.

Changelog:
- suport for networks with inhibitory synapses
- Neuron type switched from FitzHugh-Nagumo to Izhikevich
- Various simulation parameters exposed to allow arbitrary network topologies,
input patterns, neuron parameters etc.
- results are written to a provided buffer instead of text files
- the non-free, problematic[0] "Numerical Recipes" RAN1 random number generator
was replaced with a Mersenne Twister rng from the GNU scientific library.
    [0 "Random Numbers in Scientific Computing: An Introduction", Katzgraber, 2010
    http://arxiv.org/pdf/1005.4117.pdf]
- cosmetics and a minimum of documentation (i.e. the comments)

CK 2014-2016

The MIT License (MIT)

Copyright (c) 2013,2014 Ekkehard Ullner, Clemens Korndörfer

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

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

void sagwas(){
    puts("simulation version Oct 12 2016");
}

/* function simulate
 * ------------------
 * Runs a single network simulation with the given parameters and writes the resulting
 * voltage traces into a given buffer.
 *
 * Parameters:
 *
 * N: Number of rows i in the simulated grid of neurons. (regardless of network topology,
 *    the network is a 'grid' where each node is adressed by an (i,j) coordinate.)
 * M: number of columns j in the grid
 *
 * limit: number of simulation steps to run
 *
 * KT: maximum number of coupled neighbors of any node (degree of the network)
 * connection: function pointer, where
 *             connection(i,j,l, '0' | '1') must return the first (second) coordinate of the l'th afferent to cell ij
 *             connection(i,j,l, 's') must return the strength of that connection
 *
 * recording_voltage: array of shape (M,N,limit) in which simulation results will be written in row first order
 * recording_recov: same as recording_voltage, for the neuron's recovery variable
 * recording_spikes: same as recording_voltage, for binary log of spike events
 *
 * inputc_exc: array of shape (M,N) in row-first order. modulates the rate of input pulses fed into
 *              each cell, values within [0,1]. aka "the stimulus".
 * inputc_inh: same for inhibitory input pulses
 * laminex: lambda_in_ex, the rate of excitatory input spikes to input-receiving nodes
 * lamini: lambda_in_in,  the rate of inhibitory input spikes to input-receiving nodes
 * izhi_a: parameter a of the izhikevich neuron
 * izhi_b: parameter b of the izhikevich neuron
 * izhi_reset_c: reset constant of the neuron
 * izhi_recovery_d: recovery reset constant
 * con_upstr_exc: synapse conductivity of the excitatory random inputs
 * con_upstr_inh: synapse conductivity of the inhibitory random inputs
 * # lateral synapses:
 * taus: duration of transmitter presence after spike
 * alp: rising time constant of fraction of open receptors
 * bet: decay time constant of fraction of open receptors
 * # inhibitory synapses:
 * tauni: duration of transmitter presence after spike
 * ani: rising time constant of fraction of open receptors
 * bni: decay time constant of fraction of open receptors
 * # external excitatory synapses:
 * tauna: duration of transmitter presence after spike
 * ana: rising time constant of fraction of open receptors
 * bna: decay time constant of fraction of open receptors
 * activation_noise: scale of white noise added to each neuron's activation variable
 * seed: random seed > 0
 * verbose: print a lot or not
 * delta_t: integration step width
*/

void simulate(int M,
              int N,
              int limit,
              int KT,
              double (*connection)(int,int,int,char),
              double* recording_voltage,
              double* recording_recov,
              double* recording_spikes,
              double* inputc_exc,
              double* inputc_inh,
              double laminex,
              double lamini,
              double izhi_a,
              double izhi_b,
              double izhi_reset_c,
              double izhi_recovery_d,
              double con_upstr_exc,
              double con_upstr_inh,
              double taus,
              double alp,
              double bet,
              double tauni,
              double ani,
              double bni,
              double tauna,
              double ana,
              double bna,
              double activation_noise,
              int seed,
              int verbose,
              double delta_t){

    // say hello & show the current parametrisation & input pattern.
    if (verbose){
        printf("starting simulation (Izhikevich neuron)\n");
        printf("seed: %d\nM: %d\nN: %d\nlimit: %d\nKT: %d\nlaminex: %f\nlamini: %f\nizhi_a: %f\nizhi_b: %f\nizhi_reset_c: %f\nizhi_recovery_d: %f\ncon_upstr_exc: %f\ncon_upstr_inh: %f\ntaus: %f\nalp: %f\nbet: %f\ntauni: %f\nani: %f\nbni: %f\ntauna: %f\nana: %f\nbna: %f\nactivation_noise: %f\ndelta_t: %f\n",
                seed, M, N, limit, KT, laminex, lamini, izhi_a, izhi_b, izhi_reset_c, izhi_recovery_d, con_upstr_exc, con_upstr_inh, taus, alp, bet, tauni, ani, bni, tauna, ana, bna, activation_noise, delta_t);

        int i1,j1;
        int print_exc, print_inh;
        for (j1 = 0; j1<M; j1++ ){
            for (i1 = 0; i1<N; i1++ ){
                print_exc = inputc_exc[i1 + N*j1]  >  0;
                print_inh = inputc_inh[i1 + N*j1]  >  0;
                if (print_exc && print_inh) printf(" ±");
                else if (print_exc) printf(" +");
                else if (print_inh) printf(" -");
                else printf(" .");
            }
            printf("\n");
        }
    }

    assert(seed>0);
    gsl_rng* rng  =  gsl_rng_alloc(gsl_rng_mt19937);
    gsl_rng_set(rng, seed);

    // Initialisations & constant parameters:
    // neuron model:
    double xold[N][M],dx_h[N][M],xh[N][M],xnew[N][M]; // activation variable (previous value, first step, intermediate value, new value)
    double yold[N][M],dy_h[N][M],yh[N][M],ynew[N][M]; // recovery variable (previous value, first step, intermediate value, new value)
    double Isyn[N][M]; // collection of lateral input currents at each neuron in the current time step

    double spikes[N][M]; // recording of spike events in the current time step

    // lateral synapses:
    double rold[N][M],rh[N][M],rnew[N][M];  // fraction of open receptors (previous value, intermediate value, new value).

        // more precisely: r[i][j] is the fraction of open receptors at synapses anywhere in the network
        // that are the target of neuron (i,j). Since all synapses have the same rise and decay constants
        // alpha and beta, the effect of a spike at neuron i,j is the same at all of its target synapses.
        // We can therefore write the fractions of open receptors of all these target synapses as a
        // single variable r[i][j], associated with the source neuron i,j.

    double Tl[N][M]; // spike arrival times "T_j" (indexing follows the same logic as r[][])
    double Hs[N][M]; // transmitter concentrations "[T]_j" (...here, too)
    double Vna  = 0.0; // synaptic reversal potential (excitatory)
    double Vni  = -80; // synaptic reversal potential (inhibitory)

    // double taus = 0.01; // duration of transmitter presence after spike
    double Tm = 1.0; // maximum transmitter concentration

    // double alp = 8.0; // rising time constant of fraction of open receptors
    // double bet = 8.0; // decay time constant of fraction of open receptors

    // activatory external input synapses:
    double rnoa[N][M],rnha[N][M],rnna[N][M]; // fraction of open receptors
    double Tnla[N][M],Hna[N][M]; // spike arrival times and transmitter concentrations

    // double tauna  =  0.01; // duration of transmitter presence after spike
    double Tna  =  1.0; // maximum transmitter concentration

    // double ana  =  8.0; // rising time constant of fraction of open receptors
    // double bna  =  8.0; // decay time constant of fraction of open receptors

    // inhibitory external input synapses:
    double rnoi[N][M],rnhi[N][M],rnni[N][M]; // fraction of open receptors (previous value, intermediate value, new value)
    double Tnli[N][M],Hni[N][M]; // spike arrival times and transmitter concentrations

    // double tauni  =  0.01; // duration of transmitter presence after spike
    double Tni = 1.0; // maximum transmitter concentration

    // double ani = 8.0; // rising time constant of fraction of open receptors
    // double bni = 8.0; // decay time constant of fraction of open receptors

    // misc:
    double izhi_reset_threshold = 30; // spike detection threshold
    long step; // simulation step count
    // double delta_t = 0.001; // integration step width
    // double delta_t = 0.01; // integration step width
    double current_time = 0.0; // simulation time

    int i,j,l; // various loop variables over network nodes.

    int p1[N][M][KT],p2[N][M][KT]; // lookup tables holding the first (p1) and second (p2) coordinate of the KT'th afferent to neuron N,M
    float conductance_net[N][M][KT]; // lookup table: synapse conductance of the KT'th afferent to neuron N,M

    double in_exc[N][M]; // excitatory stimulus strength (input noise rate modulation) for neuron N,M
    double in_inh[N][M]; // inhibitory ...

    // remaining initialisations:
    for (j = 0;j<M;j++ ){
        for (i = 0;i<N;i++ ){
            in_exc[i][j] =  inputc_exc[i + N * j];
            in_inh[i][j] =  inputc_inh[i + N * j];

            xold[i][j] = 30*(gsl_rng_uniform(rng)-0.5);
            yold[i][j] = 30*(gsl_rng_uniform(rng)-0.5);
            rold[i][j] = 0.0;
            rnoa[i][j] = 0.0;
            rnoi[i][j] = 0.0;

            Tl[i][j] = -2 * taus;
            Hs[i][j] = 0.0;
            Isyn[i][j] = 0.0;
            Tnla[i][j] = -2 * tauna;
            Tnli[i][j] = -2 * tauni;
            Hna[i][j] = 0.0;
            Hni[i][j] = 0.0;
            // network connectivity lookup tables:
            for (l = 0;l<KT;l++ ){
                p1[i][j][l]  =  (int)connection(j,i,l,'0');
                p2[i][j][l]  =  (int)connection(j,i,l,'1');
                conductance_net[i][j][l] = connection(j,i,l,'s');
    }}}

    // // some more extreme verbosity for verification
    // printf("\n connectivity structure: \n");
    // for (l = 0; l<KT; l++){
    //     printf("\n\n%d. neighbour of each unit:\n\n", l);
    //     for (j = 0;j<M;j++ ){
    //         for (i = 0;i<N;i++ ){
    //             printf("(%d,%d)   ", p1[i][j][l], p2[i][j][l]);
    //         }
    //         printf("\n");
    //     }
    // }
    // for (l = 0; l<KT; l++){
    //     printf("\n\nconductance from %d. neighbour of each unit:\n\n", l);
    //     for (j = 0;j<M;j++ ){
    //         for (i = 0;i<N;i++ ){
    //             printf("%05.2f  ", conductance_net[i][j][l]);
    //         }
    //         printf("\n");
    //     }
    // }

    // begin stepwise integration by the implicit midpoint method
    for(step = 1; step<= limit;step++ ){
        if (verbose && (step % (limit/100)  ==  0)){
            printf("\r...%d%%",(int)(100 * step/(double)limit));
            fflush(stdout);
        }

        for (j = 0;j<M;j++ ){
            for (i = 0;i<N;i++ ){
                // set transmitter presence if there was a spike recently,
                // ...for synapses within the network..
                if (Tl[i][j] + taus>current_time) Hs[i][j] = 1.0 * Tm;
                else Hs[i][j] = 0.0;

                // ..for activatory external input synapses..
                if (Tnla[i][j] + tauna>current_time) Hna[i][j] = 1.0 * Tna;
                else  Hna[i][j] = 0.0;

                // ..and for inhibitory external input synapses.
                if (Tnli[i][j] + tauni>current_time) Hni[i][j] = 1.0 * Tni;
                else  Hni[i][j] = 0.0;

        }}

        // first integration step
        double x;
        double y;
        double I;
        double g;
        for (j = 0;j<M;j++ ){
            for (i = 0;i<N;i++ ){
                x = xold[i][j];
                y = yold[i][j];

                // collect lateral synaptic currents
                Isyn[i][j] = 0.0;
                for (l = 0;l<KT;l++ ){
                    if(p1[i][j][l]>=0 && p2[i][j][l]>=0){
                        // input currents to neuron (i,j) depend proportionally on
                        // r[ p1[i][j][l] ][ p2[i][j][l] ], that is, on the fraction of open
                        // receptors of all the synapses targeted by neighbour l projecting
                        // to neuron i,j. These synapses have a high fraction of open receptors
                        // if their source neuron recently fired a spike. Thus, input currents
                        // flow to neuron (i,j) if its neighbours have recently fired a spike.

                        // we use signed conductance values to encode excitatory vs inhibitory synapses.
                        // of course, conductance is in fact positive in both these synapses; what differs
                        // is the reversal potential.
                        g = conductance_net[i][j][l];
                        if (g > 0.0)
                            Isyn[i][j] -= g * rold[p1[i][j][l]][p2[i][j][l]] * (xold[i][j] - Vna);
                        else if (g < 0.0)
                            Isyn[i][j] -= -g * rold[p1[i][j][l]][p2[i][j][l]] * (xold[i][j] - Vni);

                    }
                }

                I = Isyn[i][j];

                // collect external synaptic currents
                I -= con_upstr_exc * rnoa[i][j] * (xold[i][j] - Vna);
                I -= con_upstr_inh * rnoi[i][j] * (xold[i][j] - Vni);

                // Izhikevich neuron:
                // dv/dt = 0.04v^2 + 5v + 140 - u + I
                // du/dt = a(bv - u)
                dx_h[i][j] = 0.04*x*x + 5*x + 140 - y + I;
                dy_h[i][j] = izhi_a * (izhi_b*x - y);

                // step:
                xh[i][j] = xold[i][j] + (dx_h[i][j])*delta_t;
                yh[i][j] = yold[i][j] + (dy_h[i][j])*delta_t;

                // fraction of open receptors.. dr/dt  =  alpha [T] (1 - r) -  beta r
                // ..of synapses within the network:
                rh[i][j] = rold[i][j] + (alp * Hs[i][j] * (1 - rold[i][j]) - bet * rold[i][j]) * delta_t;

                // ..of synapses receiving external noise, activatory:
                rnha[i][j] = rnoa[i][j] + (ana * Hna[i][j] * (1 - rnoa[i][j]) - bna * rnoa[i][j]) * delta_t;
                // ..of synapses receiving external noise, inhibitory:
                rnhi[i][j] = rnoi[i][j] + (ani * Hni[i][j] * (1 - rnoi[i][j]) - bni * rnoi[i][j]) * delta_t;

        }}

        // second integration step
        double dx;
        double dy;
        double Ihsyn;
        for (j = 0;j<M;j++ ){
            for (i = 0;i<N;i++ ){
                x = xh[i][j];
                y = yh[i][j];

                Ihsyn = 0.0;
                for (l = 0;l<KT;l++ ){
                    if(p1[i][j][l]>=0 && p2[i][j][l]>=0){
                        g = conductance_net[i][j][l];
                        if (g > 0)
                            Ihsyn -= g * rh[p1[i][j][l]][p2[i][j][l]] * (xh[i][j] - Vna);
                        else if (g < 0)
                            Ihsyn -= -g * rh[p1[i][j][l]][p2[i][j][l]] * (xh[i][j] - Vni);
                    }
                }

                I =  0.5 * (Isyn[i][j] + Ihsyn);

                // input currents from external synapses
                I -= 0.5 * con_upstr_exc * (rnoa[i][j] * (xold[i][j] - Vna)  +  rnha[i][j] * (xh[i][j] - Vna));
                I -= 0.5 * con_upstr_inh * (rnoi[i][j] * (xold[i][j] - Vni)  +  rnhi[i][j] * (xh[i][j] - Vni));

                // Izhikevich neuron:
                // dv/dt = 0.04v^2 + 5v + 140 - u + I
                // du/dt = a(bv -u)
                dx = 0.04*x*x + 5*x + 140 - y + I;
                dy = izhi_a * (izhi_b*x - y);

                xnew[i][j] = xold[i][j] + 0.5*(dx_h[i][j] + dx)*delta_t;
                ynew[i][j] = yold[i][j] + 0.5*(dy_h[i][j] + dy)*delta_t;

                // fraction of open receptors.. dr/dt  =  alpha [T] (1 - r) -  beta r
                // ..of synapses within the network:
                rnew[i][j] = rold[i][j] + 0.5 * (alp * Hs[i][j] * (1 - rold[i][j]) - bet * rold[i][j]  +  alp * Hs[i][j] * (1 - rh[i][j]) - bet * rh[i][j]) * delta_t;
                // ..of synapses receiving external noise, activatory:
                rnna[i][j] = rnoa[i][j] + 0.5 * (ana * Hna[i][j] * (1 - rnoa[i][j]) - bna * rnoa[i][j]  +  ana * Hna[i][j] * (1 - rnha[i][j]) - bna * rnha[i][j]) * delta_t;
                // ..of synapses receiving external noise, inhibitory:
                rnni[i][j] = rnoi[i][j] + 0.5 * (ani * Hni[i][j] * (1 - rnoi[i][j]) - bni * rnoi[i][j]  +  ani * Hni[i][j] * (1 - rnhi[i][j]) - bni * rnhi[i][j]) * delta_t;

        }}

        // identify spike times & prepare next step
        current_time = delta_t * step;
        for (j = 0;j<M;j++ ){
            for (i = 0;i<N;i++ ){
                // note spike times within the network
                if(xnew[i][j] >= izhi_reset_threshold){
                    xnew[i][j] = izhi_reset_c;
                    ynew[i][j] += izhi_recovery_d;
                    spikes[i][j] = 1;
                    Tl[i][j] = current_time;
                }
                else spikes[i][j] = 0;

                // sample random spike times for activatory external input
                if(gsl_rng_uniform(rng) <=  (laminex * (double)in_exc[i][j]) * delta_t){
                    Tnla[i][j] = current_time;
                }
                // sample random spike times for inhibitory external input
                if(gsl_rng_uniform(rng)<= (lamini * (double)in_inh[i][j]) * delta_t){
                   Tnli[i][j] = current_time;
                }

                // swap
                xold[i][j] = xnew[i][j];
                yold[i][j] = ynew[i][j];
                rold[i][j] = rnew[i][j];
                rnoa[i][j] = rnna[i][j];
                rnoi[i][j] = rnni[i][j];

                if (activation_noise > 0)
                    xold[i][j] += (gsl_rng_uniform(rng)-0.5)*activation_noise;
        }}

        // write the current network state into the provided output buffers.
        // each is a 3D array of shape (M,N,limit) in row first order,
        // so it has strides proportional to (N * limit, limit, 1).
        int linearind  =  0;
        for(int oi  =  0; oi < M; oi++ ) {
            for(int oj  =  0; oj < N; oj++ ) {
                    linearind  =  oi * limit * N  +  oj * limit  + step - 1;
                    recording_voltage[linearind]  =  xnew[oj][oi];
                    recording_recov[linearind]  = ynew[oj][oi];
                    //recording_recov[linearind] = (double) Tnla[oj][oi] == current_time; // <-uncomment to show input spikes instead
                    recording_spikes[linearind]  =  spikes[oj][oi];
            }

        }
    } // end of integration loop
    if (verbose){
        printf("\033[2K");
        fflush(stdout);
    }

    gsl_rng_free(rng);
}

// helper function to play with the random number generator.
void rantest(long seed,int N,double *  out){
    gsl_rng *  rng  =  gsl_rng_alloc(gsl_rng_mt19937); // initialize a mersenne twister rng
    gsl_rng_set(rng, seed); // seed it
    double number  =  - 1;

    for(int i = 0; i<N; i++ ){
        number  =  gsl_rng_uniform(rng); // sample a number
        printf("%ld  %f\n",seed,number);
        out[i]  =  number;
    }
    puts(" - - - ");

    gsl_rng_free(rng);
}


#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gsl/gsl_math.h>

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

/*! \file b_from_rot_a.c
 *  \brief calculates ror(b) to aloow an initial vector potential
 *
 *  This file is only called once after reading the initial condition.
 *  It is used to calculate b_ini from a initial vector potential, if needed.
 */

#ifdef BFROMROTA

void rot_a(void)
{
  long long ntot, ntotleft;
  int ndone;
  int *noffset, *nbuffer, *nsend, *nsend_local, *numlist, *ndonelist;
  int i, j, n;
  int npleft;
  int maxfill, source;
  int level, ngrp, sendTask, recvTask;
  int place, nexport;
  double dmax1, dmax2, fac;
  double sumt, sumcomm;

  MPI_Status status;

  noffset = (int *) mymalloc(sizeof(int) * NTask);	/* offsets of bunches in common list */
  nbuffer = (int *) mymalloc(sizeof(int) * NTask);
  nsend_local = (int *) mymalloc(sizeof(int) * NTask);
  nsend = (int *) mymalloc(sizeof(int) * NTask * NTask);
  ndonelist = (int *) mymalloc(sizeof(int) * NTask);

  NumSphUpdate = N_gas;

  numlist = (int *) mymalloc(NTask * sizeof(int) * NTask);
  MPI_Allgather(&NumSphUpdate, 1, MPI_INT, numlist, 1, MPI_INT, MPI_COMM_WORLD);
  for(i = 0, ntot = 0; i < NTask; i++)
    ntot += numlist[i];
  myfree(numlist);

  i = 0;			/* beginn with this index */
  ntotleft = ntot;		/* particles left for all tasks together */

  while(ntotleft > 0)
    {
      for(j = 0; j < NTask; j++)
	nsend_local[j] = 0;

      /* do local particles and prepare export list */
      for(nexport = 0, ndone = 0; i < N_gas && nexport < All.BunchSizeDensity - NTask; i++)
	{
	  ndone++;

	  for(j = 0; j < NTask; j++)
	    Exportflag[j] = 0;

	  rot_a_evaluate(i, 0);

	  for(j = 0; j < NTask; j++)
	    {
	      if(Exportflag[j])
		{
		  DensDataIn[nexport].Pos[0] = P[i].Pos[0];
		  DensDataIn[nexport].Pos[1] = P[i].Pos[1];
		  DensDataIn[nexport].Pos[2] = P[i].Pos[2];
		  /* using velocity structure for BPred ... */
		  DensDataIn[nexport].Vel[0] = SphP[i].BPred[0];
		  DensDataIn[nexport].Vel[1] = SphP[i].BPred[1];
		  DensDataIn[nexport].Vel[2] = SphP[i].BPred[2];

		  DensDataIn[nexport].Hsml = PPP[i].Hsml;
		  DensDataIn[nexport].Index = i;
		  DensDataIn[nexport].Task = j;
		  nexport++;
		  nsend_local[j]++;
		}
	    }
	}

      qsort(DensDataIn, nexport, sizeof(struct densdata_in), dens_compare_key);

      for(j = 1, noffset[0] = 0; j < NTask; j++)
	noffset[j] = noffset[j - 1] + nsend_local[j - 1];

      MPI_Allgather(nsend_local, NTask, MPI_INT, nsend, NTask, MPI_INT, MPI_COMM_WORLD);

      /* now do the particles that need to be exported */

      for(level = 1; level < (1 << PTask); level++)
	{
	  for(j = 0; j < NTask; j++)
	    nbuffer[j] = 0;
	  for(ngrp = level; ngrp < (1 << PTask); ngrp++)
	    {
	      maxfill = 0;
	      for(j = 0; j < NTask; j++)
		{
		  if((j ^ ngrp) < NTask)
		    if(maxfill < nbuffer[j] + nsend[(j ^ ngrp) * NTask + j])
		      maxfill = nbuffer[j] + nsend[(j ^ ngrp) * NTask + j];
		}
	      if(maxfill >= All.BunchSizeDensity)
		break;

	      sendTask = ThisTask;
	      recvTask = ThisTask ^ ngrp;

	      if(recvTask < NTask)
		{
		  if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
		    {
		      /* get the particles */
		      MPI_Sendrecv(&DensDataIn[noffset[recvTask]],
				   nsend_local[recvTask] * sizeof(struct densdata_in), MPI_BYTE,
				   recvTask, TAG_DENS_A,
				   &DensDataGet[nbuffer[ThisTask]],
				   nsend[recvTask * NTask + ThisTask] * sizeof(struct densdata_in),
				   MPI_BYTE, recvTask, TAG_DENS_A, MPI_COMM_WORLD, &status);
		    }
		}

	      for(j = 0; j < NTask; j++)
		if((j ^ ngrp) < NTask)
		  nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
	    }

	  for(j = 0; j < nbuffer[ThisTask]; j++)
	    {
	      rot_a_evaluate(j, 1);
	    }

	  MPI_Barrier(MPI_COMM_WORLD);

	  for(j = 0; j < NTask; j++)
	    nbuffer[j] = 0;
	  for(ngrp = level; ngrp < (1 << PTask); ngrp++)
	    {
	      maxfill = 0;
	      for(j = 0; j < NTask; j++)
		{
		  if((j ^ ngrp) < NTask)
		    if(maxfill < nbuffer[j] + nsend[(j ^ ngrp) * NTask + j])
		      maxfill = nbuffer[j] + nsend[(j ^ ngrp) * NTask + j];
		}
	      if(maxfill >= All.BunchSizeDensity)
		break;

	      sendTask = ThisTask;
	      recvTask = ThisTask ^ ngrp;

	      if(recvTask < NTask)
		{
		  if(nsend[ThisTask * NTask + recvTask] > 0 || nsend[recvTask * NTask + ThisTask] > 0)
		    {
		      /* send the results */
		      MPI_Sendrecv(&DensDataResult[nbuffer[ThisTask]],
				   nsend[recvTask * NTask + ThisTask] * sizeof(struct densdata_out),
				   MPI_BYTE, recvTask, TAG_DENS_B,
				   &DensDataPartialResult[noffset[recvTask]],
				   nsend_local[recvTask] * sizeof(struct densdata_out),
				   MPI_BYTE, recvTask, TAG_DENS_B, MPI_COMM_WORLD, &status);

		      /* add the result to the particles */
		      for(j = 0; j < nsend_local[recvTask]; j++)
			{
			  source = j + noffset[recvTask];
			  place = DensDataIn[source].Index;

			  SphP[place].BSmooth[0] += DensDataPartialResult[source].BSmooth[0];
			  SphP[place].BSmooth[1] += DensDataPartialResult[source].BSmooth[1];
			  SphP[place].BSmooth[2] += DensDataPartialResult[source].BSmooth[2];
			  SphP[place].DensityNorm += DensDataPartialResult[source].DensityNorm;
			}
		    }
		}

	      for(j = 0; j < NTask; j++)
		if((j ^ ngrp) < NTask)
		  nbuffer[j] += nsend[(j ^ ngrp) * NTask + j];
	    }

	  level = ngrp - 1;
	}

      MPI_Allgather(&ndone, 1, MPI_INT, ndonelist, 1, MPI_INT, MPI_COMM_WORLD);
      for(j = 0; j < NTask; j++)
	ntotleft -= ndonelist[j];
    }

  for(i = 0; i < N_gas; i++)
    for(j = 0; j < 3; j++)
#ifndef IGNORE_PERIODIC_IN_ROTA
      SphP[i].B[j] = SphP[i].BPred[j] = SphP[i].BSmooth[j] / SphP[i].d.Density;
#else
      SphP[i].B[j] = SphP[i].BPred[j] = SphP[i].BSmooth[j] / SphP[i].DensityNorm;
#endif
  myfree(ndonelist);
  myfree(nsend);
  myfree(nsend_local);
  myfree(nbuffer);
  myfree(noffset);

}

/*! This function represents the core of the calculus of rot of vector potential
 *  target particle may either be local, or reside in the communication
 *  buffer.
 */
void rot_a_evaluate(int target, int mode)
{
  int j, n;
  int startnode, numngb, numngb_inbox;
  double h, h2, fac, hinv, hinv3, hinv4;

  double wk, dwk;
  double dx, dy, dz, r, r2, u, mass_j, rho;
  double dbx, dby, dbz;

  double rotb[3];

  MyFloat *pos, *b;

  rho = rotb[0] = rotb[1] = rotb[2] = 0;

  if(mode == 0)
    {
      pos = P[target].Pos;
      b = SphP[target].BPred;
      h = PPP[target].Hsml;
    }
  else
    {
      pos = DensDataGet[target].Pos;
      b = DensDataGet[target].Vel;	/* Using Vel structure for BPred !!!! */
      h = DensDataGet[target].Hsml;
    }

  h2 = h * h;
  hinv = 1.0 / h;
#ifndef  TWODIMS
  hinv3 = hinv * hinv * hinv;
#else
  hinv3 = hinv * hinv / boxSize_Z;
#endif
  hinv4 = hinv3 * hinv;

  startnode = All.MaxPart;
  do
    {
      numngb_inbox = ngb_treefind_variable(&pos[0], 2 * h, &startnode);

      for(n = 0; n < numngb_inbox; n++)
	{
	  j = Ngblist[n];

	  dx = pos[0] - P[j].Pos[0];
	  dy = pos[1] - P[j].Pos[1];
	  dz = pos[2] - P[j].Pos[2];

	  dbx = b[0] - SphP[j].BPred[0];
	  dby = b[1] - SphP[j].BPred[1];
	  dbz = b[2] - SphP[j].BPred[2];

#ifndef IGNORE_PERIODIC_IN_ROTA
#ifdef PERIODIC			/*  now find the closest image in the given box size  */
	  if(dx > boxHalf_X)
	    dx -= boxSize_X;
	  if(dx < -boxHalf_X)
	    dx += boxSize_X;
	  if(dy > boxHalf_Y)
	    {
#ifdef BRIOWU
	      dbz /= dy;
#endif
	      dy -= boxSize_Y;
#ifdef BRIOWU
	      dbz *= dy;
#endif
	    }
	  if(dy < -boxHalf_Y)
	    {
#ifdef BRIOWU
	      dbz /= dy;
#endif
	      dy += boxSize_Y;
#ifdef BRIOWU
	      dbz *= dy;
#endif
	    }
	  if(dz > boxHalf_Z)
	    {
#ifdef BRIOWU
	      dbx /= dz;
#endif
	      dz -= boxSize_Z;
#ifdef BRIOWU
	      dbx *= dz;
#endif
	    }
	  if(dz < -boxHalf_Z)
	    {
#ifdef BRIOWU
	      dbx /= dz;
#endif
	      dz += boxSize_Z;
#ifdef BRIOWU
	      dbx *= dz;
#endif
	    }
#endif
#endif
	  r2 = dx * dx + dy * dy + dz * dz;

	  if(r2 < h2)
	    {
	      r = sqrt(r2);
	      u = r * hinv;
	      if(u < 0.5)
		{
		  wk = hinv3 * (KERNEL_COEFF_1 + KERNEL_COEFF_2 * (u - 1) * u * u);
		  dwk = hinv4 * u * (KERNEL_COEFF_3 * u - KERNEL_COEFF_4);
		}
	      else
		{
		  wk = hinv3 * KERNEL_COEFF_5 * (1.0 - u) * (1.0 - u) * (1.0 - u);
		  dwk = hinv4 * KERNEL_COEFF_6 * (1.0 - u) * (1.0 - u);
		}

	      mass_j = P[j].Mass;

	      rho += mass_j * wk;

	      if(r > 0)
		{
		  fac = mass_j * dwk / r;
#ifndef BRIOWU
		  rotb[0] += FLT(fac * (dz * dby - dy * dbz));
		  rotb[1] += FLT(fac * (dx * dbz - dz * dbx));
		  rotb[2] += FLT(fac * (dy * dbx - dx * dby));
#else
		  rotb[0] += FLT(fac * (-dy * dbz));
		  rotb[1] += FLT(fac * (-dz * dbx));
		  rotb[2] += FLT(fac * (0.0));
#endif
		}
	    }
	}

    }
  while(startnode >= 0);

  if(mode == 0)
    {
      SphP[target].BSmooth[0] = rotb[0];	/* giving back rot(B) in the Smooth */
      SphP[target].BSmooth[1] = rotb[1];	/* Data structure !!! */
      SphP[target].BSmooth[2] = rotb[2];
      SphP[target].DensityNorm = rho;
    }
  else
    {
      DensDataResult[target].BSmooth[0] = rotb[0];
      DensDataResult[target].BSmooth[1] = rotb[1];
      DensDataResult[target].BSmooth[2] = rotb[2];
      DensDataResult[target].DensityNorm = rho;
    }
}

#endif


/**
 *
 * RV-GOMEA
 *
 * If you use this software for any purpose, please cite the most recent publication:
 * A. Bouter, C. Witteveen, T. Alderliesten, P.A.N. Bosman. 2017.
 * Exploiting Linkage Information in Real-Valued Optimization with the Real-Valued
 * Gene-pool Optimal Mixing Evolutionary Algorithm. In Proceedings of the Genetic
 * and Evolutionary Computation Conference (GECCO 2017).
 * DOI: 10.1145/3071178.3071272
 *
 * Copyright (c) 1998-2017 Peter A.N. Bosman
 *
 * The software in this file is the proprietary information of
 * Peter A.N. Bosman.
 *
 * IN NO EVENT WILL THE AUTHOR OF THIS SOFTWARE BE LIABLE TO YOU FOR ANY
 * DAMAGES, INCLUDING BUT NOT LIMITED TO LOST PROFITS, LOST SAVINGS, OR OTHER
 * INCIDENTIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR THE INABILITY
 * TO USE SUCH PROGRAM, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. THE AUTHOR MAKES NO
 * REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE
 * AUTHOR SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY ANYONE AS A RESULT OF
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 *
 * The software in this file is the result of (ongoing) scientific research.
 * The following people have been actively involved in this research over
 * the years:
 * - Peter A.N. Bosman
 * - Dirk Thierens
 * - Jörn Grahl
 * - Anton Bouter
 *
 */
#pragma once

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <eigen3/Eigen/Dense>
#include <cblas.h>
#include <lapack.h>

using Eigen::MatrixXd;

#define PI 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798
#define FALSE 0
#define TRUE 1

namespace GOMEA
{
void *
Malloc(long size);
void
shrunkCovariance(MatrixXd & emp_cov, const double alpha);
void
shrunkCovarianceOAS(MatrixXd & emp_cov, const int pop_size);
float
choleskyDecomposition(MatrixXd & result, MatrixXd & matrix, int n);
void
lowerTriangularMatrixInverse(MatrixXd & A, const int n);
int *
mergeSort(double * array, int array_size);
void
mergeSortWithinBounds(double * array, int * sorted, int * tosort, int p, int q);
void
mergeSortWithinBoundsInt(int * array, int * sorted, int * tosort, int p, int q);

void
mergeSortMerge(double * array, int * sorted, int * tosort, int p, int r, int q);
int *
mergeSortInt(int * array, int array_size);
void
mergeSortMergeInt(int * array, int * sorted, int * tosort, int p, int r, int q);

int *
getRanks(double * array, int array_size);
int *
getRanksFromSorted(int * sorted, int array_size);

double
randomRealUniform01(void);
int
randomInt(int maximum);
double
random1DNormalUnit(void);
double
random1DNormalParameterized(double mean, double variance);
void
initializeRandomNumberGenerator(void);
int *
randomPermutation(int n);
int **
allPermutations(int length, int * numberOfPermutations);
int **
allPermutationsSubroutine(int from, int length, int * numberOfPermutations);

double
max(double x, double y);
double
min(double x, double y);
double
distanceEuclidean(double * solution_a, double * solution_b, int n);
double
distanceEuclidean2D(double x1, double y1, double x2, double y2);

double *
matrixVectorPartialMultiplication(double ** matrix,
                                  double *  vector,
                                  int       n0,
                                  int       number_of_elements,
                                  int *     element_indices);

extern int64_t random_seed, /* The seed used for the random-number generator. */
  random_seed_changing;     /* Internally used variable for randomly setting a random seed. */

extern double haveNextNextGaussian, /* Internally used variable for sampling the normal distribution. */
  nextNextGaussian;
}


#pragma once
#include "Type/peColor.h"
#include "Type\peBitmask.h"
#include "peCoreDefs.h"

#include <glm/detail/type_vec2.hpp>
#undef max
#include <gsl.h>
#include <random>

#pragma warning(push)
#pragma warning(disable : 4251)

/*
 * Everything in here is taking more or less one-to-one from 'Physically based
 * rendering' (Pharr, Humphreys, 2010)
 */

namespace pe {
struct Sample;
class peCoordSys;

//! \brief Represents a color spectrum. We will use RGB with floating-point
//! precision here
using Spectrum_t = RGB_32BitFloat;

//! \brief Types of BRDFs and BTDFs
enum class BxDFType {
  Reflection = 1 << 0,
  Transmission = 1 << 1,
  Diffuse = 1 << 2,
  Glossy = 1 << 3,
  Specular = 1 << 4,
  AllTypes = Diffuse | Glossy | Specular,
  AllReflection = Reflection | AllTypes,
  AllTransmission = Transmission | AllTypes,
  All = AllReflection | AllTransmission
};

template <> struct EnableEnumBitmask<BxDFType> : std::true_type {};

//! \brief BRDF or BTDF base class
class PE_CORE_API peBxDF {
public:
  virtual ~peBxDF() = default;
  explicit peBxDF(BxDFType type);

  bool HasFlags(BxDFType flags) const;

  auto Type() const { return _type; }

  //! \brief Evaluate this BxDF for the given outgoing and incoming vectors
  //! \param wo Outgoing vector
  //! \param wi Incoming vector
  //! \returns Value of the distribution function for the two vectors
  virtual Spectrum_t Eval(const glm::vec3 &wo, const glm::vec3 &wi) const = 0;

  //! \brief Sampling function for BxDF distributions that utilize delta
  //! distributions. Here, the incident direction wi cannot
  //!        be known to the user, hence the BxDF computes it
  //! \param wo Outgoing vector
  //! \param wi Incoming vector, will be computed by the BxDF
  //! \param rnd1 First uniform random variable
  //! \param rnd2 Second uniform random variable
  //! \param pdf Probability density function for this BxDF and the given pair
  //! of vectors \returns Value of the distribution function for the two vectors
  virtual Spectrum_t Sample_f(const glm::vec3 &wo, glm::vec3 &wi,
                              const float rnd1, const float rnd2,
                              float &pdf) const;

  //! \brief Computes the hemishperical-directional reflectance, which is the
  //! total reflection in the given direction due to constant illumination over
  //! the hemisphere. Not every BxDF will be able to compute this in closed
  //! form, so they will use something like a monte carlo algorithm to compute
  //! it, hence the <paramref name="samples"/> member
  //! \param wo Outgoing vector
  //! \param samples Samples
  //! \returns Hemispherical reflection around <paramref name="wo"/>
  virtual Spectrum_t rho(const glm::vec3 &wo,
                         const gsl::span<glm::vec2> &samples) const;

  //! \brief Computes the hemispherical-hemispherical reflectance, which is the
  //! fraction of incident light reflected by the surface when the incident
  //! light is the same from all directions. Not every BxDF will be able to
  //! compute this in closed form, so they will use something like a monte carlo
  //! algorithm to compute it
  //! \param samples1 First set of samples for monte carlo method
  //! \param samples2 Second set of samples for monte carlo method
  //! \returns Direction-independent reflectance
  virtual Spectrum_t rho(const gsl::span<glm::vec2> &samples1,
                         const gsl::span<glm::vec2> &samples2) const;

  //! \brief Returns the probability density function for the given pairs of
  //! vectors \param wo Outgoing vector in shading space \param wi Incoming
  //! vector in shading space \returns PDF
  virtual float Pdf(const glm::vec3 &wo, const glm::vec3 &wi) const;

private:
  const BxDFType _type;
};

#pragma region Fresnel

//! \brief Helper class to encapsulate fresnel reflectance
struct PE_CORE_API peFresnel {
  virtual ~peFresnel() {}
  virtual Spectrum_t Eval(float cosi) const = 0;
};

//! \brief Fresnel reflectance for a conductor
class PE_CORE_API peFresnelConductor : public peFresnel {
public:
  //! \brief Initializes this FresnelConductor structure with the given index of
  //! refraction and absorption
  //! \param eta Index of refraction of conductor
  //! \param k Absorption index of conductor
  peFresnelConductor(const Spectrum_t &eta, const Spectrum_t &k);
  Spectrum_t Eval(float cosi) const override;

private:
  const Spectrum_t _eta;
  const Spectrum_t _k;
};

//! \brief Fresnel reflectance for dielectric material
class PE_CORE_API peFresnelDielectric : public peFresnel {
public:
  //! \brief Initializes this FresnelDielectric structure with the given
  //! incident and transmitted medium indices of refraction
  //! \param etaIncident Index of refraction for incident material
  //! \param etaTransmitted Index of refraction for transmitted material
  peFresnelDielectric(float etaIncident, float etaTransmitted);
  Spectrum_t Eval(float cosi) const override;

private:
  const float _etaIndicent, _etaTransmitted;
};

#pragma endregion

//! \brief BRDF for specular reflection
class PE_CORE_API peSpecularReflection : public peBxDF {
public:
  peSpecularReflection(const Spectrum_t &spectrum, const peFresnel &fresnel);

  Spectrum_t Eval(const glm::vec3 &wo, const glm::vec3 &wi) const override;
  Spectrum_t Sample_f(const glm::vec3 &wo, glm::vec3 &wi, const float rnd1,
                      const float rnd2, float &pdf) const override;

private:
  const Spectrum_t _color;
  const peFresnel &_fresnel;
};

//! \brief Lambertian diffuse reflection
class PE_CORE_API peLambert : public peBxDF {
public:
  explicit peLambert(const Spectrum_t &color);
  Spectrum_t Eval(const glm::vec3 &wo, const glm::vec3 &wi) const override;

  Spectrum_t rho(const glm::vec3 &wo,
                 const gsl::span<glm::vec2> &samples) const override;
  Spectrum_t rho(const gsl::span<glm::vec2> &samples1,
                 const gsl::span<glm::vec2> &samples2) const override;

private:
  const Spectrum_t _color;
};

//! \brief Random values for BSDF sampling
struct PE_CORE_API BSDFSample {
  BSDFSample() = default;
  BSDFSample(const glm::vec2 &dir, float component);
  template <typename Rnd> explicit BSDFSample(Rnd &rng) {
    std::uniform_real_distribution<float> dist{0.f, 1.f};
    dir = {dist(rng), dist(rng)};
    component = dist(rng);
  }

  glm::vec2 dir;
  float component;
};

//! \brief Bidirectional scattering distribution function. Determines surface
//! properties of an object
class PE_CORE_API BSDF {
public:
  BSDF();

  BSDF(const BSDF &other);
  BSDF(BSDF &&other) noexcept;

  BSDF &operator=(const BSDF &);
  BSDF &operator=(BSDF &&) noexcept;

  void Add(peBxDF const *bxdf);

  uint32_t NumBxDFs() const;
  uint32_t NumBxDFsWithFlags(BxDFType flags) const;

  //! \brief Evaluate the BSDF for the given set of incoming and outgoing
  //! vectors \param outgoingWorld Outgoing vector in world space \param
  //! incomingWorld Incoming vector in world space \param shadingCoordSys
  //! Shading coordinate system \param flags Types of BxDFs to sample \param
  //! geometricNormal The normal of the actual geometry for the evaluated point
  //! \returns Evaluated spectrum
  Spectrum_t Eval(const glm::vec3 &outgoingWorld,
                  const glm::vec3 &incomingWorld,
                  const peCoordSys &shadingCoordSys,
                  const glm::vec3 &geometricNormal, BxDFType flags) const;

  //! \brief Sample this BSDF by evaluating a random BxDF
  Spectrum_t Sample_f(const glm::vec3 &wo, glm::vec3 &wi,
                      const peCoordSys &shadingCoordSys,
                      const glm::vec3 &geometryNormal, const BSDFSample &sample,
                      float &pdf, BxDFType flags, BxDFType &sampledType) const;

  //! \brief Sums up the hemispherical-hemispherical reflectance values of
  //! all assigned BxDFs \param rnd Random number generator for monte carlo
  //! method \param flags Types of BxDFs to sample \param sqrtSamples
  //! Sampling parameter for monte carlo \returns Summed reflectance
  Spectrum_t rho(std::default_random_engine &rnd,
                 BxDFType flags = BxDFType::All,
                 uint32_t sqrtSamples = 6) const;

  //! \brief Sums up the hemispherical-directional reflectance values of all
  //! assigned BxDFs \param wo Outgoing direction \param rnd Random number
  //! generator for monte carlo method \param flags Types of BxDFs to sample
  //! \param sqrtSamples Sampling parameter for monte carlo
  //! \returns Summed reflectance
  Spectrum_t rho(const glm::vec3 &wo, std::default_random_engine &rnd,
                 BxDFType flags = BxDFType::All,
                 uint32_t sqrtSamples = 6) const;

  //! \brief Probability density function of this BSDF for the given pair of
  //! vectors \param wo Outgoing vector in world space \param wi Incoming vector
  //! in world space
  float Pdf(const glm::vec3 &wo, const glm::vec3 &wi,
            const peCoordSys &shadingCoordSys,
            BxDFType flags = BxDFType::All) const;

private:
  constexpr static size_t MaxBxDF = 8;
  uint32_t _numBxdfs;
  std::array<peBxDF const *, MaxBxDF> _bxdfs;
};

#pragma region HelperFunctions

//! \brief Computes fresnel reflectance for dielectric materials
//! \param cosIncident Cosine of angle of incident direction
//! \param cosTransmitted Cosine of angle of transmitted direction
//! \param etaIncident Index of refraction for incident medium
//! \param etaTransmitted Index of refraction for transmitted medium
//! \returns Fresnel reflectance
Spectrum_t PE_CORE_API FresnelDielectric(float cosIncident,
                                         float cosTransmitted,
                                         const Spectrum_t &etaIncident,
                                         const Spectrum_t &etaTransmitted);

//! \brief Computes the fresnel reflectance for a conducting material
//! \param cosIndicent Cosine of the angle of incident direction
//! \param eta Index of refraction of the conductor
//! \param k Absorption coefficient
//! \returns Fresnel reflectance
Spectrum_t PE_CORE_API FresnelConductor(float cosIndicent,
                                        const Spectrum_t &eta,
                                        const Spectrum_t &k);

//! \brief Helper to evaluate fresnel shading for dieletric materials
//! \param cosIncident Cosine of angle of incident direction
//! \param etaIncident Index of refraction of incident medium
//! \param etaTransmitted Index of refraction of transmitted medium
//! \returns Fresnel reflectance
Spectrum_t PE_CORE_API EvalFresnelDielectric(float cosIncident,
                                             float etaIncident,
                                             float etaTransmitted);

#pragma endregion

} // namespace pe

#pragma warning(pop)


/**
 *
 * @file sgecon.c
 *
 *  PLASMA computational routines
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Jakub Kurzak
 * @author Ichitaro Yamazaki
 * @author Mathieu Faverge
 * @date 2012-10-04
 * @generated s Tue Jan  7 11:45:10 2014
 *
 **/
#include <lapacke.h>
#include "common.h"
#include <math.h>
#undef COMPLEX
#define REAL

/***************************************************************************//**
 *
 * @ingroup float
 *
 *  PLASMA_sgecon - estimates the reciprocal of the condition number
 *  of a general complex matrix A, in either the 1-norm or the infinity-norm,
 *  using the LU factorization computed by PLASMA_sgetrf().
 *
 *  An estimate is obtained for norm(inv(A)), and the reciprocal of the condition
 *  number is computed as
 *
 *    \f[ rcond = \frac{1}{\|\|A\-\| \times \-\|A^{-1}\|\|} \f]
 *
 *******************************************************************************
 *
 * @param[in] norm
 *          Specifies whether the 1-norm condition number
 *          or the infinity-norm condition number is required:
 *          = PlasmaOneNorm: One norm
 *          = PlasmaInfNorm: Infinity norm
 *
 * @param[in] N
 *          The order of the matrix A. N >= 0.
 *
 * @param[in] A
 *          The N-by-N matrix A.
 *
 * @param[in] LDA
 *          The leading dimension of the array A. LDA >= max(1,N).
 *
 * @param[in] Anorm
 *          If norm = PlasmaOneNorm, the 1-norm of the original matrix A.
 *          If norm = PlasmaInfNorm, the infinity-norm of the original matrix A.
 *
 * \param[out] rcond
 *          The reciprocal of the condition number of the matrix A,
 *          computed as stated above.
 *
 *******************************************************************************
 *
 * @return
 *          \retval PLASMA_SUCCESS successful exit
 *          \retval <0 if -i, the i-th argument had an illegal value
 *
 *******************************************************************************
 *
 * @sa PLASMA_sgecon_Tile
 * @sa PLASMA_sgecon_Tile_Async
 * @sa PLASMA_cgecon
 * @sa PLASMA_dgecon
 * @sa PLASMA_sgecon
 *
 ******************************************************************************/
int PLASMA_sgecon(PLASMA_enum norm, int N,
                  float *A, int LDA, float Anorm, float *rcond)
{
    int NB;
    int status;
    plasma_context_t *plasma;
    PLASMA_sequence *sequence = NULL;
    PLASMA_request request = PLASMA_REQUEST_INITIALIZER;
    PLASMA_desc descA;

    plasma = plasma_context_self();
    if (plasma == NULL) {
        plasma_fatal_error("PLASMA_sgecon", "PLASMA not initialized");
        return PLASMA_ERR_NOT_INITIALIZED;
    }
    /* Check input arguments */
    if (norm != PlasmaOneNorm && norm != PlasmaInfNorm) {
        plasma_error("PLASMA_sgecon", "illegal value of norm");
        return -1;
    }
    if (N < 0) {
        plasma_error("PLASMA_sgecon", "illegal value of N");
        return -2;
    }
    if (LDA < max(1,N)) {
        plasma_error("PLASMA_sgecon", "illegal value of LDA");
        return -4;
    }
    if (Anorm < 0.) {
        plasma_error("PLASMA_sgecon", "illegal value of Anorm");
        return -5;
    }

    /* Quick return */
    *rcond = (float)0.;
    if (N == 0) {
        *rcond = (float)1.;
        return PLASMA_SUCCESS;
    }
    else if (Anorm == 0.) {
        return PLASMA_SUCCESS;
    }

    /* Tune NB depending on M, N & NRHS; Set NBNB */
    status = plasma_tune(PLASMA_FUNC_SGESV, N, N, 0);
    if (status != PLASMA_SUCCESS) {
        plasma_error("PLASMA_sgecon", "plasma_tune() failed");
        return status;
    }
    /* Set NT */
    NB = PLASMA_NB;
    plasma_sequence_create(plasma, &sequence);

    if (PLASMA_TRANSLATION == PLASMA_OUTOFPLACE) {
        plasma_sooplap2tile(
            descA, A, NB, NB, LDA, N, 0, 0, N, N,
            sequence, &request, plasma_desc_mat_free(&(descA)));
    } else {
        plasma_siplap2tile(
            descA, A, NB, NB, LDA, N, 0, 0, N, N, sequence, &request);
    }

    /* Call the tile interface */
    PLASMA_sgecon_Tile_Async(norm, &descA, Anorm, rcond, sequence, &request);

    if (PLASMA_TRANSLATION == PLASMA_OUTOFPLACE) {
        plasma_dynamic_sync();
        plasma_desc_mat_free(&descA);
    } else {
        plasma_siptile2lap(descA, A, NB, NB, LDA, N, sequence, &request);
        plasma_dynamic_sync();
    }

    status = sequence->status;
    plasma_sequence_destroy(plasma, sequence);
    return status;
}

/***************************************************************************//**
 *
 * @ingroup float_Tile
 *
 *  PLASMA_sgecon_Tile - estimates the reciprocal of the condition number
 *  of a general complex matrix A, in either the 1-norm or the infinity-norm.
 *  Tile equivalent of PLASMA_sgecon().
 *  Operates on matrices stored by tiles.
 *  All matrices are passed through descriptors.
 *  All dimensions are taken from the descriptors.
 *
 *******************************************************************************
 *
 * @param[in] norm
 *          Specifies whether the 1-norm condition number
 *          or the infinity-norm condition number is required:
 *          = PlasmaOneNorm: One norm
 *          = PlasmaInfNorm: Infinity norm
 *
 * @param[in] A
 *          The N-by-N matrix A.
 *
 * @param[in] Anorm
 *          If norm = PlasmaOneNorm, the 1-norm of the original matrix A.
 *          If norm = PlasmaInfNorm, the infinity-norm of the original matrix A.
 *
 * \param[out] rcond
 *          The reciprocal of the condition number of the matrix A,
 *          computed as stated above.
 *
 *******************************************************************************
 *
 * @return
 *          \retval PLASMA_SUCCESS successful exit
 *          \retval <0 if -i, the i-th argument had an illegal value
 *
 *******************************************************************************
 *
 * @sa PLASMA_sgecon
 * @sa PLASMA_sgecon_Tile_Async
 * @sa PLASMA_cgecon_Tile
 * @sa PLASMA_dgecon_Tile
 * @sa PLASMA_sgecon_Tile
 *
 ******************************************************************************/
int PLASMA_sgecon_Tile(PLASMA_enum norm, PLASMA_desc *A, float Anorm, float *rcond)
{
    plasma_context_t *plasma;
    PLASMA_sequence *sequence = NULL;
    PLASMA_request request = PLASMA_REQUEST_INITIALIZER;
    int status;

    plasma = plasma_context_self();
    if (plasma == NULL) {
        plasma_fatal_error("PLASMA_sgecon_Tile", "PLASMA not initialized");
        return PLASMA_ERR_NOT_INITIALIZED;
    }
    plasma_sequence_create(plasma, &sequence);
    PLASMA_sgecon_Tile_Async(norm, A, Anorm, rcond, sequence, &request);
    plasma_dynamic_sync();
    status = sequence->status;
    plasma_sequence_destroy(plasma, sequence);
    return status;
}

/***************************************************************************//**
 *
 * @ingroup float_Tile_Async
 *
 *  PLASMA_sgecon_Tile_Async - estimates the reciprocal of the condition number
 *  of a general complex matrix A, in either the 1-norm or the infinity-norm.
 *  Non-blocking equivalent of PLASMA_sgecon_Tile().
 *  May return before the computation is finished.
 *  Allows for pipelining of operations at runtime.
 *
 *******************************************************************************
 *
 * @param[in] sequence
 *          Identifies the sequence of function calls that this call belongs to
 *          (for completion checks and exception handling purposes).
 *
 * @param[out] request
 *          Identifies this function call (for exception handling purposes).
 *
 *******************************************************************************
 *
 * @sa PLASMA_sgecon
 * @sa PLASMA_sgecon_Tile
 * @sa PLASMA_cgecon_Tile_Async
 * @sa PLASMA_dgecon_Tile_Async
 * @sa PLASMA_sgecon_Tile_Async
 *
 ******************************************************************************/
int PLASMA_sgecon_Tile_Async(PLASMA_enum norm, PLASMA_desc *A, float Anorm, float *rcond,
                             PLASMA_sequence *sequence, PLASMA_request *request)
{
    plasma_context_t *plasma;
    PLASMA_desc descA;
    PLASMA_desc descW;
    float *workN;
    float Ainvnorm;
    int kase, kase1;
    int isave[3], itrs = 0;
    int fallback = PLASMA_FALSE;

    plasma = plasma_context_self();
    if (plasma == NULL) {
        plasma_fatal_error("PLASMA_sgecon_Tile_Async", "PLASMA not initialized");
        return PLASMA_ERR_NOT_INITIALIZED;
    }
    if (sequence == NULL) {
        plasma_fatal_error("PLASMA_sgecon_Tile_Async", "NULL sequence");
        return PLASMA_ERR_UNALLOCATED;
    }
    if (request == NULL) {
        plasma_fatal_error("PLASMA_sgecon_Tile_Async", "NULL request");
        return PLASMA_ERR_UNALLOCATED;
    }
    /* Check sequence status */
    if (sequence->status == PLASMA_SUCCESS)
        request->status = PLASMA_SUCCESS;
    else
        return plasma_request_fail(sequence, request, PLASMA_ERR_SEQUENCE_FLUSHED);

    /* Check descriptors for correctness */
    if ( A->m != A->n ) {
        plasma_error("PLASMA_sgecon_Tile_Async", "invalid A descriptor (not square)");
        return plasma_request_fail(sequence, request, PLASMA_ERR_ILLEGAL_VALUE);
    }
    if (plasma_desc_check(A) != PLASMA_SUCCESS) {
        plasma_error("PLASMA_sgecon_Tile_Async", "invalid first descriptor");
        return plasma_request_fail(sequence, request, PLASMA_ERR_ILLEGAL_VALUE);
    } else {
        descA = *A;
    }
    /* Check input arguments */
    if (descA.nb != descA.mb) {
        plasma_error("PLASMA_sgecon_Tile_Async", "only square tiles supported");
        return plasma_request_fail(sequence, request, PLASMA_ERR_ILLEGAL_VALUE);
    }

    /* Quick return */
    *rcond = (float)0.;
    if (descA.m == 0) {
        *rcond = (float)1.;
        return PLASMA_SUCCESS;
    }
    else if (Anorm == 0.) {
        return PLASMA_SUCCESS;
    }

    /* Estimate the norm of inv(A). */
    Ainvnorm = (float)0.;
    if (norm == PlasmaOneNorm)
        kase1 = 1;
    else
        kase1 = 2;
    kase = 0;

#if defined(REAL)
    int *isgn = (int*)plasma_shared_alloc(plasma, descA.m, PlasmaInteger);
#endif

    workN = (float*)plasma_shared_alloc(plasma, descA.m, PlasmaRealFloat);
    plasma_sdesc_alloc( descW, descA.mb, descA.nb,
                        descA.m, 1, 0, 0, descA.m, 1, plasma_desc_mat_free(&(descW)));

    do {
        itrs ++;
#if defined(REAL)
        LAPACKE_slacn2_work( descA.m, workN, descW.mat, isgn, &Ainvnorm, &kase, isave);
#else
        LAPACKE_slacn2_work( descA.m, workN, descW.mat,       &Ainvnorm, &kase, isave);
#endif

#define FALLBACK
#ifdef  FALLBACK
        /*
         * Fall back to LAPACK
         */
        if( isnan(Ainvnorm) || isinf(Ainvnorm) || Ainvnorm > LAPACKE_slamch('O') ) {
            int info;
            float *Atmp = (float*)malloc(descA.m * descA.n * sizeof(float));

            plasma_sooptile2lap( descA, Atmp, descA.mb, descA.nb, descA.m, descA.n, sequence, request);
            plasma_dynamic_sync();
            info = LAPACKE_sgecon(LAPACK_COL_MAJOR, lapack_const(norm), descA.n, Atmp, descA.m, Anorm, rcond);
            free(Atmp);
            fallback = PLASMA_TRUE;
            sequence->status = info;
            kase = 0;
        }
#endif

        if (kase != 0) {
            if (kase == kase1) {
                /* Multiply by inv(L). */
                plasma_parallel_call_9(plasma_pstrsm,
                    PLASMA_enum, PlasmaLeft,
                    PLASMA_enum, PlasmaLower,
                    PLASMA_enum, PlasmaNoTrans,
                    PLASMA_enum, PlasmaUnit,
                    float, 1.0,
                    PLASMA_desc, descA,
                    PLASMA_desc, descW,
                    PLASMA_sequence*, sequence,
                    PLASMA_request*, request);

                /* Multiply by inv(U). */
                plasma_parallel_call_9(plasma_pstrsm,
                    PLASMA_enum, PlasmaLeft,
                    PLASMA_enum, PlasmaUpper,
                    PLASMA_enum, PlasmaNoTrans,
                    PLASMA_enum, PlasmaNonUnit,
                    float, 1.0,
                    PLASMA_desc, descA,
                    PLASMA_desc, descW,
                    PLASMA_sequence*, sequence,
                    PLASMA_request*, request);
            }
            else {
                /* Multiply by inv(U**T). */
                plasma_parallel_call_9(plasma_pstrsm,
                    PLASMA_enum, PlasmaLeft,
                    PLASMA_enum, PlasmaUpper,
                    PLASMA_enum, PlasmaTrans,
                    PLASMA_enum, PlasmaNonUnit,
                    float, 1.0,
                    PLASMA_desc, descA,
                    PLASMA_desc, descW,
                    PLASMA_sequence*, sequence,
                    PLASMA_request*, request);

                /* Multiply by inv(L**T). */
                plasma_parallel_call_9(plasma_pstrsm,
                    PLASMA_enum, PlasmaLeft,
                    PLASMA_enum, PlasmaLower,
                    PLASMA_enum, PlasmaTrans,
                    PLASMA_enum, PlasmaUnit,
                    float, 1.0,
                    PLASMA_desc, descA,
                    PLASMA_desc, descW,
                    PLASMA_sequence*, sequence,
                    PLASMA_request*, request);
            }
        }
        plasma_dynamic_sync();
    }
    while (kase != 0);

    /* Compute the estimate of the reciprocal condition number. */
    if ((Ainvnorm != 0.0) && (fallback == PLASMA_FALSE)) {
        *rcond = ((float)1.0 / Ainvnorm) / Anorm;
    }

#if defined(REAL)
    plasma_shared_free(plasma, isgn);
#endif
    plasma_shared_free(plasma, workN);
    plasma_desc_mat_free(&descW);

    return PLASMA_SUCCESS;
}


#ifndef NonLinearLSQ_h
#define NonLinearLSQ_h
/**
 * @file
 * $Revision: 4928 $
 * $Date: 2012-12-21 10:44:12 -0700 (Fri, 21 Dec 2012) $
 * $Id: NonLinearLSQ.h 4928 2012-12-21 17:44:12Z slambright@GS.DOI.NET $
 *
 *   Unless noted otherwise, the portions of Isis written by the USGS are
 *   public domain. See individual third-party library and package descriptions
 *   for intellectual property information, user agreements, and related
 *   information.
 *
 *   Although Isis has been used by the USGS, no warranty, expressed or
 *   implied, is made by the USGS as to the accuracy and functioning of such
 *   software and related material nor shall the fact of distribution
 *   constitute any such warranty, and no responsibility is assumed by the
 *   USGS in connection therewith.
 *
 *   For additional information, launch
 *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
 *   in a browser or see the Privacy & Disclaimers page on the Isis website,
 *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
 *   http://www.usgs.gov/privacy.html.
 */

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>

#include <QString>

#include <tnt_array1d.h>
#include <tnt_array1d_utils.h>
#include <tnt_array2d.h>
#include <tnt_array2d_utils.h>

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

#include "IException.h"

namespace Isis {

  /**
   * @brief NonLinearLSQ Computes a fit using a Levenberg-Marquardt algorithm
   *
   * This virtual base class uses the GSL toolkit to apply the
   * Levenberg-Marquardt algorithm to fit data to a non-linear equation using
   * least squares.
   *
   * @ingroup Utility
   * @author 2007-11-15 Kris Becker
   *
   * @internal
   */
  class NonLinearLSQ {
    public:
      typedef TNT::Array1D<double> NLVector;
      typedef TNT::Array2D<double> NLMatrix;

      //  Constructors and Destructor
      NonLinearLSQ() : _fitParms(), _uncert(), _nIters(0), _maxIters(50),
                       _status(0), _userTerminated(false), _userMessage() {}

      /** Destructor */
      virtual ~NonLinearLSQ() { }

      virtual int nSize() const = 0;
      virtual int nParms() const = 0;

      /**
       * @brief Sets the maximum number of iterations
       *
       * @param m User provides the maximum number iterations
       */
      void setMaxIters(int m) { _maxIters = m; }

      /**
       * @brief Maximum number iterations for valid solution
       *
       *
       * @return int Maximum resolutions
       */
      int maxIters() const { return (_maxIters); }

      virtual NLVector guess()  = 0;
      virtual NLVector f_x(const NLVector &x) = 0;
      virtual NLMatrix df_x(const NLVector &x) = 0;

      virtual double absErr() const { return (1.0E-4); }
      virtual double relErr() const { return (1.0E-4); }

      int curvefit();
      /** Return status of last fit processing */
      inline int status() const { return (_status); }
      /** Determine success from last fit processing */
      inline bool success() const { return (_status == GSL_SUCCESS); }
      /** Check status for success of the given condition  */
      inline bool success(int status) const { return (status == GSL_SUCCESS); }
      /** Return error message pertaining to last fit procesing */
      inline QString statusstr() const {
        return (QString(gsl_strerror(_status)));
      }
      /** Return error message given status condition */
      inline QString statusstr(int status) const {
        return (QString(gsl_strerror(status)));
      }

      /** Default interation test simply returns input status */
      virtual int checkIteration(const int Iter, const NLVector &fitcoefs,
                                 const NLVector &uncerts, double cplxconj,
                                 int Istatus) {
        return (Istatus);
      }

      /** Return coefficients from last fit processing */
      inline NLVector coefs() const { return (_fitParms); }
      /** Return uncertainties from last fit processing */
      inline NLVector uncert() const { return (_uncert); }
      /** Return number of iterations from last fit processing */
      inline int nIterations() const { return (_nIters); }

    protected:
      void Terminate(const QString &message = "");
      void Abort(const QString &reason = "");

      bool doContinue() const { return (!_userTerminated); }

    private:
      NLVector    _fitParms;
      NLVector    _uncert;
      int         _nIters;
      int         _maxIters;
      int         _status;
      bool        _userTerminated;
      QString _userMessage;

      struct _nlsqPointer {
          NonLinearLSQ *nlsq;
      };
      static int f(const gsl_vector *x, void *params, gsl_vector *fx);
      static int df(const gsl_vector *x, void *params, gsl_matrix *J);
      static int fdf(const gsl_vector *x, void *params, gsl_vector *fx,
                     gsl_matrix *J);

      NLVector gslToNlsq(const gsl_vector *v) const;
      NLMatrix gslToNlsq(const gsl_matrix *m) const;
      gsl_vector *NlsqTogsl(const NLVector &v, gsl_vector *gv = 0) const;
      gsl_matrix *NlsqTogsl(const NLMatrix &m, gsl_matrix *gm = 0) const;
      NLVector getUncertainty(const gsl_matrix *m) const;
  };

}     // namespace Isis
#endif


/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
#pragma once

#include <gsl.h>
#include <nlohmann/json_fwd.hpp>
#include <cstdint>
#include <string>

namespace cb {
namespace crypto {
enum class Algorithm { MD5, SHA1, SHA256, SHA512 };

bool isSupported(Algorithm algorithm);

const int MD5_DIGEST_SIZE = 16;
const int SHA1_DIGEST_SIZE = 20;
const int SHA256_DIGEST_SIZE = 32;
const int SHA512_DIGEST_SIZE = 64;

/**
 * Generate a HMAC digest of the key and data by using the given
 * algorithm
 *
 * @throws std::invalid_argument - unsupported algorithm
 *         std::runtime_error - Failures generating the HMAC
 */
std::string HMAC(Algorithm algorithm,
                 std::string_view key,
                 std::string_view data);

/**
 * Generate a PBKDF2_HMAC digest of the key and data by using the given
 * algorithm
 *
 * @throws std::invalid_argument - unsupported algorithm
 *         std::runtime_error - Failures generating the HMAC
 */
std::string PBKDF2_HMAC(Algorithm algorithm,
                        const std::string& pass,
                        std::string_view salt,
                        unsigned int iterationCount);

/**
 * Generate a digest by using the requested algorithm
 */
std::string digest(Algorithm algorithm, std::string_view data);

enum class Cipher { AES_256_cbc };

Cipher to_cipher(const std::string& str);

/**
 * Encrypt the specified data by using a given cipher
 *
 * @param cipher The cipher to use
 * @param key The key used for encryption
 * @param ivec The IV to use for encryption
 * @param data The Pointer to the data to encrypt
 * @return The encrypted data
 */
std::string encrypt(Cipher cipher,
                    std::string_view key,
                    std::string_view iv,
                    std::string_view data);

/**
 * Encrypt the specified data
 *
 * {
 *    "cipher" : "name of the cipher",
 *    "key" : "base64 of the raw key",
 *    "iv" : "base64 of the raw iv"
 * }
 *
 * @param meta the json description of the encryption to use
 * @param data Pointer to the data to encrypt
 * @param length the length of the data to encrypt
 * @return The encrypted data
 */
std::string encrypt(const nlohmann::json& json, std::string_view data);

/**
 * Decrypt the specified data by using a given cipher
 *
 * @param cipher The cipher to use
 * @param key The key used for encryption
 * @param ivec The IV to use for encryption
 * @param data The data to decrypt
 * @return The decrypted data
 */
std::string decrypt(Cipher cipher,
                    std::string_view key,
                    std::string_view iv,
                    std::string_view data);

/**
 * Decrypt the specified data
 *
 * {
 *    "cipher" : "name of the cipher",
 *    "key" : "base64 of the raw key",
 *    "iv" : "base64 of the raw iv"
 * }
 *
 * @param meta the json description of the encryption to use
 * @param data Pointer to the data to decrypt
 * @param length the length of the data to decrypt
 * @return The decrypted data
 */
std::string decrypt(const nlohmann::json& json, std::string_view data);

} // namespace crypto
} // namespace cb


#pragma once

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

namespace Library
{
	class Mesh;

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

	public:
		ProxyModel(Game& game, const std::shared_ptr<Camera>& camera, const std::string& modelFileName, float scale = 1.0f);
		ProxyModel(const ProxyModel&) = delete;
		ProxyModel(ProxyModel&&) = default;
		ProxyModel& operator=(const ProxyModel&) = delete;
		ProxyModel& operator=(ProxyModel&&) = default;
		~ProxyModel() = default;

		const DirectX::XMFLOAT3& Position() const;
		const DirectX::XMFLOAT3& Direction() const;
		const DirectX::XMFLOAT3& Up() const;
		const DirectX::XMFLOAT3& Right() const;

		DirectX::XMVECTOR PositionVector() const;
		DirectX::XMVECTOR DirectionVector() const;
		DirectX::XMVECTOR UpVector() const;
		DirectX::XMVECTOR RightVector() const;

		bool& DisplayWireframe();

		void SetPosition(float x, float y, float z);
		void SetPosition(DirectX::FXMVECTOR position);
		void SetPosition(const DirectX::XMFLOAT3& position);

		void ApplyRotation(DirectX::CXMMATRIX transform);
		void ApplyRotation(const DirectX::XMFLOAT4X4& transform);

		void SetColor(const DirectX::XMFLOAT4& color);

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

	private:
		DirectX::XMFLOAT4X4 mWorldMatrix{ MatrixHelper::Identity };
		DirectX::XMFLOAT3 mPosition{ Vector3Helper::Zero };
		DirectX::XMFLOAT3 mDirection{ Vector3Helper::Forward };
		DirectX::XMFLOAT3 mUp{ Vector3Helper::Up };
		DirectX::XMFLOAT3 mRight{ Vector3Helper::Right };
		BasicMaterial mMaterial;
		std::string mModelFileName;
		float mScale;
		winrt::com_ptr<ID3D11Buffer> mVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mIndexBuffer;
		std::uint32_t mIndexCount{ 0 };
		bool mDisplayWireframe{ true };
		bool mUpdateWorldMatrix{ true };
		bool mUpdateMaterial{ true };
	};
}


/**
 * APER_CHECK - create a FITS image showing the locations of
 *               apertures.
 */
#include "aper_check.h"
#include <stdio.h>
#include <stdlib.h>
#include <gsl/gsl_vector.h>
#include "spce_output.h"

void mark_trace_in_aXe_mask(ap_pixel * ap_p, aXe_mask *mask)
{
  gsl_vector_int *trace_inds;
  int i, ind;

  trace_inds = (gsl_vector_int *) get_trace_inds (ap_p);

  for (i = 0; i < (int)trace_inds->size; i++)
    {
      ind = gsl_vector_int_get (trace_inds, i);
      fprintf(stderr,"%d %d\n",ap_p[ind].p_x,ap_p[ind].p_y);
    }

  gsl_vector_int_free(trace_inds);
}

/**
   Function to create and return a gsl array of the same size as the grism
   part of n observation structure.

   @param ob a pointer to an observation structure
   @return a pointer to a newly allocated aXe_mask structure

*/
aXe_mask *
aXe_mask_init (observation * ob)
{
  aXe_mask *mask;
  long i,j;
  double v;

     /* Allocated space for the mask array */
  mask = (aXe_mask *) malloc (sizeof (aXe_mask));
  if (!mask)
    {
      aXe_message (aXe_M_FATAL, __FILE__, __LINE__, "Out of memory.");
    }

  /* Create the GSL image array */
  mask->img = gsl_matrix_alloc (ob->grism->size1, ob->grism->size2);
  //  fprintf(stderr,"%ld %ld\n",ob->grism->size1,ob->grism->size2);

  /* Initialise the mask array */
  for (i=0;i<(int)ob->grism->size1;i++) {
    for (j=0;j<(int)ob->grism->size2;j++) {
      v = gsl_matrix_get(ob->grism,i,j);
      gsl_matrix_set(mask->img, i,j, v);

    }
  }

  //gsl_matrix_set_all (mask->img, 1.0);

  return mask;
}

/**
 * This function sets all the pixels listed in an ap_pixel list
 * in an aXe_mask to 0.0

    @param a pointer to a ap_pixel array
    @param mask an existing aXe_mask structure

*/
void
add_ap_p_to_aXe_mask (ap_pixel * ap_p, aXe_mask * mask)
{
  ap_pixel *cur_p;

  if (ap_p==NULL) return;

  for (cur_p = ap_p; cur_p->p_x != -1; cur_p++)
    {

      /* Loop over pixels which are valid */
      if (!isnan (cur_p->count))
        {
          //   fprintf(stderr,"%d %d\n",cur_p->p_x, cur_p->p_y);

          gsl_matrix_set (mask->img, cur_p->p_x, cur_p->p_y, 0.0);
        }
    }
}


#ifndef SNPINFER_DATASTRUCTURE
#define SNPINFER_DATASTRUCTURE

#define NUMPRECISION 1e-6

#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <vector>
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <iterator>
#include <omp.h>
#include <sys/stat.h>
using namespace std;

#define GSL_DLL
#include <gsl/gsl_sys.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_cdf.h>
#include <gsl/gsl_sf.h>
#include <gsl/gsl_fit.h>

typedef struct SNPINFO {
        string chr;
	int posst, posed;//, label;
        //int err, info, st, ed, shift;
	string snpid;
	//double qual;
	//vector<char> alleles;
} SNPINFO;

#define MINUSINFINITE -1000000000
#define PI 3.14159265359

typedef struct MYDATA {
	int indN, totalN, L, ploidity; //indN = N*plodity, totalN = N, but if replicates > 1, then totalN > N
	int *indIndex; //index of individuals (true individuals, not haploids, length+1 for total copies, =totalN) (necessary when there are replicates per individual)
	float *data; //length = indindex[last]*ploidity*L;
	int *asz;
	vector<vector<int> > fixState; //fix states, ~ pop, indN of them
	vector<vector<bool> > fixAllele; //fix data without imputation, ~ data, totalN of them; NOTE: false is fix, true is to impute!
	vector<vector<int> > breaks; //must contain start and end position as double breaks

	//additional info
	vector<SNPINFO> snpinfo;
	vector<string> indinfo;
	vector<string> fyinfo, fxinfo;
} MYDATA;

typedef struct PARAUNIT {
	vector<float> allele;
	int lapseN, popN;
} PARAUNIT;

typedef struct TENSORPARA {
	//recombination parameters
	double priorW, probAlpha, defmut, *rPrior, *popr; //priorW is for recomb rate
							//probAlpha is for states proportion
	bool *rec, *lapse;
	float *recombN, trueindN;
	float *indWeight, *idw;

	//parameter for states
	int maxK, maxHapK; //maxHapK is used if number of states is fixed;//12/18/15: maxK is current number of cluster? and maxHapK is the maximum allowed if >0?
	int *pop;
	float *nh;
	vector<vector<PARAUNIT> > param; //LxKxZ, where K=maxK, Z=asz
	vector<vector<int> > flips;
	double *Vh, *Q, A;

	//control parameters
	int burnin, mcmc;
	bool shrinkclass, singlecall, imputedata;
	bool addsample; //graudually add samples, used for haplotype inference
	bool samplefull; //true for haplotype inference
	char changeAlpha; //add (>0) or reduce (<0) probAlpha at the begining, add used for haplotype inference, reduce used for stratification mapping
	int splitstop; //# of pops, beyond which no more splitting
	int refweight; //weight of reference data with known states
	char maximum; //sample or maximize, 3bits abc: a: maximum recomb, b: maximum state, c: maximum allele
	bool samplemaximum; //indicating if first sample and then take maximum, used for pop inference
	bool logscale; //indicating if probability is in local scale, used for popinfer
	double recrate; //recombination rate to be used for set up recomb priors
	int recombcut; //above which position specific recomb is counted
	double heteroVh; //0 if Vh is global, > 0 if locally Vh changes. Only implemented for ploidity = 1, and not implemented in greedyswitch function
} TENSORPARA;

typedef struct TENSORPARAP0 {
	float *recombN0;
	float *nh0; //*nh0pp;
	double *Q0;
	unsigned short *param0;//, *param0pp;
	int clustersz0, popn0, unitsz0, totalN0;
} TENSORPARA0;

inline float fast_log2(float val)
{
   int * const    exp_ptr = reinterpret_cast <int *> (&val);
   int            x = *exp_ptr;
   const int      log_2 = ((x >> 23) & 255) - 128;
   x &= ~(255 << 23);
   x += 127 << 23;
   *exp_ptr = x;

   val = ((-1.0f/3) * val + 2) * val - 2.0f/3;   // (1)

   return (val + log_2);
}

inline float fast_log(const float &val)
{
   return (fast_log2 (val) * 0.69314718f);
}

//void call_IDEAS(int, char *argv[]);

#endif


#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_drotm (const int N, double *X, const int incX, double *Y,
	     const int incY, const double *P)
{
#define BASE double
#include "source_rotm.h"
#undef BASE
}