//====---- Sudoku/Location.h                                          ----====//
//
// class Location: represent locations within a board,
// and calculate location related properties.
//====--------------------------------------------------------------------====//
//
// Everything is `constexpr` and `noexcept`.
// All values are `const`.
//
// A separate Location_Block class offers block properties.
// There is no implicit conversion between these.
//
//====--------------------------------------------------------------------====//
#pragma once

#include "Size.h"

#include <gsl/gsl> // index

#include <type_traits> // is_signed

namespace Sudoku
{
template<int N>
class Location
{
	using Size  = ::Sudoku::Size<N>;
	using index = gsl::index;

	// prefer signed integers for calculations
	static_assert(std::is_signed_v<decltype(Size::base)>);
	static_assert(std::is_signed_v<decltype(Size::elem)>);

	static constexpr gsl::index location(index row, index col) noexcept
	{
		return row * Size::elem + col; // [0,full)
	}

public:
	// constructors
	constexpr Location() = default;
	explicit constexpr Location(index element) noexcept : id_(element) {}
	constexpr Location(index row, index col) noexcept : id_(location(row, col))
	{
	}

	// information
	[[nodiscard]] constexpr index element() const noexcept
	{
		return id_; // default [0,full)
	}
	[[nodiscard]] constexpr index row() const noexcept
	{
		return id_ / Size::elem; //[0,elem)
	}
	[[nodiscard]] constexpr index col() const noexcept
	{
		return id_ % Size::elem; //[0,elem)
	}
	[[nodiscard]] constexpr index block() const noexcept
	{
		return row() / Size::base * Size::base + col() / Size::base; // [0,elem)
	}
	[[nodiscard]] constexpr index block_row() const noexcept
	{
		return row() % Size::base; // [0,base)
	}
	[[nodiscard]] constexpr index block_col() const noexcept
	{
		return col() % Size::base; // [0,base)
	}
	[[nodiscard]] constexpr index block_elem() const noexcept
	{
		return block_row() * Size::base + block_col(); // [0,elem)
	}

	// comparison
	friend constexpr bool
		operator==(const Location& a, const Location& b) noexcept
	{ // Friend definitions: abseil.io/tips/99
		return a.id_ == b.id_;
	}

private:
	const index id_{};
};

//====--------------------------------------------------------------------====//

template<int N>
class Location_Block
{
	using Size     = ::Sudoku::Size<N>;
	using Location = ::Sudoku::Location<N>;

	// prefer signed integers for calculations
	static_assert(std::is_signed_v<decltype(Size::base)>);

	static constexpr gsl::index
		block_element(gsl::index row, gsl::index col) noexcept
	{
		return row * Size::base + col; // [0,elem)
	}
	static constexpr Location
		block_loc(gsl::index id, gsl::index element) noexcept
	{
		const gsl::index row{
			(id / Size::base) * Size::base + element / Size::base};
		const gsl::index col{
			(id % Size::base) * Size::base + element % Size::base};
		return Location(row, col);
	}
	static constexpr Location
		block_loc(gsl::index id, gsl::index row, gsl::index col) noexcept
	{
		return block_loc(id, block_element(row, col));
	}

public:
	constexpr Location_Block() = default;
	explicit constexpr Location_Block(Location loc) noexcept : loc_(loc)
	{ // empty constructor
	}
	constexpr Location_Block(gsl::index id, gsl::index element) noexcept
		: loc_(block_loc(id, element))
	{ // empty constructor
	}
	constexpr Location_Block(
		gsl::index id, gsl::index row, gsl::index col) noexcept
		: loc_(block_loc(id, row, col))
	{ // empty constructor
	}

	[[nodiscard]] constexpr gsl::index id() const noexcept
	{
		return loc_.block(); // [0,elem)
	}
	[[nodiscard]] constexpr gsl::index element() const noexcept
	{
		return loc_.block_elem(); // [0,elem)
	}
	[[nodiscard]] constexpr gsl::index row() const noexcept
	{
		return loc_.block_row(); // [0,base)
	}
	[[nodiscard]] constexpr gsl::index col() const noexcept
	{
		return loc_.block_col(); // [0,base)
	}

	// [[implicit]]
	// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
	constexpr operator Location() const noexcept { return loc_; }

private:
	const Location loc_{};
};

//====--------------------------------------------------------------------====//
// free-function declarations
template<int N>
constexpr bool
	operator==(const Location_Block<N>&, const Location_Block<N>&) noexcept;
template<int N>
constexpr bool
	operator==(const Location<N>&, const Location_Block<N>&) noexcept;
template<int N>
constexpr bool
	operator==(const Location_Block<N>&, const Location<N>&) noexcept;

template<int N, typename typeB>
constexpr bool operator!=(const Location<N>&, const typeB&) noexcept;
template<int N, typename typeB>
constexpr bool operator!=(const Location_Block<N>&, const typeB&) noexcept;

template<int N>
constexpr bool operator<(const Location<N>&, const Location<N>&) noexcept;
template<int N>
constexpr bool
	operator<(const Location_Block<N>&, const Location_Block<N>&) noexcept;
template<int N>
constexpr bool operator<=(const Location<N>&, const Location<N>&) noexcept;
template<int N>
constexpr bool
	operator<=(const Location_Block<N>&, const Location_Block<N>&) noexcept;
template<int N>
constexpr bool operator>=(const Location<N>&, const Location<N>&) noexcept;
template<int N>
constexpr bool
	operator>=(const Location_Block<N>&, const Location_Block<N>&) noexcept;
template<int N>
constexpr bool operator>(const Location<N>&, const Location<N>&) noexcept;
template<int N>
constexpr bool
	operator>(const Location_Block<N>&, const Location_Block<N>&) noexcept;

//====--------------------------------------------------------------------====//
// definitions

template<int N>
constexpr bool operator==(
	const Location_Block<N>& left, const Location_Block<N>& right) noexcept
{
	return Location<N>{left} == Location<N>{right};
}

template<int N>
constexpr bool
	operator==(const Location_Block<N>& block, const Location<N>& loc) noexcept
{
	return Location<N>{block} == loc;
}

template<int N>
inline constexpr bool
	operator==(const Location<N>& loc, const Location_Block<N>& block) noexcept
{
	return block == loc;
}

template<int N, typename typeB>
inline constexpr bool
	operator!=(const Location<N>& left, const typeB& right) noexcept
{
	static_assert(
		std::is_same_v<Location<N>, typeB> ||
		std::is_same_v<Location_Block<N>, typeB>);
	return !(left == right);
}

template<int N, typename typeB>
inline constexpr bool
	operator!=(const Location_Block<N>& left, const typeB& right) noexcept
{
	static_assert(
		std::is_same_v<Location<N>, typeB> ||
		std::is_same_v<Location_Block<N>, typeB>);
	return !(left == right);
}

template<int N>
constexpr bool
	operator<(const Location<N>& left, const Location<N>& right) noexcept
{
	return left.element() < right.element();
}

template<int N>
constexpr bool
	operator<=(const Location<N>& left, const Location<N>& right) noexcept
{
	return left.element() <= right.element();
}

template<int N>
constexpr bool
	operator>=(const Location<N>& left, const Location<N>& right) noexcept
{
	return left.element() >= right.element();
}

template<int N>
constexpr bool
	operator>(const Location<N>& left, const Location<N>& right) noexcept
{
	return left.element() > right.element();
}

// Sorted by block first.
template<int N>
constexpr bool operator<(
	const Location_Block<N>& left, const Location_Block<N>& right) noexcept
{
	return (left.id() == right.id()) ? (left.element() < right.element())
									 : left.id() < right.id();
}

template<int N>
constexpr bool operator<=(
	const Location_Block<N>& left, const Location_Block<N>& right) noexcept
{
	return (left.id() == right.id()) ? (left.element() <= right.element())
									 : left.id() < right.id();
}

template<int N>
constexpr bool operator>=(
	const Location_Block<N>& left, const Location_Block<N>& right) noexcept
{
	return (left.id() == right.id()) ? (left.element() >= right.element())
									 : left.id() > right.id();
}

template<int N>
constexpr bool operator>(
	const Location_Block<N>& left, const Location_Block<N>& right) noexcept
{
	return (left.id() == right.id()) ? (left.element() > right.element())
									 : left.id() > right.id();
}

} // namespace Sudoku


/**
 * @file spectralestimator.h
 * @brief Speech recognition front end.
 * @author John McDonough, Matthias Woelfel, Kenichi Kumatani
 */

#ifndef SPECTRALESTIMATOR_H
#define SPECTRALESTIMATOR_H

#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_complex_math.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_vector_complex.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_eigen.h>
#include <math.h>
#include <algorithm>

#include "matrix/gslmatrix.h"
#include "stream/stream.h"
#include "common/mlist.h"

#include <stdio.h>
#include <iostream>

/**
   @brief calculate the auto-correlation vector, r, with the time-discrete signal, x[n].
          Each component, r[k], represents the auto-correlation function of the input sample for lag, k.
          Accordingly, r[k] can be expressed as \cE{ x[n] x[n-k] }.
   @param const gsl_vector *samples[in] time-discrete signal which corresponds to x[n].
   @param gsl_vector *autoCorrelationVector[out] auto-correlation vector which corresponds to r.
   @note  the size of "autoCorrelationVector" should be "order+1" in order to calculate the LP model of the order, "order".
 */
void calcAutoCorrelationVector( const gsl_vector_float *samples, gsl_vector *autoCorrelationVector );

/**
   @brief calculate the linear prediction coefficients (LPC) with the Levinson-Durbin Algorithm.
   @param gsl_vector_float *autoCorrelationVector[in]
   @param gsl_vector_float *lpcs[out] lpcs[0,...,p-1] where p is the order of the model.
   @return prediction error
   @notice The estimated signal is defined as
           \hat{x}[n] = sum_{k=1}^p lpcs[k-1] * x[n-k].
           That is different from the definition in MATLAB lpc()
	   where it is \hat{x}(n) = 1.0 - sum_{k=1}^p lpcs(k+1) * x(n-k).
 */
float calcLPCswithLevinsonDurbin( gsl_vector_float *autoCorrelationVector, gsl_vector_float *lpcs );

// ----- definition for class `LPCSpectrumEstimator' -----
//

/**
   @class calculate LPCs with the Levinson-Durbin algorithm, and estimate the LPC envelope.
   @note  You can feed samples to this object with calcLPCs( const gsl_vector_float* samples ),
	  and the LPCs are then computed.
 */
class LPCSpectrumEstimator : public VectorFloatFeatureStream {
public:
  LPCSpectrumEstimator( const VectorFloatFeatureStreamPtr& samp, unsigned order, unsigned fftLen, const String& nm = "LPCSpectrumEstimator");
  ~LPCSpectrumEstimator();

  const gsl_vector_float* next(int frame_no = -5);
  void reset();

  /**
     @brief get the auto-correlation vector, r[0,...,order-1],
            where r[k] represents the auto-correlation function of the input sample for lag, k+1.
     @note you have to call calcLPCs() before you call this method.
   */
  const gsl_vector_float* getAutoCorrelationVector(){
    return (const gsl_vector_float*)_r;
  }
  /**
     @brief get the prediction error of the LP model.
     @note you have to call calcLPCs() before you call this method.
   */
  float getPredictionError(){
    return _e;
  }
  /**
     @brief get the LPCs.
     @note you have to call calcLPCs() before you call this method.
   */
  const gsl_vector_float* getLPCs(){
    return _lpcs; //_vector;
  }

  gsl_vector_complex* getFTLPCs(){
    return _ftlpcs;
  }

  const gsl_vector_float* calcLPCs( const gsl_vector_float* samples );
  void calcLPEnvelope();

private:
  void complexPackedArrayUnpack(const double* halfcomplex_coefficient, gsl_vector_complex* complex_coefficient) const;
private:
  static const double             _epsilon;
  VectorFloatFeatureStreamPtr        _samp;
  unsigned                          _order; /* the LP model of the order */
  unsigned                         _fftLen;
  unsigned                        _fftLen2;
  float                                 _e; /* prediction error */
  gsl_vector_float*                     _r; /* _order x 1 auto-correlation vector _r[1,...,p]; See [1] */
  gsl_vector*             _autoCorrelation; /* (_order+1) x 1 auto-correlation vector, where the first element corresponds to the power */
  gsl_vector_float*                  _lpcs; /* LPCs */
  double*                          _wslpcs; /* workspace for the LPCs */
  gsl_vector_complex*              _ftlpcs;
};

typedef Inherit<LPCSpectrumEstimator, VectorFloatFeatureStreamPtr> LPCSpectrumEstimatorPtr;

// ----- definition for class `CepstralSpectrumEstimator' -----
//
class CepstralSpectrumEstimator : public VectorFloatFeatureStream {
public:
  CepstralSpectrumEstimator(const VectorComplexFeatureStreamPtr& source, unsigned order = 14, unsigned fftLen = 256,
			    double logPadding = 1.0, const String& nm = "CepstralSpectrumEstimator");
  ~CepstralSpectrumEstimator();

  const gsl_vector_float* next(int frame_no = -5);
  void reset() { _source->reset();  VectorFloatFeatureStream::reset(); }

private:
  VectorComplexFeatureStreamPtr			_source;
  const unsigned				_order;
  const unsigned				_fftLen;
  const double					_logPadding;

  double*					_samples;
  gsl_vector_complex*				_spectrum;
  gsl_vector_complex*				_cepstrum;
};

typedef Inherit<CepstralSpectrumEstimator, VectorFloatFeatureStreamPtr> CepstralSpectrumEstimatorPtr;

// ----- definition for class `SEMNB' -----
//

/**
   @class
 */

class SEMNB : public Countable {
public:
  SEMNB( unsigned order, unsigned fftLen, const String& nm = "SEMNB");
  ~SEMNB();

  const gsl_vector*	calcDerivativeOfDeviation( LPCSpectrumEstimatorPtr &lpcSEPtr );
  virtual void		reset();
  const gsl_vector*	getLPEnvelope() const { return _lpEnvelope; }

private:
  void			_calcEigen();
  void			_calcLambda_bar();

  double		_dLambdak_dPm(unsigned k, unsigned m);
  void			_dLambdabar_dPm(unsigned m);
  void			_da_dPm(unsigned m);
  float			_dSigma_dP(const gsl_vector_float* lpcs, double epsilonp, unsigned m);

  double		_dSp_dan(const gsl_vector_float* lpcs, unsigned m, unsigned n);
  double		_dSp_dPm(const gsl_vector_float* lpcs, unsigned m);
  double		_depsilonp_dPm(const gsl_vector_float* lpcs, unsigned m);
  void			_calc_dr_dPm(unsigned m);
  double		_dPhat_dP(const gsl_vector_float* lpcs, double epsilonp, unsigned m);

  const unsigned				_order;
  const unsigned				_fftLen;
  const unsigned				_fftLen2;

  gsl_vector*					_derivative;
  gsl_matrix*					_R;
  gsl_matrix*					_Rcopy;
  gsl_eigen_symmv_workspace*			_workSpace;
  gsl_vector*					_evalues;
  gsl_matrix*					_evectors;
  gsl_vector*	                                _lpEnvelope;
  gsl_vector_complex*                           _ftlpcs;

  gsl_vector*					_r;
  gsl_vector*					_dr_dPm;
  gsl_vector*					_dak_dPm;
  gsl_matrix*					_Lambda_bar;
  gsl_matrix*					_dLambdamatrix;

  gsl_matrix*					_C;
  gsl_matrix*					_D;
};

typedef refcountable_ptr<SEMNB> SEMNBPtr;

#endif


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

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

/* The Type I Gumbel distribution has the form,

   p(x) dx = a b exp(-(b exp(-ax) + ax)) dx

   and the Type II Gumbel distribution has the form,

   p(x) dx = b a x^-(a+1) exp(-b x^-a)) dx

 */

double
gsl_ran_gumbel1 (const gsl_rng * r, const double a, const double b)
{
  double x = gsl_rng_uniform_pos (r);

  double z = (log(b) - log(-log(x))) / a;

  return z;
}

double
gsl_ran_gumbel1_pdf (const double x, const double a, const double b)
{
  double p = a * b *  exp (-(b * exp(-a * x) + a * x));
  return p;
}

double
gsl_ran_gumbel2 (const gsl_rng * r, const double a, const double b)
{
  double x = gsl_rng_uniform_pos (r);

  double z = pow(-b / log(x), 1/a);

  return z;
}

double
gsl_ran_gumbel2_pdf (const double x, const double a, const double b)
{
  if (x <= 0)
    {
      return 0 ;
    }
  else
    {
      double p = b * a *  pow(x,-(a+1)) * exp (-b * pow(x, -a));
      return p;
    }
}


//
// beta.h
//
// code using beta distribution
//
// copyright 2020 Peter Andrews
//

#ifndef PAA_BETA_H_
#define PAA_BETA_H_

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

#include <cmath>
#include <mutex>
#include <utility>

#include "error.h"
#include "utility.h"

namespace paa {

class GSLRNG {
 public:
  explicit GSLRNG(const uint64_t seed) : gen{gsl_rng_alloc(gsl_rng_mt19937)} {
    if (!gen) throw Error("Problem creating gsl generator");
    gsl_rng_set(gen, seed);
  }
  ~GSLRNG() { gsl_rng_free(gen); }
  operator gsl_rng * () const { return gen; }
  GSLRNG(const GSLRNG &) = delete;
  GSLRNG & operator=(const GSLRNG &) = delete;
  void lock() { mutex.lock(); }
  void unlock() { mutex.unlock(); }

 private:
  gsl_rng * gen;
  std::mutex mutex{};
};

template<class Val>
class BetaT {
 public:
  using Params = std::pair<Val, Val>;
  BetaT(const Val alpha__, const Val beta__) :
      alpha_{alpha__}, beta_{beta__} {
        if (alpha_ <= 0) throw Error("Nonpositive alpha in Beta distribution");
        if (beta_ <= 0) throw Error("Nonpositive beta in Beta distribution");
      }
  explicit BetaT(const Params params) :
      BetaT{params.first, params.second} {}
  BetaT(const Val mean_, const Val stdev_, const bool) :
      alpha_{get_alpha(mean_, stdev_)},
      beta_{get_beta(mean_, stdev_)} {
        if (stdev_ >= max_stdev(mean_))
          throw Error("Maximum stdev for basic Beta distribution is")
              << max_stdev(mean_);
      }
  Val alpha() const { return alpha_; }
  Val beta() const { return beta_; }
  Val low() const { return 0.0; }
  Val high() const { return 1.0; }
  Val range() const { return 1.0; }
  Val middle() const { return 0.5; }
  static Val get_alpha(const Val mean_, const Val stdev_) {
    return mean_ * (mean_ * (1 - mean_) / sqr(stdev_) - 1);
  }
  static Val get_beta(const Val mean_, const Val stdev_) {
    return (1 - mean_) * (mean_ * (1 - mean_) / sqr(stdev_) - 1);
  }
  static Val max_stdev(const Val mean_) {
    return sqrt(mean_ * (1 - mean_));
  }
  Val mean() const { return alpha_ / (alpha_ + beta_); }
  Val stdev() const {
    return sqrt((alpha_ * beta_) /
                (sqr(alpha_ + beta_) * (alpha_ + beta_ + 1)));
  }
  Val operator()(const Val val) const {
    return gsl_ran_beta_pdf(val, alpha_, beta_);
  }
  Val operator()(gsl_rng * gen) const {
    return gsl_ran_beta(gen, alpha_, beta_);
  }

 private:
  Val alpha_;
  Val beta_;
};
using Beta = BetaT<double>;
using fBeta = BetaT<float>;

template<class Val>
class Beta4T {
 public:
  Beta4T(const Val alpha__, const Val beta__,
        const Val low__, const Val high__) :
      beta_dist{alpha__, beta__}, low_{low__}, high_{high__} {
        if (mean() < low())
          throw Error("Mean less than low in Beta distribution");
        if (mean() > high())
          throw Error("Mean greater than high in Beta distribution");
      }
  Beta4T(const Val mean_, const Val stdev_,
        const Val low__, const Val high__,
        const bool) :
      beta_dist{get_alpha_beta(mean_, stdev_, low__, high__)},
      low_{low__}, high_{high__} {}

  Val alpha() const { return beta_dist.alpha(); }
  Val beta() const { return beta_dist.beta(); }
  Val low() const { return low_; }
  Val high() const { return high_; }
  Val range() const { return (high_ - low_); }
  Val middle() const { return (high_ - low_) / 2; }
  Val mean() const { return low_ + scale * beta_dist.mean(); }
  Val stdev() const { return scale * beta_dist.stdev(); }
  static Val max_stdev(const Val mean_, const Val low__, const Val high__) {
    const Val sf{high__ - low__};
    const Val m{(mean_ - low__) / sf};
    return sf * BetaT<Val>::max_stdev(m);
  }
  Val operator()(const Val val) const {
    return static_cast<Val>(beta_dist((val - low_) / scale)) / scale;
  }
  Val operator()(gsl_rng * gen) const {
    return low_ + scale * static_cast<Val>(beta_dist(gen));
  }

 private:
  static typename BetaT<Val>::Params get_alpha_beta(
      const Val mean_, const Val stdev_,
      const Val low__, const Val high__) {
    const Val sf{high__ - low__};
    const Val m{(mean_ - low__) / sf};
    const Val sd{stdev_ / sf};
    return typename BetaT<Val>::Params{
      BetaT<Val>::get_alpha(m, sd), BetaT<Val>::get_beta(m, sd)};
  }

  BetaT<Val> beta_dist;
  Val low_;
  Val high_;
  Val scale{high_ - low_};
};
using Beta4 = Beta4T<double>;
using fBeta4 = Beta4T<float>;

}  // namespace paa

#endif  // PAA_BETA_H_


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

typedef struct Vortex
{
    double x, y;
    double vorticity;

    int active;
} Vortex;

/* possibly should be replaced with one function? */
double Qfield_x(double x, double y)
{
    double r = x*x+y*y;
    return -y/(2*M_PI*fmax(r,1/1024/1024));
//    return -y/(2*M_PI*fmax(r,1/1024));
}

double Qfield_y(double x, double y)
{
    double r = x*x+y*y;
    return  x/(2*M_PI*fmax(r,1/1024/1024));
}

double Pfield_x(double x, double y)
{
    double r = hypot(x,y);
    if(r == 0)
        return 1.;
    return x/r*exp(-r);
}

double Pfield_y(double x, double y)
{
    double r = hypot(x,y);
    if(r == 0)
        return 1.;
    return y/r*exp(-r);
}

double Mfield(double x, double y)
{
    double r2= x*x+y*y;
    double r = sqrt(r2);
    if(x==0 && y==0)
        return 0.;
    return (r+1.)*exp(-r)/r2;
}

int VortexInBody(double x, double y)
{
    if(x*x+y*y<1)
        return 1;
    else
        return 0;
}

int main(int argc, char **argv)
{
    int NumberOfPanels = 12, MaxVortexes = 16500, Niterations = 200,      i,j,k,m,n, iterator;
    double nu = 1/13, tau = 0.005/*, eps = 0.002*/, rho = 1.;
    double vx_inf = 1., vy_inf = 0.;

    double  PanelNodes [NumberOfPanels][2],
            PanelMids  [NumberOfPanels][2],
            PanelNorms [NumberOfPanels][2],
            PanelTaus  [NumberOfPanels][2],
            PanelLength[NumberOfPanels];

    double DeployPoints[NumberOfPanels][2];

    Vortex InFlow[MaxVortexes], NextInFlow[MaxVortexes];

    int ActiveVortexesInFLow=0;

    if(1)/* cylinder profile forming & deploys */
    {

        for(i=0;i<NumberOfPanels;i++)
        {
            PanelNodes[i][0] = cos(2.*M_PI/NumberOfPanels*i);
            PanelNodes[i][1] = sin(2.*M_PI/NumberOfPanels*i);

            DeployPoints[i][0] = 1.05*PanelNodes[i][0];
            DeployPoints[i][1] = 1.05*PanelNodes[i][1];

            PanelNorms[i][0] = cos(2.*M_PI/NumberOfPanels*(i+0.5));
            PanelNorms[i][1] = sin(2.*M_PI/NumberOfPanels*(i+0.5));

        }

        for(i=0;i<NumberOfPanels-1;i++)
        {
            PanelMids[i][0] = (PanelNodes[i][0]+PanelNodes[i+1][0])/2;
            PanelMids[i][1] = (PanelNodes[i][1]+PanelNodes[i+1][1])/2;

            PanelTaus[i][0] = (PanelNodes[i+1][0]-PanelNodes[i][0]);
            PanelTaus[i][1] = (PanelNodes[i+1][1]-PanelNodes[i][1]);
            PanelLength[i]  = sqrt(PanelTaus[i][0]*PanelTaus[i][0]+
                                   PanelTaus[i][1]*PanelTaus[i][1]);
            PanelTaus[i][0] /= PanelLength[i];
            PanelTaus[i][1] /= PanelLength[i];
//            PanelNorms[i][0] = -PanelTaus[i][1];
//            PanelNorms[i][1] = PanelTaus[i][0];
        }
        PanelMids[NumberOfPanels-1][0] = (PanelNodes[NumberOfPanels-1][0]+PanelNodes[0][0])/2;
        PanelMids[NumberOfPanels-1][1] = (PanelNodes[NumberOfPanels-1][1]+PanelNodes[0][1])/2;
        PanelTaus[NumberOfPanels-1][0] = (PanelNodes[0][0]-PanelNodes[NumberOfPanels-1][0]);
        PanelTaus[NumberOfPanels-1][1] = (PanelNodes[0][1]-PanelNodes[NumberOfPanels-1][1]);
        PanelLength[NumberOfPanels-1]  = hypot(PanelTaus[NumberOfPanels-1][0],PanelTaus[NumberOfPanels-1][1]);
        PanelTaus[NumberOfPanels-1][0] /= PanelLength[NumberOfPanels-1];
        PanelTaus[NumberOfPanels-1][1] /= PanelLength[NumberOfPanels-1];
//        PanelNorms[Np-1][0] = -PanelTaus[Np-1][1];
//        PanelNorms[Np-1][1] = PanelTaus[Np-1][0];
    }

    // defining and completing Vortex Birth Matrix
    gsl_matrix *OriginalVortexGenerationMatrix = gsl_matrix_alloc(NumberOfPanels+1,NumberOfPanels+1);
    gsl_matrix *VortexGenerationMatrix = gsl_matrix_alloc(NumberOfPanels+1,NumberOfPanels+1);

    for(i=0; i<NumberOfPanels; i++)
    {
        for(j=0; j<NumberOfPanels; j++)
        {
            gsl_matrix_set(VortexGenerationMatrix,i,j,
            PanelNorms[i][0]*Qfield_x(PanelMids[i][0]-DeployPoints[j][0],
                                      PanelMids[i][1]-DeployPoints[j][1])
           +PanelNorms[i][1]*Qfield_y(PanelMids[i][0]-DeployPoints[j][0],
                                      PanelMids[i][1]-DeployPoints[j][1]));
        }
    }
    for(i=0;i<NumberOfPanels;i++)
    {
        gsl_matrix_set(VortexGenerationMatrix,NumberOfPanels,i,1);
        gsl_matrix_set(VortexGenerationMatrix,i,NumberOfPanels,1);
    }
    gsl_matrix_set(VortexGenerationMatrix,NumberOfPanels,NumberOfPanels,0);
    gsl_matrix_memcpy(OriginalVortexGenerationMatrix,VortexGenerationMatrix);

    // recieve initial aproximation for vortexes on surface
    gsl_vector *VelocityOnInfProjections = gsl_vector_alloc(NumberOfPanels+1); //Velocity On Infinity
    gsl_vector *VelocityProjections = gsl_vector_alloc(NumberOfPanels+1); //Velocity from active vortexes
//    gsl_vector *velocities_on_surface = gsl_vector_alloc(Np+1); //full velocity on surface = VOI + VFV
    gsl_vector *NewVorticities = gsl_vector_alloc(NumberOfPanels+1);

    for(i=0;i<NumberOfPanels;i++)
    {
        gsl_vector_set(VelocityOnInfProjections,i,-(PanelNorms[i][0]*vx_inf+PanelNorms[i][1]*vy_inf));
    }
    gsl_vector_set(VelocityOnInfProjections,NumberOfPanels,0.);

    gsl_permutation * p = gsl_permutation_alloc (NumberOfPanels+1);
    gsl_linalg_LU_decomp(VortexGenerationMatrix,p,&k);
    gsl_linalg_LU_solve (VortexGenerationMatrix,p,VelocityOnInfProjections,NewVorticities);

    FILE *forces;
    forces = fopen("forces.dat","w");

    for(iterator=0; iterator<Niterations; iterator++)
    {
        double f_x = 0., f_y = 0./*, M_z = 0.*/;

        //add generated vortexes to flow
        for(i=0;i<NumberOfPanels;i++)
        {
            InFlow[ActiveVortexesInFLow+i].active = 1;
            InFlow[ActiveVortexesInFLow+i].vorticity = gsl_vector_get(NewVorticities,i);
            InFlow[ActiveVortexesInFLow+i].x = DeployPoints[i][0];
            InFlow[ActiveVortexesInFLow+i].y = DeployPoints[i][1];
        }
        ActiveVortexesInFLow += NumberOfPanels;

        // time iteration
        printf("active vortexes %d\n",ActiveVortexesInFLow);

        for(i=0;i<ActiveVortexesInFLow;i++)
        {
            while(InFlow[i].active!=1)i++;
            double eps = sqrt(4/3)*PanelLength[0]/1000;
            double  I0 = 2*M_PI*eps*eps,
                    I1 = 0.,
                    I2_x = 0., I2_y = 0.,
                    I3_x = 0., I3_y = 0.;

            double u_x = vx_inf;
            double u_y = vy_inf;

            //Epsilon update
            if(iterator>5 && 0)
            {
                double sq1=1., sq2=1., sq3=1.;
                for(j=0;j<ActiveVortexesInFLow;j++)
                {
                    double temp = (InFlow[i].x-InFlow[j].x)*(InFlow[i].x-InFlow[j].x)
                                 +(InFlow[i].y-InFlow[j].y)*(InFlow[i].y-InFlow[j].y);
                    if(i!=j && temp < sq1
                            && InFlow[j].active==1
                            && InFlow[i].vorticity*InFlow[j].vorticity>0
                       )
                    {
                        sq1 = temp;
                        sq2 = sq1;
                        sq3 = sq2;
                    }
                }
                eps = sqrt( (sq1+sq2+sq3)/3 );
            }

            //Vortex-caused part of velocity
            for(j=0;j<ActiveVortexesInFLow;j++)
            {
                double rx = InFlow[i].x-InFlow[j].x;
                double ry = InFlow[i].y-InFlow[j].y;
                if( InFlow[j].active==1 &&  i!=j /*&& fabs(rx) > 1/1024.*0.25 && fabs(ry) > 1/1024.*0.25*/ )
                {
                    u_x += InFlow[j].vorticity*Qfield_x(rx,ry);
                    u_y += InFlow[j].vorticity*Qfield_y(rx,ry);
                }
            }

            //Viscous component of velocity
            for(j=0;j<ActiveVortexesInFLow;j++)
            {
                if( InFlow[j].active==1 )
                {
                    I2_x += InFlow[j].vorticity*Pfield_x((InFlow[i].x-InFlow[j].x)/eps,(InFlow[i].y-InFlow[j].y)/eps)/eps;
                    I2_y += InFlow[j].vorticity*Pfield_y((InFlow[i].x-InFlow[j].x)/eps,(InFlow[i].y-InFlow[j].y)/eps)/eps;
                    I1  += InFlow[j].vorticity*exp(-hypot((InFlow[i].x-InFlow[j].x),(InFlow[i].y-InFlow[j].y))/eps);
                }
            }
            for(j=0;j<NumberOfPanels;j++)
            {
                double Rr = hypot((InFlow[i].x-PanelMids[j][0]),(InFlow[i].y-PanelMids[j][1]));
                I3_x -= PanelNorms[j][0]*exp(-Rr/eps)*PanelLength[j];
                I3_y -= PanelNorms[j][1]*exp(-Rr/eps)*PanelLength[j];
                I0   -= ((InFlow[i].x-PanelMids[j][0])*PanelNorms[j][0]
                        +(InFlow[i].y-PanelMids[j][1])*PanelNorms[j][1])
                        *PanelLength[j]
                        *Mfield((InFlow[i].x-PanelMids[j][0])/eps,
                        (InFlow[i].y-PanelMids[j][1])/eps);

            }

            //        printf("%f %f\n",u_x,u_y);
            u_x += nu*(-I2_x/I1+I3_x/I0);
            u_y += nu*(-I2_y/I1+I3_y/I0);
            //        printf("%f %f\n",u_x,u_y);

            if(tau*u_x < 1000 && tau*u_y < 1000 )
            {
                NextInFlow[i].x = InFlow[i].x + tau*u_x;
                NextInFlow[i].y = InFlow[i].y + tau*u_y;

//                int minRmid = 0;
//контроль протекания
                double Rmid = sqrt((PanelMids[0][0]-NextInFlow[i].x)*(PanelMids[0][0]-NextInFlow[i].x)+
                                   (PanelMids[0][1]-NextInFlow[i].y)*(PanelMids[0][1]-NextInFlow[i].y));
                double projectionDistOnMidVector = (PanelMids[0][0]*NextInFlow[i].x+PanelMids[0][1]*NextInFlow[i].y)/
                                                   (PanelMids[0][0]*PanelMids[0][0]+PanelMids[0][1]*PanelMids[0][1]);

                for(m=1;m<NumberOfPanels;m++)
                {
                    double temp = sqrt((PanelMids[m][0]-NextInFlow[i].x)*(PanelMids[m][0]-NextInFlow[i].x)+
                                       (PanelMids[m][1]-NextInFlow[i].y)*(PanelMids[m][1]-NextInFlow[i].y));
                    if(fmin(Rmid,temp)<Rmid)
                    {
                        Rmid = temp;
//                        minRmid = m;
                        projectionDistOnMidVector = (PanelMids[m][0]*NextInFlow[i].x+PanelMids[m][1]*NextInFlow[i].y)/
                                                    (PanelMids[m][0]*PanelMids[m][0]+PanelMids[m][1]*PanelMids[m][1]);
                    }
                }

//                if(!VortexInBody(NextInFlow[i].x,NextInFlow[i].y))
                if(projectionDistOnMidVector > 1.)
                {
                    NextInFlow[i].active = InFlow[i].active;
                    NextInFlow[i].vorticity = InFlow[i].vorticity;
                }
                else
                {
                    NextInFlow[i].active = 3;
                    NextInFlow[i].vorticity = InFlow[i].vorticity;
                }
            }
            else
            {
                NextInFlow[i].x = InFlow[i].x;
                NextInFlow[i].y = InFlow[i].y;
                NextInFlow[i].active = 2;
                NextInFlow[i].vorticity = InFlow[i].vorticity;
            }
//            if(NextInFlow[i].vorticity<0.01)
        }

        for(m = 0; m < NumberOfPanels; m++)
        {
            f_x += -rho*(gsl_vector_get(NewVorticities,m)/tau* PanelMids[m][1]);
            f_y +=  rho*(gsl_vector_get(NewVorticities,m)/tau* PanelMids[m][0]);
        }

        fprintf(forces,"%f %f %f\n",iterator*tau, f_x, f_y);

        //updating coords
        for(i=0;i<ActiveVortexesInFLow;i++)
        {
            InFlow[i] = NextInFlow[i];
        }

        //definition of speed from vortexes after iteration
        double VelocityProjInControlPoint[NumberOfPanels];
        for(j=0; j<NumberOfPanels; j++)
            VelocityProjInControlPoint[j] = PanelNorms[j][0]*vx_inf + PanelNorms[j][1]*vy_inf;

        for(i=0; i<ActiveVortexesInFLow; i++)
        {
            if(InFlow[i].active==1)
            {
                for(j=0; j<NumberOfPanels; j++)
                {
                    VelocityProjInControlPoint[j] +=
                            (PanelNorms[j][0]*Qfield_x((PanelMids[j][0]-InFlow[i].x),
                                                       (PanelMids[j][1]-InFlow[i].y))
                            +PanelNorms[j][1]*Qfield_y((PanelMids[j][0]-InFlow[i].x),
                                                       (PanelMids[j][1]-InFlow[i].y)))
                            *InFlow[i].vorticity;
                }
            }
        }

        for(j=0; j<NumberOfPanels; j++)
            gsl_vector_set(VelocityProjections,j,-VelocityProjInControlPoint[j]);
        gsl_vector_set(VelocityProjections,NumberOfPanels,0);

        gsl_matrix_memcpy(VortexGenerationMatrix, OriginalVortexGenerationMatrix);

        gsl_linalg_LU_decomp(VortexGenerationMatrix,p,&k);
        gsl_linalg_LU_solve (VortexGenerationMatrix,p,VelocityProjections,NewVorticities);

        if(iterator%10==0)
        {
            /*
            FILE *VortexesOut, *BodyOut, *averagedOut;
            VortexesOut = fopen("MVE_flow.dat","w");
            BodyOut =     fopen("MVE_body.dat","w");
            averagedOut = fopen("MVE_aver.dat","w");

            for(i=0;i<ActiveVortexesInFLow;i++)
            {
                if(InFlow[i].active==1)
                    fprintf(VortexesOut,"%f %f %f\n",InFlow[i].x,InFlow[i].y,InFlow[i].vorticity);
            }

            for(i=0; i<Np; i++)
                fprintf(BodyOut,"%f %f\n", DeployPoints[i][0], DeployPoints[i][1]);

            double averagedVorticity[101][101];

            for(i=0;i<ActiveVortexesInFLow;i++)
            {
                if(fabs(InFlow[i].x)<=10 && fabs(InFlow[i].y)<=10 && InFlow[i].active == 1)
                {
                    averagedVorticity[(int)(50+(InFlow[i].x)/0.2)][(int)(50+(InFlow[i].y)/0.2)] += InFlow[i].vorticity*0.04;
                }
            }

            for(i=0;i<101;i++)
            {
                for(j=0;j<101;j++)
                    fprintf(averagedOut,"%f %f %f\n", -10+i*0.2, -10+j*0.02, averagedVorticity[i][j]);

            }

            fclose(averagedOut);
            fclose(VortexesOut);
            fclose(BodyOut);
            int temp;
            system("screen -S gnuplot -X stuff \"replot^M\" ");
            scanf("%d",&temp);
            if(ActiveVortexesInFLow<16000)
                Niterations +=temp;
            else
                return 0;
//            system("screen -S gnuplot -X stuff \"plot \'MVE_flow.dat\' using 1:2, \'MVE_body.dat\' w line^M\" ");
*/
            char FileName[32];
            sprintf(FileName,"VelocityFiled%6.6d.dat",iterator);
            FILE *VelocityField;
            VelocityField = fopen(FileName,"w");
            fprintf(VelocityField,"TITLE = \"Flow Model\"\n");
            fprintf(VelocityField,"VARIABLES = \"x\", \"y\", \"vx\", \"vy\"\n");
            fprintf(VelocityField,"ZONE T=\"Frame 0\", I=%d, J=%d\n", 200, 100);
            for(i=0;i<200;i++)
            {
                for(j=0;j<100;j++)
                {
                    double vx=vx_inf, vy=vy_inf;
                    for(n=0;n<ActiveVortexesInFLow;n++)
                    {
                        if(InFlow[n].active==1)
                        {
                            vx += InFlow[n].vorticity*Qfield_x((0.04*i-2)-InFlow[n].x,
                                                               (0.04*j-2)-InFlow[n].y);
                            vy += InFlow[n].vorticity*Qfield_y((0.04*i-2)-InFlow[n].x,
                                                               (0.04*j-2)-InFlow[n].y);
                        }
                    }
                    fprintf(VelocityField,"%f %f %f %f\n",0.04*i-2, 0.04*j-2, vx, vy);
                }
            }
        }
    }
/*
    //the most interesting part: output of results
    FILE *VortexesOut, *BodyOut, *averagedOut;
    VortexesOut = fopen("MVE_flow.dat","w");
    BodyOut =     fopen("MVE_body.dat","w");
    averagedOut = fopen("MVE_aver.dat","w");

    for(i=0;i<ActiveVortexesInFLow;i++)
    {
        if(InFlow[i].active==1)
            fprintf(VortexesOut,"%f %f %f\n",InFlow[i].x,InFlow[i].y,InFlow[i].vorticity);
    }

    for(i=0; i<Np; i++)
        fprintf(BodyOut,"%f %f\n", DeployPoints[i][0], DeployPoints[i][1]);

    double averagedVorticity[101][101];

    for(i=0;i<ActiveVortexesInFLow;i++)
    {
        if(fabs(InFlow[i].x)<=10 && fabs(InFlow[i].y)<=10 && InFlow[i].active == 1)
        {
            averagedVorticity[(int)(50+(InFlow[i].x)/0.2)][(int)(50+(InFlow[i].y)/0.2)] += InFlow[i].vorticity*0.04;
        }
    }

    for(i=0;i<101;i++)
    {
        for(j=0;j<101;j++)
            fprintf(averagedOut,"%f %f %f\n", -10+i*0.2, -10+j*0.02, averagedVorticity[i][j]);

    }

    fclose(averagedOut);
    fclose(VortexesOut);
    fclose(BodyOut);
    */
    return 0;
}


/**
 * Created when     :   2021.11.19;
 * Last Update      :   2021.12.02;
 * Author           :   G. Marino <gcmarino404@gmail.com>;
 * Notes            :   Header to the program Newton-main and correlated files.
 */

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

//  Size of the visualization grid of area N*N;
#define N 1000
//  How close the guessed root given the point used as guest must be to the real root of the equation, Tol is for Tolerance;
#define Tol 1e-8
#define iterations 1000
#define phi (1+sqrt(5))/2

//  Struct used to create arrays of complex numbers which ones are the roots of the studied equation;
struct cmplx {
    double real;    //  Real part of the given complex number;
    double imag;    //  Imaginary part of the given complex number;
};

//  Output (op) function, print the results into .dat archives;
void op(int *arr) {
    int i, j;
    FILE *file;
    char name[100];

    sprintf(name, "dat/Fractal.dat");
    file = fopen(name, "w");
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            fprintf(file, "%d ", arr[i*N+j]);
        };
        fprintf(file, "\n");
    };
    fclose(file);
};


/*  @file mvn.c
 *  @title multivariate normal random variables
 *  @author Carl Boettiger, <cboettig@gmail.com>
 *
 *  Based on the R function rmvnorm, from the mvtnorm package
 *  by Friedrich Leisch and Fabian Scheipl, implemented
 *  using the GSL libraries
 */

#include <gsl/gsl_math.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_eigen.h>

int mvn(gsl_rng * rng, const gsl_vector * mean, gsl_matrix * covar, gsl_vector * ANS)
{
	int i;
	size_t n = mean->size;

	/* Calculate eigenvalues and eigenvectors of covar matrix */
	gsl_vector *eval = gsl_vector_alloc (n);
	gsl_matrix *evec = gsl_matrix_alloc (n, n);
	gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc (n);
	gsl_eigen_symmv (covar, eval, evec, w);
	gsl_eigen_symmv_free (w);
//	gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_ABS_DESC);

	/* Setup for: evec * matrix(diag(eval)) * transpose(evec)  */
	gsl_matrix *eval_mx = gsl_matrix_calloc (n, n);
	gsl_matrix * x_M = gsl_matrix_alloc (n,n);
	gsl_matrix * x_M_x = gsl_matrix_alloc (n,n);

	gsl_vector_view diagonal = gsl_matrix_diagonal(eval_mx);
	gsl_vector_memcpy(&diagonal.vector, eval);
	for(i=0;i<n;i++)
	{
		gsl_vector_set( &diagonal.vector,
						i,
						sqrt( gsl_vector_get(&diagonal.vector, i) )
					  );
	}

	/* evec * matrix(diag(eval)) * transpose(evec)  */
//	gsl_blas_dsymm (CblasLeft, CblasUpper,
//					1.0, evec, eval_mx, 0.0, x_M);

	gsl_blas_dgemm (CblasNoTrans, CblasNoTrans,
					1.0, evec, eval_mx, 0.0, x_M);
	gsl_blas_dgemm (CblasNoTrans, CblasTrans,
					1.0, x_M, evec, 0.0, x_M_x);

	gsl_matrix_free(x_M);
	gsl_matrix_free(eval_mx);
	gsl_matrix_free(evec);
	gsl_vector_free(eval);

	gsl_vector * rnorms = gsl_vector_alloc(n);
	for(i=0;i<n;i++)
	{
		gsl_vector_set
			( rnorms, i,
			  gsl_ran_gaussian_ziggurat(rng, 1)
			);
	}

	gsl_blas_dgemv( CblasTrans, 1.0, x_M_x, rnorms, 0, ANS);
	gsl_vector_add(ANS, mean);
	gsl_matrix_free(x_M_x);
  gsl_vector_free(rnorms);

	return 0;
	/* answer provided through pass by reference */
}

/*
int main()
{
	const int n_tips = 2;
	gsl_rng * rng = gsl_rng_alloc(gsl_rng_default);
	gsl_vector * simdata = gsl_vector_alloc(n_tips);
	gsl_matrix * I = gsl_matrix_alloc(n_tips, n_tips);
	gsl_matrix_set_identity(I);
	gsl_vector * A = gsl_vector_calloc(n_tips);
	gsl_vector_set_all(A, 5.);
	mvn(rng, A, I, simdata);
	gsl_vector_fprintf(stdout, A, "%g");
	return 0;
}
*/

/*
#define N 3
int main(void)
{

	double mean[] = {1,2,5};
	double sigma[] = {1, 0, 0,
					  0, 1, .9,
					  0, .9, 1};
	double out[N] = {0,0,0};

	gsl_vector_view mean_view = gsl_vector_view_array(mean, N);
	gsl_matrix_view sigma_view = gsl_matrix_view_array(sigma, N,N);
	gsl_vector_view out_view = gsl_vector_view_array(out, N);

	gsl_rng * rng = gsl_rng_alloc(gsl_rng_default);

	int i;
	for(i=0;i<10000;i++) {
		mvn(rng, &mean_view.vector, &sigma_view.matrix, &out_view.vector);
		printf("%g %g %g\n", out[0], out[1], out[2]);
	}
	return 0;
}
*/


/**
 *
 * @file core_zpltmg_circul.c
 *
 *  PLASMA core_blas kernel
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.8.0
 * @author Mathieu Faverge
 * @date 2010-11-15
 * @precisions normal z -> c d s
 *
 **/
#include <lapacke.h>
#include <math.h>
#include "common.h"

/***************************************************************************//**
 *
 * @ingroup dplasma_cores_complex64
 *
 *  CORE_zpltmg_circul is a kernel used in circulant matrix generation
 *
 *  See http://www.mathworks.fr/fr/help/matlab/ref/gallery.html#f84-999880
 *
 *  Circulant matrix
 *
 *  A circulant matrix has the property that each row is obtained from the
 *  previous one by cyclically permuting the entries one step forward. It is a
 *  special Toeplitz matrix in which the diagonals "wrap around."
 *
 *  The eigensystem of C (n-by-n) is known explicitly: If t is an nth root of
 *  unity, then the inner product of v and w = [1 t t2 ... t(n – 1)] is an
 *  eigenvalue of C and w(n:-1:1) is an eigenvector, where v is the first column of
 *  C.
 *
 *
 *******************************************************************************
 *
 * @param[in] M
 *         The number of rows of the tile A to initialize. M >= 2.
 *
 * @param[in] N
 *         The number of columns of the tile A to initialize. N >= 0.
 *
 * @param[out] A
 *         On entry, the M-by-N tile to be initialized.
 *
 * @param[in] LDA
 *         The leading dimension of the tile A. LDA >= max(1,M).
 *
 * @param[in] gM
 *         The global number of rows of the full matrix, A is belonging to. gM >= (m0+gM).
 *
 * @param[in] m0
 *         The index of the first row of tile A in the full matrix. m0 >= 0.
 *
 * @param[in] n0
 *         The index of the first column of tile A in the full matrix. n0 >= 0.
 *
 * @param[in] V
 *          Workspace of size gM, that contains the first clumn of the full matrix
 *
 *******************************************************************************
 *
 * @return
 *         \retval PLASMA_SUCCESS successful exit
 *         \retval <0 if INFO = -k, the k-th argument had an illegal value
 *
 ******************************************************************************/
#if defined(PLASMA_HAVE_WEAK)
#pragma weak CORE_zpltmg_circul = PCORE_zpltmg_circul
#define CORE_zpltmg_circul PCORE_zpltmg_circul
#endif
int CORE_zpltmg_circul( int M, int N, PLASMA_Complex64_t *A, int LDA,
                        int gM, int m0, int n0,
                        const PLASMA_Complex64_t *V )
{
    int i, j, ii, jj;

    /* Check input arguments */
    if (M < 0) {
        coreblas_error(1, "Illegal value of M");
        return -1;
    }
    if (N < 0) {
        coreblas_error(2, "Illegal value of N");
        return -2;
    }
    if ((LDA < max(1,M)) && (M > 0)) {
        coreblas_error(4, "Illegal value of LDA");
        return -4;
    }
    if (m0 < 0) {
        coreblas_error(6, "Illegal value of m0");
        return -6;
    }
    if (n0 < 0) {
        coreblas_error(7, "Illegal value of n0");
        return -7;
    }
    if (gM < m0+M) {
        coreblas_error(5, "Illegal value of gM");
        return -5;
    }

    for (j=0, jj=n0; j<N; j++, jj++) {
        for (i=0, ii=m0; i<M; i++, ii++) {
            A[LDA*j + i] = V[ (jj-ii+gM)%gM ];
        }
    }

    return PLASMA_SUCCESS;
}


/* randist/discrete.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 James Theiler, 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.
 */

/*
   Random Discrete Events

   Given K discrete events with different probabilities P[k]
   produce a value k consistent with its probability.

   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 Foundation, Inc., 59 Temple Place, Suite
   330, Boston, MA 02111-1307 USA
*/

/*
 * Based on: Alastair J Walker, An efficient method for generating
 * discrete random variables with general distributions, ACM Trans
 * Math Soft 3, 253-256 (1977).  See also: D. E. Knuth, The Art of
 * Computer Programming, Volume 2 (Seminumerical algorithms), 3rd
 * edition, Addison-Wesley (1997), p120.

 * Walker's algorithm does some preprocessing, and provides two
 * arrays: floating point F[k] and integer A[k].  A value k is chosen
 * from 0..K-1 with equal likelihood, and then a uniform random number
 * u is compared to F[k].  If it is less than F[k], then k is
 * returned.  Otherwise, A[k] is returned.

 * Walker's original paper describes an O(K^2) algorithm for setting
 * up the F and A arrays.  I found this disturbing since I wanted to
 * use very large values of K.  I'm sure I'm not the first to realize
 * this, but in fact the preprocessing can be done in O(K) steps.

 * A figure of merit for the preprocessing is the average value for
 * the F[k]'s (that is, SUM_k F[k]/K); this corresponds to the
 * probability that k is returned, instead of A[k], thereby saving a
 * redirection.  Walker's O(K^2) preprocessing will generally improve
 * that figure of merit, compared to my cheaper O(K) method; from some
 * experiments with a perl script, I get values of around 0.6 for my
 * method and just under 0.75 for Walker's.  Knuth has pointed out
 * that finding _the_ optimum lookup tables, which maximize the
 * average F[k], is a combinatorially difficult problem.  But any
 * valid preprocessing will still provide O(1) time for the call to
 * gsl_ran_discrete().  I find that if I artificially set F[k]=1 --
 * ie, better than optimum! -- I get a speedup of maybe 20%, so that's
 * the maximum I could expect from the most expensive preprocessing.
 * Folding in the difference of 0.6 vs 0.75, I'd estimate that the
 * speedup would be less than 10%.

 * I've not implemented it here, but one compromise is to sort the
 * probabilities once, and then work from the two ends inward.  This
 * requires O(K log K), still lots cheaper than O(K^2), and from my
 * experiments with the perl script, the figure of merit is within
 * about 0.01 for K up to 1000, and no sign of diverging (in fact,
 * they seemed to be converging, but it's hard to say with just a
 * handful of runs).

 * The O(K) algorithm goes through all the p_k's and decides if they
 * are "smalls" or "bigs" according to whether they are less than or
 * greater than the mean value 1/K.  The indices to the smalls and the
 * bigs are put in separate stacks, and then we work through the
 * stacks together.  For each small, we pair it up with the next big
 * in the stack (Walker always wanted to pair up the smallest small
 * with the biggest big).  The small "borrows" from the big just
 * enough to bring the small up to mean.  This reduces the size of the
 * big, so the (smaller) big is compared again to the mean, and if it
 * is smaller, it gets "popped" from the big stack and "pushed" to the
 * small stack.  Otherwise, it stays put.  Since every time we pop a
 * small, we are able to deal with it right then and there, and we
 * never have to pop more than K smalls, then the algorithm is O(K).

 * This implementation sets up two separate stacks, and allocates K
 * elements between them.  Since neither stack ever grows, we do an
 * extra O(K) pass through the data to determine how many smalls and
 * bigs there are to begin with and allocate appropriately.  In all
 * there are 2*K*sizeof(double) transient bytes of memory that are
 * used than returned, and K*(sizeof(int)+sizeof(double)) bytes used
 * in the lookup table.

 * Walker spoke of using two random numbers (an integer 0..K-1, and a
 * floating point u in [0,1]), but Knuth points out that one can just
 * use the integer and fractional parts of K*u where u is in [0,1].
 * In fact, Knuth further notes that taking F'[k]=(k+F[k])/K, one can
 * directly compare u to F'[k] without having to explicitly set
 * u=K*u-int(K*u).

 * Usage:

 * Starting with an array of probabilities P, initialize and do
 * preprocessing with a call to:

 *    gsl_rng *r;
 *    gsl_ran_discrete_t *f;
 *    f = gsl_ran_discrete_preproc(K,P);

 * Then, whenever a random index 0..K-1 is desired, use

 *    k = gsl_ran_discrete(r,f);

 * Note that several different randevent struct's can be
 * simultaneously active.

 * Aside: A very clever alternative approach is described in
 * Abramowitz and Stegun, p 950, citing: Marsaglia, Random variables
 * and computers, Proc Third Prague Conference in Probability Theory,
 * 1962.  A more accesible reference is: G. Marsaglia, Generating
 * discrete random numbers in a computer, Comm ACM 6, 37-38 (1963).
 * If anybody is interested, I (jt) have also coded up this version as
 * part of another software package.  However, I've done some
 * comparisons, and the Walker method is both faster and more stingy
 * with memory.  So, in the end I decided not to include it with the
 * GSL package.

 * Written 26 Jan 1999, James Theiler, jt@lanl.gov
 * Adapted to GSL, 30 Jan 1999, jt

 */

#include <config.h>
#include <stdio.h>              /* used for NULL, also fprintf(stderr,...) */
#include <stdlib.h>             /* used for malloc's */
#include <math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#define DEBUG 0
#define KNUTH_CONVENTION 1      /* Saves a few steps of arithmetic
                                 * in the call to gsl_ran_discrete()
                                 */

/*** Begin Stack (this code is used just in this file) ***/

/* Stack code converted to use unsigned indices (i.e. s->i == 0 now
   means an empty stack, instead of -1), for consistency and to give a
   bigger allowable range. BJG */

typedef struct {
    size_t N;                      /* max number of elts on stack */
    size_t *v;                     /* array of values on the stack */
    size_t i;                      /* index of top of stack */
} gsl_stack_t;

static gsl_stack_t *
new_stack(size_t N) {
    gsl_stack_t *s;
    s = (gsl_stack_t *)malloc(sizeof(gsl_stack_t));
    s->N = N;
    s->i = 0;                  /* indicates stack is empty */
    s->v = (size_t *)malloc(sizeof(size_t)*N);
    return s;
}

static int
push_stack(gsl_stack_t *s, size_t v)
{
    if ((s->i) >= (s->N)) {
      return -1; /* stack overflow (shouldn't happen) */
    }
    (s->v)[s->i] = v;
    s->i += 1;
    return 0;
}

static size_t pop_stack(gsl_stack_t *s)
{
    if ((s->i) == 0) {
      GSL_ERROR ("internal error - stack exhausted", GSL_ESANITY);
    }
    s->i -= 1;
    return ((s->v)[s->i]);
}

static inline size_t size_stack(const gsl_stack_t *s)
{
    return s->i;
}

static void free_stack(gsl_stack_t *s)
{
    free((char *)(s->v));
    free((char *)s);
}

/*** End Stack ***/

/*** Begin Walker's Algorithm ***/

gsl_ran_discrete_t *
gsl_ran_discrete_preproc(size_t Kevents, const double *ProbArray)
{
    size_t k,b,s;
    gsl_ran_discrete_t *g;
    size_t nBigs, nSmalls;
    gsl_stack_t *Bigs;
    gsl_stack_t *Smalls;
    double *E;
    double pTotal = 0.0, mean, d;

    if (Kevents < 1) {
      /* Could probably treat Kevents=1 as a special case */

      GSL_ERROR_VAL ("number of events must be a positive integer",
                        GSL_EINVAL, 0);
    }

    /* Make sure elements of ProbArray[] are positive.
     * Won't enforce that sum is unity; instead will just normalize
     */

    for (k=0; k<Kevents; ++k) {
        if (ProbArray[k] < 0) {
          GSL_ERROR_VAL ("probabilities must be non-negative",
                            GSL_EINVAL, 0) ;
        }
        pTotal += ProbArray[k];
    }

    /* Begin setting up the main "object" (just a struct, no steroids) */
    g = (gsl_ran_discrete_t *)malloc(sizeof(gsl_ran_discrete_t));
    g->K = Kevents;
    g->F = (double *)malloc(sizeof(double)*Kevents);
    g->A = (size_t *)malloc(sizeof(size_t)*Kevents);

    E = (double *)malloc(sizeof(double)*Kevents);

    if (E==NULL) {
      GSL_ERROR_VAL ("Cannot allocate memory for randevent", GSL_ENOMEM, 0);
    }

    for (k=0; k<Kevents; ++k) {
        E[k] = ProbArray[k]/pTotal;
    }

    /* Now create the Bigs and the Smalls */
    mean = 1.0/Kevents;
    nSmalls=nBigs=0;
    {
      /* Temporarily use which[k] = g->A[k] to indicate small or large */
      size_t * const which = g->A;

      for (k=0; k<Kevents; ++k) {
        if (E[k] < mean) {
          ++nSmalls; which[k] = 0;
        } else {
          ++nBigs; which[k] = 1;
        }
      }

      Bigs   = new_stack(nBigs);
      Smalls = new_stack(nSmalls);
      for (k=0; k<Kevents; ++k) {
        gsl_stack_t * Dest = which[k] ? Bigs : Smalls;
        int status = push_stack(Dest,k);
        if (status)
          GSL_ERROR_VAL ("failed to build stacks", GSL_EFAILED, 0);
      }
    }

    /* Now work through the smalls */
    while (size_stack(Smalls) > 0) {
        s = pop_stack(Smalls);
        if (size_stack(Bigs) == 0) {
            (g->A)[s]=s;
            (g->F)[s]=1.0;
            continue;
        }
        b = pop_stack(Bigs);
        (g->A)[s]=b;
        (g->F)[s]=Kevents*E[s];
#if DEBUG
        fprintf(stderr,"s=%2d, A=%2d, F=%.4f\n",s,(g->A)[s],(g->F)[s]);
#endif
        d = mean - E[s];
        E[s] += d;              /* now E[s] == mean */
        E[b] -= d;
        if (E[b] < mean) {
            push_stack(Smalls,b); /* no longer big, join ranks of the small */
        }
        else if (E[b] > mean) {
            push_stack(Bigs,b); /* still big, put it back where you found it */
        }
        else {
            /* E[b]==mean implies it is finished too */
            (g->A)[b]=b;
            (g->F)[b]=1.0;
        }
    }
    while (size_stack(Bigs) > 0) {
        b = pop_stack(Bigs);
        (g->A)[b]=b;
        (g->F)[b]=1.0;
    }
    /* Stacks have been emptied, and A and F have been filled */

    if ( size_stack(Smalls) != 0) {
      GSL_ERROR_VAL ("Smalls stack has not been emptied",
                     GSL_ESANITY, 0 );
    }

#if 0
    /* if 1, then artificially set all F[k]'s to unity.  This will
     * give wrong answers, but you'll get them faster.  But, not
     * that much faster (I get maybe 20%); that's an upper bound
     * on what the optimal preprocessing would give.
     */
    for (k=0; k<Kevents; ++k) {
        (g->F)[k] = 1.0;
    }
#endif

#if KNUTH_CONVENTION
    /* For convenience, set F'[k]=(k+F[k])/K */
    /* This saves some arithmetic in gsl_ran_discrete(); I find that
     * it doesn't actually make much difference.
     */
    for (k=0; k<Kevents; ++k) {
        (g->F)[k] += k;
        (g->F)[k] /= Kevents;
    }
#endif

    free_stack(Bigs);
    free_stack(Smalls);
    free((char *)E);

    return g;
}

size_t
gsl_ran_discrete(const gsl_rng *r, const gsl_ran_discrete_t *g)
{
    size_t c=0;
    double u,f;
    u = gsl_rng_uniform(r);
#if KNUTH_CONVENTION
    c = (u*(g->K));
#else
    u *= g->K;
    c = u;
    u -= c;
#endif
    f = (g->F)[c];
    /* fprintf(stderr,"c,f,u: %d %.4f %f\n",c,f,u); */
    if (f == 1.0) return c;

    if (u < f) {
        return c;
    }
    else {
        return (g->A)[c];
    }
}

void gsl_ran_discrete_free(gsl_ran_discrete_t *g)
{
    RETURN_IF_NULL (g);
    free((char *)(g->A));
    free((char *)(g->F));
    free((char *)g);
}

double
gsl_ran_discrete_pdf(size_t k, const gsl_ran_discrete_t *g)
{
    size_t i,K;
    double f,p=0;
    K= g->K;
    if (k>K) return 0;
    for (i=0; i<K; ++i) {
        f = (g->F)[i];
#if KNUTH_CONVENTION
        f = K*f-i;
#endif
        if (i==k) {
            p += f;
        } else if (k == (g->A)[i]) {
            p += 1.0 - f;
        }
    }
    return p/K;
}


#include <stdio.h>
#include <stdlib.h>
#include "cs.h"
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include "adkCSparse.h"
#include "adkGSL.h"

//gslMatrixToCSsparse -- returns new cs_sparse object. compressed
struct cs_di_sparse *gslMatrixToCSsparse(gsl_matrix *gm, int numNonZero){
	int i, j;
	struct cs_di_sparse *triplet, *compmat;
	double tmp;

	//now allocate new cs_sparse obj
	triplet = cs_spalloc(gm->size1, gm->size2, numNonZero, 1, 1);
	for(i=0;i<gm->size1;i++){
		for(j=0;j<gm->size2;j++){
			tmp = gsl_matrix_get(gm,i,j);
			if(tmp != 0.0) cs_entry(triplet,i,j,tmp);
		}
	}
	compmat = cs_compress(triplet);
	cs_spfree(triplet);
	return(compmat);
}

//gslMatrixToCSsparse -- returns new cs_sparse object. compressed
struct cs_di_sparse *arraysToCSsparse(int rank, int numNonZero, int *dim1, int *dim2,double *x){
	int i;
	struct cs_di_sparse *triplet, *compmat;

	//now allocate new cs_sparse obj
	triplet = cs_spalloc(rank, rank, numNonZero, 1, 1);
	for(i=0;i<numNonZero;i++) cs_entry(triplet,dim1[i],dim2[i],x[i]);
	compmat = cs_compress(triplet);
	cs_spfree(triplet);
	return(compmat);
}

//cs_max -- returns the maximum value of a cs_sparse object
double cs_max(struct cs_di_sparse *mat){
	int j,p;
	double max=0.0;
	double val;

	if (mat->nz < 0){
		for (j = 0 ; j < mat->n ; j++){
			for(p = mat->p[j] ; p < mat->p[j+1] ; p++){
				val = mat->x[p];
				if(val >max){
					max=val;
				}
			}
		}
	}
	else{ //below is untested
		for(j=0;j<mat->nzmax;j++){
			if(mat->x[j] > max){
				max = mat->x[j];
			}
		}
	}
	return(max);
}

//cs_scale -- scales each value by some constant
void cs_scale(struct cs_di_sparse *mat, double c){
	int i;
	for(i=0;i<mat->nzmax;i++){
		mat->x[i] *= c;
	}
}

//cs_scale -- scales each value by some constant
void cs_print_adk(struct cs_di_sparse *mat){
	int i,j,col,row,p;
	double val;
	gsl_matrix *gm;
	gm = gsl_matrix_alloc(mat->m,mat->n);
	gsl_matrix_set_zero(gm);

	if (mat->nz < 0){
		for (j = 0 ; j < mat->n ; j++){
			col=j;
			for(p = mat->p[j] ; p < mat->p[j+1] ; p++){
				row = mat->i [p];
				val = mat->x[p];
				gsl_matrix_set(gm,row,col,val);
			}
		}
	}
	else{

		for(i=0;i<mat->nz;i++){
			gsl_matrix_set(gm,mat->p[i],mat->i[i],mat->x[i]);
		}
	}
	gsl_matrix_prettyPrint(gm);
	gsl_matrix_free(gm);

}


/*
** pseudoinverse
**
** G.Lohmann, July 2004
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "viaio/Vlib.h"

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

extern void printmat(gsl_matrix *R,char *str);
extern void printvec(gsl_vector *x,char *str);

/*
**    B = A^-1 = A^+
*/
gsl_matrix *PseudoInv(gsl_matrix *A,gsl_matrix *B)
{
  int j,k,l,n,m;
  double u,x;
  gsl_matrix *U=NULL,*V=NULL;
  gsl_vector *w=NULL;

  m = A->size1;
  n = A->size2;

  if (B == NULL) {
    B = gsl_matrix_calloc (n,m);
  }

  U = gsl_matrix_calloc (m, n);
  V = gsl_matrix_calloc (n, n);
  w = gsl_vector_calloc (n);

  /* singular value decomposition */
  gsl_matrix_memcpy (U,A);
  gsl_linalg_SV_decomp_jacobi(U,V,w);
  gsl_matrix_set_zero(B);

  k=0;
  for (j=0; j<n; j++) {
    if (fabs(w->data[j]) > 1.0e-6) k++;
  }
  if (k < 1) VError(" Design matrix is singular\n");

  for (k=0; k<n; k++) {
    for (l=0; l<m; l++) {
      for (j=0; j<n; j++) {
	u = gsl_vector_get(w,j);
        if (fabs(u) > 1.0e-6) {
          x = gsl_matrix_get(B,k,l);
	  x += gsl_matrix_get(V,k,j)*gsl_matrix_get(U,l,j)/u;
          gsl_matrix_set(B,k,l,x);
        }
      }
    }
  }
  gsl_matrix_free(U);
  gsl_matrix_free(V);
  gsl_vector_free(w);
  return B;
}


#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gsl/gsl_siman.h>

/* set up parameters for this simulated annealing run */

/* how many points do we try before stepping */
#define N_TRIES 200

/* how many iterations for each T? */
#define ITERS_FIXED_T 1000

/* max step size in random walk */
#define STEP_SIZE 1.0

/* Boltzmann constant */
#define K 1.0

/* initial temperature */
#define T_INITIAL 0.008

/* damping factor for temperature */
#define MU_T 1.003
#define T_MIN 2.0e-6

gsl_siman_params_t params
  = {N_TRIES, ITERS_FIXED_T, STEP_SIZE,
     K, T_INITIAL, MU_T, T_MIN};

/* now some functions to test in one dimension */
double E1(void *xp)
{
  double x = * ((double *) xp);

  return exp(-pow((x-1.0),2.0))*sin(8*x);
}

double M1(void *xp, void *yp)
{
  double x = *((double *) xp);
  double y = *((double *) yp);

  return fabs(x - y);
}

void S1(const gsl_rng * r, void *xp, double step_size)
{
  double old_x = *((double *) xp);
  double new_x;

  double u = gsl_rng_uniform(r);
  new_x = u * 2 * step_size - step_size + old_x;

  memcpy(xp, &new_x, sizeof(new_x));
}

void P1(void *xp)
{
  printf ("%12g", *((double *) xp));
}

int
main(int argc, char *argv[])
{
  const gsl_rng_type * T;
  gsl_rng * r;

  double x_initial = 15.5;

  gsl_rng_env_setup();

  T = gsl_rng_default;
  r = gsl_rng_alloc(T);

  gsl_siman_solve(r, &x_initial, E1, S1, M1, P1,
                  NULL, NULL, NULL,
                  sizeof(double), params);

  gsl_rng_free (r);
  return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <gbpLib.h>
#include <gbpMisc.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_roots.h>

double bisect_array_function(double x_interp, void *params) {
    double interp;
    double r_val;
    interp = interpolate(((bisect_af_params *)params)->interp, x_interp);
    r_val  = interp - ((bisect_af_params *)params)->value;
    return (r_val);
}

double bisect_array(interp_info *interp, double value, double threshold) {
    double *                     x;
    double *                     y;
    double *                     d2y;
    double                       x_lo;
    double                       x_hi;
    double                       r_val;
    int                          i;
    int                          alloc_flag = GBP_FALSE;
    int                          iter       = 0;
    int                          max_iter   = 500;
    int                          status     = GSL_CONTINUE;
    bisect_af_params             params;
    gsl_function                 F;
    const gsl_root_fsolver_type *T;
    gsl_root_fsolver *           s;

    params.interp = interp;
    params.value  = value;
    F.function    = bisect_array_function;
    F.params      = (void *)(&params);

    x_lo = interp->x[0];
    x_hi = interp->x[interp->n - 1];

    if(fabs(bisect_array_function(x_lo, &params)) < threshold)
        return (x_lo);
    if(fabs(bisect_array_function(x_hi, &params)) < threshold)
        return (x_hi);

    T = gsl_root_fsolver_brent;
    s = gsl_root_fsolver_alloc(T);
    gsl_root_fsolver_set(s, &F, x_lo, x_hi);

    while(status == GSL_CONTINUE && iter < max_iter) {
        status = gsl_root_fsolver_iterate(s);
        r_val  = gsl_root_fsolver_root(s);
        x_lo   = gsl_root_fsolver_x_lower(s);
        x_hi   = gsl_root_fsolver_x_upper(s);
        status = gsl_root_test_interval(x_lo, x_hi, 0, threshold);
        iter++;
    }

    // Clean-up
    gsl_root_fsolver_free(s);

    return (r_val);
}


/*! \file Integrate.h
 *  \brief header file for integrating functions or data.
 */

#ifndef INTEGRATE_H
#define INTEGRATE_H

#include <cmath>
#include <iostream>
#include <gsl/gsl_math.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_interp.h>
#include <gsl/gsl_monte.h>
#include <gsl/gsl_monte_plain.h>
#include <gsl/gsl_monte_miser.h>
#include <gsl/gsl_monte_vegas.h>
#include <Precision.h>
#include <Function.h>
#include <Interpolate.h>
#include <Random.h>

using namespace std;
namespace Math
{
    /// Integrate function f(x) from x[lower] to x[upper].  Uses some
    /// algorithm I found somewhere, sometime.
    Double_t IntegrateData(const Double_t x[], const Double_t f[], const int lower,
                         const int upper);

    /// Integrate function f(x) from x[lower] to x[upper].  Uses trapeziod
    /// algorithm.
    Double_t IntegrateTrap(const Double_t x[], const Double_t f[], const int a,
                         const int b);
    ///uses adaptive trapezoidal rule based on numerical recipes
    Double_t IntegrateTrapezoidal(const math_function * f, const Double_t a,
                         const Double_t b, const int n);
    Double_t IntegrateQTrap(const math_function * f, const Double_t a,
                         const Double_t b, const Double_t epsrel, int IMAX=16);
    ///uses simple trapezoidal
    Double_t IntegrateSimpleTrapezoidal(const math_function * f, const Double_t a,
                         const Double_t b, const int n);

    ///extended closed integration
    Double_t IntegrateClosed(const math_function * f, const Double_t a,
                         const Double_t b, const int n);

    ///simpsons 3/8 rule
    Double_t IntegrateSimpson(const math_function * f, const Double_t a,
                         const Double_t b);

    ///Romberg integration based on numerical recipes
    Double_t IntegrateRomberg(const math_function * f, const Double_t a,
                         const Double_t b, const Double_t epsrel, const int n, const int K);

    ///integration based vegas monte carlo integrator. can also return error and chisq
    ///vegas monte is either gsl or NR based vegas integrator.
    Double_t IntegrateVegasMonte(math_multidim_function * f, Double_t *a, Double_t *b, const int n, Double_t *error=0,Double_t*chisq=0,int interations=6);
    double IntegrateVegasMonte(gsl_monte_function * f, double *a, double *b, const int n, double *error=0,double *chisq=0);

    ///Romberg integration based on numerical recipes but uses vegas monte carlo integrator.
    Double_t IntegrateRombergMonte(math_multidim_function * f, Double_t *a,
                         Double_t *b, const Double_t epsrel, const int sampling, const int n, const int K, int interations=6);

    ///subroutine used in my nr vegas integrator.
    void rebin(Double_t rc, int nd, Double_t r[], Double_t xin[], Double_t xi[]);
    ///numerical recipes vegas integrator. for simplicity use IntegrateVegasMonte as interface
    void vegas(math_multidim_function *fxn, Double_t regn[], int ndim, int init,
    unsigned long ncall, int itmx, int nprn, long int idum, Double_t *tgral, Double_t *sd,
    Double_t *chi2a);
}

#endif


#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_roots.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_sf_expint.h>
#include "ccl.h"

static double einasto_norm_integrand(double x, void *params)
{
  double alpha = *((double *)(params));
  return x*x*exp(-2*(pow(x,alpha)-1)/alpha);
}

void ccl_einasto_norm_integral(int n_m, double *r_s, double *r_delta, double *alpha,
			       double *norm_out,int *status)
{
#pragma omp parallel default(none)			\
  shared(n_m, r_s, r_delta, alpha, norm_out, status)
  {
    int ii;
    int status_this=0;
    gsl_function F;
    gsl_integration_workspace *w = gsl_integration_workspace_alloc(1000);

    if (w == NULL)
      status_this = CCL_ERROR_MEMORY;

    if(status_this == 0) {
#pragma omp for
      for(ii=0;ii<n_m;ii++) {
	int qagstatus;
	double result, eresult;
	double x_max = r_delta[ii]/r_s[ii];
	F.function = &einasto_norm_integrand;
	F.params = &(alpha[ii]);
	qagstatus = gsl_integration_qag(&F, 0, x_max, 0, 1E-4,
					1000, GSL_INTEG_GAUSS31,
					w, &result, &eresult);
	if(qagstatus != GSL_SUCCESS) {
	  ccl_raise_gsl_warning(qagstatus, "ccl_haloprofile.c: ccl_einasto_norm_integral():");
	  status_this = CCL_ERROR_INTEG;
	  result = NAN;
	}
	norm_out[ii] = 4 * M_PI * r_s[ii] * r_s[ii] * r_s[ii] * result;
      }
    } //end omp for

    gsl_integration_workspace_free(w);
    if(status_this) {
      #pragma omp atomic write
      *status = status_this;
    }
  } //end omp parallel
}

static double hernquist_norm_integrand(double x, void *params)
{
  double opx=1+x;
  return x*x/(x*opx*opx*opx);
}

void ccl_hernquist_norm_integral(int n_m, double *r_s, double *r_delta,
			       double *norm_out,int *status)
{
#pragma omp parallel default(none)		\
  shared(n_m, r_s, r_delta, norm_out, status)
  {
    int ii;
    int status_this=0;
    gsl_function F;
    gsl_integration_workspace *w = gsl_integration_workspace_alloc(1000);

    if (w == NULL)
      status_this = CCL_ERROR_MEMORY;

    if(status_this == 0) {
#pragma omp for
      for(ii=0;ii<n_m;ii++) {
	int qagstatus;
	double result, eresult;
	double x_max = r_delta[ii]/r_s[ii];
	F.function = &hernquist_norm_integrand;
	F.params = NULL;
	qagstatus = gsl_integration_qag(&F, 0, x_max, 0, 1E-4,
					1000, GSL_INTEG_GAUSS31,
					w, &result, &eresult);
	if(qagstatus != GSL_SUCCESS) {
	  ccl_raise_gsl_warning(qagstatus, "ccl_haloprofile.c: ccl_hernquist_norm_integral():");
	  status_this = CCL_ERROR_INTEG;
	  result = NAN;
	}
	norm_out[ii] = 4 * M_PI * r_s[ii] * r_s[ii] * r_s[ii] * result;
      }
    } //end omp for

    gsl_integration_workspace_free(w);
    if(status_this) {
      #pragma omp atomic write
      *status = status_this;
    }
  } //end omp parallel
}


//
// Created by karl_ on 2020-5-3.
//

#include <math.h>
#include <cblas.h>
#include <imgproc/color-convert.h>

gboolean imgproc_to_HSL(CoreImage *src, CoreImage **dst) {
    CoreSize *size;
    CoreColorSpace src_color_space;
    CorePixelType src_pixel_type;
    gdouble *src_data_cast, *dst_data;
    gdouble *hsl_pixel, *rgb_pixel, c_max, c_min, c;
    gsize i, j, area;

    size = core_image_get_size(src);
    area = core_size_get_area(size);
    src_color_space = core_image_get_color_space(src);
    src_pixel_type = core_image_get_pixel_type(src);

    g_return_val_if_fail(src_color_space == CORE_COLOR_SPACE_RGB, FALSE);

    if (core_pixel_is_double(src_pixel_type)) {
        src_data_cast = core_image_get_data(src);
    } else if (core_pixel_is_uint8(src_pixel_type)) {
        src_data_cast = malloc(sizeof(gdouble) * core_size_get_area(size));
        for (i = 0; i < core_size_get_area(size) * 3; ++i) {
            src_data_cast[i] = ((guint8 *) core_image_get_data(src))[i] / core_pixel_get_range(src_pixel_type);
        }
    } else {
        return FALSE;
    }

    dst_data = g_malloc(sizeof(gdouble) * core_size_get_area(size));
    for (i = 0; i < area; ++i) {
        hsl_pixel = dst_data + i * 3;
        rgb_pixel = src_data_cast + i * 3;
        c_min = 1;
        c_max = 0;
        c = c_max - c_min;
        for (j = 0; j < 3; ++j) {
            if (rgb_pixel[j] > c_max) {
                c_max = rgb_pixel[j];
            }
            if (rgb_pixel[j] < c_min) {
                c_max = rgb_pixel[j];
            }
        }

        /* Lightness */
        hsl_pixel[2] = (c_min + c_max) / 2;

        /* Saturation */
        if (!c) {
            hsl_pixel[1] = 0;
        } else {
            hsl_pixel[1] = c / (1 - fabs(hsl_pixel[2] * 2 - 1));
        }

        /* Hue */
        if (!c) {
            hsl_pixel[0] = 0;
        } else {
            if (rgb_pixel[0] == c_max) {
                hsl_pixel[0] = 1.0 / 6 * (rgb_pixel[1] - rgb_pixel[2]) / c;
            } else if (rgb_pixel[1] == c_max) {
                hsl_pixel[0] = 1.0 / 6 * (2 + (rgb_pixel[2] - rgb_pixel[0]) / c);
            } else if (rgb_pixel[2] == c_max) {
                hsl_pixel[0] = 1.0 / 6 * (4 + (rgb_pixel[0] - rgb_pixel[1]) / c);
            }
        }
    }

    if (*dst == NULL) {
        *dst = core_image_new_with_data(dst_data, CORE_COLOR_SPACE_HSL, CORE_PIXEL_D3, size, FALSE);
    } else {
        core_image_assign_data(*dst, dst_data, CORE_COLOR_SPACE_HSL, CORE_PIXEL_D3, size, FALSE);
    }

    if (core_pixel_is_uint8(src_pixel_type)) {
        free(src_data_cast);
    }
    g_object_unref(size);

    return TRUE;
}

gboolean imgproc_to_RGB(CoreImage *src, CoreImage **dst) {
    CoreSize *size;
    CoreColorSpace color_space;
    CorePixelType pixel_type;
    gdouble *src_data, *dst_data;
    gdouble *hsl_pixel, *rgb_pixel;
    gdouble c, h, h_ceil, x, m, r, g, b;
    gsize i, area;

    g_return_val_if_fail(src, FALSE);
    color_space = core_image_get_color_space(src);
    pixel_type = core_image_get_pixel_type(src);
    g_return_val_if_fail(color_space == CORE_COLOR_SPACE_HSL, FALSE);
    g_return_val_if_fail(pixel_type == CORE_PIXEL_D3, FALSE);
    size = core_image_get_size(src);
    area = core_size_get_area(size);
    src_data = core_image_get_data(src);
    dst_data = g_malloc(sizeof(gdouble) * area);
    for (i = 0; i < area; ++i) {
        hsl_pixel = src_data + i * 3;
        rgb_pixel = dst_data + i * 3;

        c = (1 - fabs(2 * hsl_pixel[2] - 1));
        h = hsl_pixel[0] * 6.0;
        x = c * (1 - fabs(h - floor(h / 2) * 2 - 1));
        h_ceil = ceil(h) + DBL_EPSILON;
        if (h_ceil >= 6) {
            r = c;
            g = 0;
            b = x;
        } else if (h_ceil >= 5) {
            r = x;
            g = 0;
            b = c;
        } else if (h_ceil >= 4) {
            r = 0;
            g = x;
            b = c;
        } else if (h_ceil >= 3) {
            r = 0;
            g = c;
            b = x;
        } else if (h_ceil >= 2) {
            r = x;
            g = c;
            b = 0;
        } else if (h_ceil >= 1) {
            r = c;
            g = x;
            b = 0;
        } else {
            r = g = b = 0;
        }
        m = hsl_pixel[2] - c / 2;
        rgb_pixel[0] = r + m;
        rgb_pixel[1] = g + m;
        rgb_pixel[2] = b + m;
    }

    if (*dst == NULL) {
        *dst = core_image_new_with_data(dst_data, CORE_COLOR_SPACE_RGB, CORE_PIXEL_D3, size, FALSE);
    } else {
        core_image_assign_data(*dst, dst_data, CORE_COLOR_SPACE_RGB, CORE_PIXEL_D3, size, FALSE);
    }

    g_object_unref(size);
    return TRUE;
}

gboolean imgproc_to_grayscale(CoreImage *src, CoreImage **dst) {
    gsize i;
    CoreSize *size;
    gdouble *dst_data_cast, *src_data_cast;
    gpointer src_data, dst_data;
    gsize channel, area;
    CorePixelType pixel_type;
    g_return_val_if_fail(src != NULL, FALSE);
    g_return_val_if_fail(dst != NULL, FALSE);

    size = core_image_get_size(src);
    area = core_size_get_area(size);
    pixel_type = core_image_get_pixel_type(src);
    channel = core_image_get_channel(src);
    src_data = core_image_get_data(src);

    if (core_pixel_is_uint8(pixel_type)) {
        src_data_cast = g_malloc(area * sizeof(gdouble) * channel);
        for (i = 0; i < area * channel; ++i) {
            src_data_cast[i] = (gdouble) ((guint8 *) src_data)[i];
        }
    } else {
        /* do not need to cast if pixel type is Dx */
        src_data_cast = src_data;
    }
    dst_data_cast = g_malloc(area * sizeof(gdouble));

    cblas_dcopy(area, src_data_cast, channel, dst_data_cast, 1);
    for (i = 1; i < channel; ++i) {
        cblas_daxpy(area, 1.0, src_data_cast + i, channel, dst_data_cast, 1);
    }
    if (channel > 1) {
        cblas_daxpy(area, 1.0 / channel - 1.0, dst_data_cast, 1, dst_data_cast, 1);
    }

    if (core_pixel_is_uint8(pixel_type)) {
        pixel_type = CORE_PIXEL_U1;
    } else if (core_pixel_is_double(pixel_type)) {
        pixel_type = CORE_PIXEL_D1;
    } else {
        g_return_val_if_fail(FALSE, FALSE);
    }

    /* cast dst_data from double back to uchar if needed */
    if (core_pixel_is_uint8(pixel_type)) {
        for (i = 0; i < area; ++i) {
            ((guint8 *) dst_data_cast)[i] = dst_data_cast[i];
        }
    }
    dst_data = dst_data_cast;
    if (core_pixel_is_uint8(pixel_type)) {
        dst_data = g_realloc(dst_data, sizeof(guint8) * area);
    }

    /* assign result */
    if (*dst == NULL) {
        *dst = core_image_new_with_data(dst_data, CORE_COLOR_SPACE_GRAY_SCALE, pixel_type, size, FALSE);
    } else {
        core_image_assign_data(*dst, dst_data, CORE_COLOR_SPACE_GRAY_SCALE, pixel_type, size, FALSE);
    }

    /* free additional allocated memory */
    if (core_pixel_is_uint8(pixel_type)) {
        g_free(src_data_cast);
    }
    g_object_unref(size);
    return TRUE;
}

gboolean imgproc_to_binary_threshold(CoreImage *src, CoreImage **dst, gdouble threshold, gboolean inverse) {
    CoreImage *gray_src = NULL;
    CoreSize *size;
    gsize i, area;
    gdouble *src_data, *dst_data;
    CoreColorSpace color_space;
    CorePixelType pixel_type;
    g_return_val_if_fail(src != NULL, FALSE);
    g_return_val_if_fail(dst != NULL, FALSE);

    if (core_image_get_channel(src) > 1) {
        imgproc_to_grayscale(src, &gray_src);
    } else {
        gray_src = g_object_ref(src);
    }
    size = core_image_get_size(gray_src);
    area = core_size_get_area(size);
    src_data = core_image_get_data(gray_src);
    dst_data = g_malloc(sizeof(gdouble) * area);
    for (i = 0; i < area; ++i) {
        dst_data[i] = ((unsigned) (src_data[i] > threshold) ^ (unsigned) inverse) * 255.0;
    }
    if (*dst == NULL) {
        core_image_new_with_data(dst_data, CORE_COLOR_SPACE_BIN, CORE_PIXEL_U1, size, FALSE);
    } else {
        core_image_assign_data(*dst, dst_data, CORE_COLOR_SPACE_BIN, CORE_PIXEL_U1, size, FALSE);
    }
    g_object_unref(size);
    g_object_unref(gray_src);
    return TRUE;
}


/*---
  Flow*: A Verification Tool for Cyber-Physical Systems.
  Authors: Xin Chen, Sriram Sankaranarayanan, and Erika Abraham.
  Email: Xin Chen <chenxin415@gmail.com> if you have questions or comments.

  The code is released as is under the GNU General Public License (GPL).
---*/

#ifndef MATRIX_H_
#define MATRIX_H_

#include "include.h"
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_linalg.h>

namespace flowstar
{

class Real;
class Interval;
class UnivariatePolynomial;
class Polynomial;
class RowVector;
class ColVector;
class rMatrix;
class iMatrix;
class upMatrix;
class mpMatrix;
class iMatrix2;
class HybridSystem;
class TaylorModelVec;

// The matrix class is implemented based on the data structure of gsl matrix.
class Matrix
{
private:
	gsl_matrix *data;
public:
	Matrix();
	Matrix(const int m, const int n);	// Create an m x n matrix, all of the entries are 0.
	Matrix(const int n);				// Create an n x n matrix, all of the entries are 0.
	Matrix(const Matrix & A);
	~Matrix();

	double get(const int i, const int j) const;				// Get the entry at position [i,j].
	void set(const double v, const int i, const int j);		// Set A[i,j] = v.

	int rows() const;
	int cols() const;

	void row(RowVector & result, const int i) const;			// Return the (i+1)-st row.

	void sortColumns();		// Sort the columns by size in descending order.
	int rank() const;

	void neg(Matrix & result) const;
	void neg_assign();

	void inverse(Matrix & result) const;
	void inverse_assign();

	void transpose(Matrix & result) const;
	void svd(Matrix & U) const;

	void QR(Matrix & D);
	void QRfactor(Matrix & Q);

	void output(FILE *fp) const;

	Matrix & operator += (const Matrix & A);
	Matrix & operator -= (const Matrix & A);
	Matrix & operator *= (const Matrix & A);

	Matrix operator + (const Matrix & A) const;
	Matrix operator - (const Matrix & A) const;
	Matrix operator * (const Matrix & A) const;

	Matrix & operator = (const Matrix & A);
};

class RowVector
{
private:
	Matrix vec;
public:
	RowVector();
	RowVector(const int n);
	RowVector(const RowVector & v);
	~RowVector();

	void set(const double v, const int pos);
	double get(const int pos) const;
	int size() const;

	void transpose(ColVector & result) const;

	void neg(RowVector & result) const;
	void neg_assign();

	void dump(FILE *fp) const;

	double innerProd(const RowVector & v) const;
	double EuclideanNorm() const;
	void normalize();

	bool operator == (const RowVector & v) const;

	RowVector & operator += (const RowVector & v);
	RowVector & operator -= (const RowVector & v);
	RowVector operator + (const RowVector & v) const;
	RowVector operator - (const RowVector & v) const;

	RowVector & operator = (const RowVector & v);

	friend class ColVector;
};

class ColVector
{
private:
	Matrix vec;
public:
	ColVector();
	ColVector(const int n);
	ColVector(const ColVector & v);
	~ColVector();

	void set(const double v, const int pos);
	double get(const int pos) const;
	int size() const;

	void transpose(RowVector & result) const;

	void neg(ColVector & result) const;
	void neg_assign();

	void mul(ColVector & result, const Matrix & m) const;
	void mul_assign(const Matrix & m);

	ColVector & operator += (const ColVector & v);
	ColVector & operator -= (const ColVector & v);
	ColVector operator + (const ColVector & v) const;
	ColVector operator - (const ColVector & v) const;

	ColVector & operator = (const ColVector & v);

	friend class RowVector;
};

class bMatrix
{
protected:
	bool *data;
	int size1;
	int size2;

public:
	bMatrix();
	bMatrix(const int m, const int n);
	bMatrix(const bMatrix & B);
	~bMatrix();

	int rows() const;
	int cols() const;

	void output(FILE *fp) const;

	bMatrix & operator += (const bMatrix & B);
	bool * operator [] (const int i);

	bMatrix & operator = (const bMatrix & B);
};

class rMatrix
{
protected:
	Real *data;
	int size1;
	int size2;

public:
	rMatrix();
	rMatrix(const int m, const int n);	// zero matrix
	rMatrix(const int n);				// identity matrix
	rMatrix(const rMatrix & rmatrix);
	~rMatrix();

	int rows() const;
	int cols() const;

	void abs(rMatrix & result) const;
	void transpose(rMatrix & result) const;

	void add_RNDD(rMatrix & result, const rMatrix & rmatrix) const;
	void add_assign_RNDD(const rMatrix & rmatrix);
	void add_RNDU(rMatrix & result, const rMatrix & rmatrix) const;
	void add_assign_RNDU(const rMatrix & rmatrix);

	void mul_RNDD(rMatrix & result, const rMatrix & rmatrix) const;
	void mul_RNDU(rMatrix & result, const rMatrix & rmatrix) const;

	void output(FILE *fp) const;

	rMatrix & operator += (const rMatrix & B);
	rMatrix & operator -= (const rMatrix & B);
	rMatrix & operator *= (const rMatrix & B);
	rMatrix operator + (const rMatrix & B) const;
	rMatrix operator - (const rMatrix & B) const;
	rMatrix operator * (const rMatrix & B) const;

	rMatrix & operator *= (const Real & r);
	rMatrix & operator *= (const double d);

	rMatrix & operator = (const rMatrix & rmatrix);		// should always be the same precision

	Real * operator [] (const int i);

	friend void to_iMatrix2(iMatrix2 & result, const rMatrix & lo, const rMatrix & up);

	friend class iMatrix;
	friend class iMatrix2;
	friend class upMatrix;
};

// matrix for intervals
class iMatrix
{
protected:
	Interval *data;
	int size1;
	int size2;

public:
	iMatrix();
	iMatrix(const int m, const int n);	// zero matrix
	iMatrix(const int n);				// identity matrix
	iMatrix(const iMatrix & A);
	iMatrix(const rMatrix & A);
	iMatrix(const iMatrix2 & A);
	iMatrix(const std::vector<Interval> & box);
	iMatrix(const std::string & matlab_format);
	~iMatrix();

	void clear();

	void mul(iMatrix & result, iMatrix & A);

	int rows() const;
	int cols() const;

	bool isZero() const;

	void pow(iMatrix & result, const int order) const;
	void pow_assign(const int order);

	double max_norm() const;
	void max_norm(Real & norm) const;

	void transpose(iMatrix & result) const;
	void times_pars(mpMatrix & result) const;
	void center();

	void linearTrans(std::vector<Polynomial> & result, const std::vector<Polynomial> & polyVec) const;

	void right_scale_assign(const std::vector<Interval> & scalars);

	void to_iMatrix2(iMatrix2 & A) const;

	void output(FILE *fp) const;

	iMatrix & operator += (const iMatrix & A);
	iMatrix & operator += (const Real & rad);
	iMatrix & operator -= (const iMatrix & A);
	iMatrix & operator *= (const iMatrix & A);
	iMatrix & operator *= (const Interval & I);
	iMatrix & operator *= (const double c);
	iMatrix & operator /= (const Interval & I);
	iMatrix & operator /= (const double c);

	iMatrix operator + (const iMatrix & A) const;
	iMatrix operator - (const iMatrix & A) const;
	iMatrix operator * (const iMatrix & A) const;
	iMatrix operator * (const Interval & I) const;
	iMatrix operator * (const double c) const;
	upMatrix operator * (const upMatrix & upm) const;

	mpMatrix operator * (const mpMatrix & mpm) const;
	TaylorModelVec operator * (const TaylorModelVec & tmv) const;

	Interval * operator [] (const int i);
	iMatrix & operator = (const iMatrix & A);
	iMatrix & operator = (const rMatrix & A);
	iMatrix & operator = (const iMatrix2 & A);
	iMatrix & operator = (const std::vector<Interval> & box);

	friend class upMatrix;
	friend class mpMatrix;
	friend class rMatrix;
	friend class iMatrix2;
	friend class Zonotope;
};

class iMatrix2
{
public:
	rMatrix center;
	rMatrix radius;

public:
	iMatrix2();
	iMatrix2(const int m, const int n);	// zero matrix
	iMatrix2(const int n);				// identity matrix
	iMatrix2(const iMatrix2 & A);
	iMatrix2(const iMatrix & A);
	iMatrix2(const std::vector<Interval> & box);
	~iMatrix2();

	int rows() const;
	int cols() const;

	void to_iMatrix(iMatrix & A) const;
	void transpose(iMatrix2 & result) const;
	void mag(Interval & I, const int i, const int j);
	void mag(Real & r, const int i, const int j);
	void add_assign(const Interval & I, const int i, const int j);

	iMatrix2 & operator += (const iMatrix2 & A);
	iMatrix2 & operator += (const iMatrix & A);
	iMatrix2 & operator += (const Real & rad);
	iMatrix2 & operator *= (const iMatrix2 & A);
	iMatrix2 & operator *= (const Interval & I);

	iMatrix2 operator + (const iMatrix2 & A) const;
	iMatrix2 operator * (const iMatrix2 & A) const;
	iMatrix operator * (const iMatrix & A) const;
	upMatrix operator * (const upMatrix & upm) const;
	TaylorModelVec operator * (const TaylorModelVec & tmv) const;

	iMatrix2 & operator = (const iMatrix2 & A);

	void output(FILE *fp) const;

	friend void to_iMatrix2(iMatrix2 & result, const rMatrix & lo, const rMatrix & up);

	friend class upMatrix;
	friend class mpMatrix;
	friend class rMatrix;
	friend class iMatrix;
	friend class Zonotope;
	friend class Polynomial;
	friend class HybridSystem;
};

// matrix for univariate polynomials
class upMatrix
{
protected:
	UnivariatePolynomial *data;
	int size1;
	int size2;

public:
	upMatrix();
	upMatrix(const int m, const int n);
	upMatrix(const int n);
	upMatrix(const iMatrix & A);
	upMatrix(const iMatrix2 & A);
	upMatrix(const upMatrix & upm);
	~upMatrix();

	int rows() const;
	int cols() const;
	int degree() const;

	bool isZero() const;

	void intEval(iMatrix & result, const std::vector<Interval> & val_exp_table) const;	// interval evaluation based on the monomial form
	void intEval(iMatrix & result, const Interval & val) const;							// interval evaluation based on the Horner form

	void intEval(iMatrix2 & result, const std::vector<Interval> & val_exp_table) const;
	void intEval(iMatrix2 & result, const Interval & val) const;

	void integral();
	void times_x(const int order);
	void transpose(upMatrix & result) const;

	void times_pars(mpMatrix & result) const;

	void ctrunc(iMatrix & rem, const int order, const std::vector<Interval> & val_exp_table);
	void ctrunc(iMatrix & rem, const int order, const Interval & val);

	void ctrunc(iMatrix & rem1, iMatrix & rem2, const int order, const std::vector<Interval> & val1_exp_table, const std::vector<Interval> & val2_exp_table);
	void ctrunc(iMatrix & rem1, iMatrix & rem2, const int order, const Interval & val1, const Interval & val2);

	void ctrunc(const int order, const std::vector<Interval> & val_exp_table);
	void ctrunc(const int order, const Interval & val);

	void nctrunc(const int order);

	void substitute(upMatrix & result, const std::vector<UnivariatePolynomial> & t_exp_table) const;
	void substitute(upMatrix & result, const UnivariatePolynomial & t) const;

	void output(FILE *fp) const;

	void decompose(upMatrix & positive, upMatrix & negative, iMatrix2 & im2_rem) const;

	upMatrix & operator += (const upMatrix & upm);
	upMatrix & operator += (const iMatrix & A);
	upMatrix & operator += (const Real & rad);
	upMatrix & operator -= (const upMatrix & upm);
	upMatrix & operator -= (const iMatrix & A);
	upMatrix & operator *= (const upMatrix & upm);
	upMatrix & operator *= (const iMatrix & A);
	upMatrix & operator *= (const Interval & I);

	upMatrix operator + (const upMatrix & upm) const;
	upMatrix operator + (const iMatrix & A) const;
	upMatrix operator - (const upMatrix & upm) const;
	upMatrix operator - (const iMatrix & A) const;
	upMatrix operator * (const upMatrix & upm) const;
	upMatrix operator * (const iMatrix & A) const;
	upMatrix operator * (const iMatrix2 & A) const;
	upMatrix operator * (const Interval & I) const;
	mpMatrix operator * (const mpMatrix & mpm) const;

	UnivariatePolynomial * operator [] (const int i);

	upMatrix & operator = (const upMatrix & upm);

	friend class iMatrix;
	friend class iMatrix2;
};

// matrix for multivariate polynomials
class mpMatrix
{
protected:
	Polynomial *data;
	int size1;
	int size2;

public:
	mpMatrix();
	mpMatrix(const int m, const int n);
	mpMatrix(const int n);
	mpMatrix(const mpMatrix & mpm);
	~mpMatrix();

	int rows() const;
	int cols() const;

	void intEval(mpMatrix & result, const std::vector<Interval> & val_exp_table) const;
	void intEval(iMatrix & result, const std::vector<Interval> & domain) const;

	void output(FILE *fp, const std::vector<std::string> & varNames) const;

	mpMatrix & operator += (const mpMatrix & mpm);

	mpMatrix operator + (const mpMatrix & mpm) const;

	Polynomial * operator [] (const int i);
	mpMatrix & operator = (const mpMatrix & mpm);

	friend class iMatrix;
	friend class upMatrix;
};

class MatrixParseSetting
{
public:
	std::string strExpression;
	iMatrix result;

public:
	MatrixParseSetting();
	MatrixParseSetting(const MatrixParseSetting & setting);
	~MatrixParseSetting();

	MatrixParseSetting & operator = (const MatrixParseSetting & setting);
};

void to_iMatrix2(iMatrix2 & result, const rMatrix & lo, const rMatrix & up);

extern MatrixParseSetting matrixParseSetting;

}

void parse_Matrix();

#endif /* MATRIX_H_ */


#include <stdio.h>
#include <math.h>

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

#define N (4096*4*16)

int main (void)
{
    long countsq;
    double x, r2;
    //6 dimensional space
    int dim = 6;

    gsl_rng *r;

    r = gsl_rng_alloc (gsl_rng_taus2);
    gsl_rng_set (r, 1UL);

    long i, j, nn;

    printf ("# Iter        Npoints   Volume     AbsErr\n");
    nn = N;
    for (j = 0; j < 16; j++)
    {
        countsq = 0L;
        for (i = 0; i < nn; i++)
        {
            // 4-dimensional distance from the origin, squared
            r2 = 0.;
            for (int k = 0; k < dim; k++)
            {
                x = 2 * gsl_rng_uniform (r) - 1.;
                r2 += x * x;
            }

            // are we inside the unit ball
            if (r2 <= 1.)
            {
                countsq++;
            }
        }
        // ratio of the volume of the 4-dimensional unit ball and
        // and 4-dimensional cube of side length 2.
        double vol = ((double) countsq) * pow (2, (double) dim) / nn;
        double exact = M_PI * M_PI / 2;

        printf ("%3ld  %16ld   %f   %f\n", j, nn, vol, fabs (exact - vol));
        nn *= 2;
    }

    gsl_rng_free (r);

    return 0;
}


/*! \file
  2D/3D median filter

\par Author:
Gabriele Lohmann, MPI-CBS
*/

/* From the Vista library: */
#include <viaio/VImage.h>
#include <viaio/Vlib.h>
#include <viaio/mu.h>

/* From the standard C library: */
#include <stdio.h>
#include <stdlib.h>

#include <gsl/gsl_cblas.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_statistics.h>
#include <gsl/gsl_sort.h>

#define ABS(x) ((x) > 0 ? (x) : -(x))

/*!
\fn VImage VMedianImage3d (VImage src, VImage dest, int dim, VBoolean ignore)
\param src      input image
\param dest     output image
\param dim      kernel size (3,5,7...)
\param ignore   whether to ignore zero voxels
*/
VImage
VMedianImage3d (VImage src, VImage dest, int dim, VBoolean ignore)
{
  int nbands,nrows,ncols;
  int i,len,len2,b,r,c,bb,rr,cc,b0,b1,r0,r1,c0,c1,d=0;
  gsl_vector *vec=NULL;
  double u,tiny=1.0e-8;

  if (dim%2 == 0) VError("VMedianImage3d: dim (%d) must be odd",dim);

  nrows  = VImageNRows (src);
  ncols  = VImageNColumns (src);
  nbands = VImageNBands (src);
  if (nbands <= d) VError("VMedianImage3d: number of slices too small (%d)",nbands);

  d = dim/2;
  len = dim * dim * dim;
  len2 = len/2;

  vec = gsl_vector_calloc(len);

  dest = VCopyImage(src,dest,VAllBands);
  VFillImage(dest,VAllBands,0);

  for (b=d; b<nbands-d; b++) {
    for (r=d; r<nrows-d; r++) {
      for (c=d; c<ncols-d; c++) {

	u = VGetPixel(src,b,r,c);

	i = 0;
	b0 = b-d;
	b1 = b+d;
	for (bb=b0; bb<=b1; bb++) {

	  r0 = r-d;
	  r1 = r+d;
	  for (rr=r0; rr<=r1; rr++) {

	    c0 = c-d;
	    c1 = c+d;
	    for (cc=c0; cc<=c1; cc++) {
	      u = VGetPixel(src,bb,rr,cc);
	      if (ABS(u) > tiny && ignore == TRUE) {
		gsl_vector_set(vec,i,u);
		i++;
	      }
	    }
	  }

	  if (i < len2) continue;
	  gsl_sort(vec->data,vec->stride,(size_t)i);
	  u = gsl_stats_median_from_sorted_data(vec->data,vec->stride,i);
	  VSetPixel(dest,b,r,c,u);
	}
      }
    }
  }
  gsl_vector_free(vec);
  return dest;
}

/*!
\fn VImage VMedianImage2d (VImage src, VImage dest, int dim, VBoolean ignore)
\param src      input image
\param dest     output image
\param dim      kernel size
\param ignore   whether to ignore zero voxels
*/
VImage VMedianImage2d (VImage src, VImage dest, int dim, VBoolean ignore)
{
  int nbands,nrows,ncols;
  int i,len,len2,b,r,c,rr,cc,d=0;
  gsl_vector *vec=NULL;
  double u=0;

  if (dim%2 == 0) VError("VMedianImage2d: dim (%d) must be odd",dim);

  nrows  = VImageNRows (src);
  ncols  = VImageNColumns (src);
  nbands = VImageNBands (src);

  d = dim/2;
  len = dim * dim;
  len2 = len/2;
  vec = gsl_vector_calloc(len);

  dest   = VCopyImage(src,dest,VAllBands);

  for (b=0; b<nbands; b++) {
    for (r=d; r<nrows-d; r++) {
      for (c=d; c<ncols-d; c++) {
	gsl_vector_set_zero(vec);

	u = VGetPixel(src,b,r,c);

	i = 0;
	for (rr=r-d; rr<=r+d; rr++) {
	  for (cc=c-d; cc<=c+d; cc++) {
	    u = VGetPixel(src,b,rr,cc);
	    if (ABS(u) > 0 && ignore == TRUE) {
	      gsl_vector_set(vec,i,u);
	      i++;
	    }
	  }
	}

	if (i < len2) continue;
	gsl_sort(vec->data,vec->stride,(size_t)i);
	u = gsl_stats_median_from_sorted_data(vec->data,vec->stride,i);
	VSetPixel(dest,b,r,c,u);
      }
    }
  }
  gsl_vector_free(vec);
  return dest;
}


#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_min.h>

double fn1 (double x, void * params)
{
  return cos(x) + 1.0;
}

int
main (void)
{
  int status;
  int iter = 0, max_iter = 100;
  const gsl_min_fminimizer_type *T;
  gsl_min_fminimizer *s;
  double m = 2.0, m_expected = M_PI;
  double a = 0.0, b = 6.0;
  gsl_function F;

  F.function = &fn1;
  F.params = 0;

  T = gsl_min_fminimizer_brent;
  s = gsl_min_fminimizer_alloc (T);
  gsl_min_fminimizer_set (s, &F, m, a, b);

  printf ("using %s method\n",
          gsl_min_fminimizer_name (s));

  printf ("%5s [%9s, %9s] %9s %10s %9s\n",
          "iter", "lower", "upper", "min",
          "err", "err(est)");

  printf ("%5d [%.7f, %.7f] %.7f %+.7f %.7f\n",
          iter, a, b,
          m, m - m_expected, b - a);

  do
    {
      iter++;
      status = gsl_min_fminimizer_iterate (s);

      m = gsl_min_fminimizer_x_minimum (s);
      a = gsl_min_fminimizer_x_lower (s);
      b = gsl_min_fminimizer_x_upper (s);

      status
        = gsl_min_test_interval (a, b, 0.001, 0.0);

      if (status == GSL_SUCCESS)
        printf ("Converged:\n");

      printf ("%5d [%.7f, %.7f] "
              "%.7f %+.7f %.7f\n",
              iter, a, b,
              m, m - m_expected, b - a);
    }
  while (status == GSL_CONTINUE && iter < max_iter);

  gsl_min_fminimizer_free (s);

  return status;
}