/*******************************************************************************
 * Copyright 2013-2014 Sebastian Niemann <niemann@sra.uni-hannover.de>.
 *
 * Licensed under the MIT License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/MIT
 *
 * Developers:
 *   Sebastian Niemann - Lead developer
 *   Daniel Kiechle - Unit testing
 ******************************************************************************/
#include <Expected.hpp>
using armadilloJava::Expected;

#include <iostream>
using std::cout;
using std::endl;

#include <utility>
using std::pair;

#include <armadillo>
using arma::Mat;
using arma::Col;
using arma::uword;

#include <InputClass.hpp>
using armadilloJava::InputClass;

#include <Input.hpp>
using armadilloJava::Input;

namespace armadilloJava {
  class ExpectedInPlaceGenMatColIndsGenMat : public Expected {
    public:
      ExpectedInPlaceGenMatColIndsGenMat() {
        cout << "Compute ExpectedInPlaceGenMatColIndsGenMat(): " << endl;

        vector<vector<pair<string, void*>>> inputs = Input::getTestParameters({
          InputClass::GenMat,
          InputClass::ColInds,
          InputClass::GenMat
        });

        for (vector<pair<string, void*>> input : inputs) {
          _fileSuffix = "";

          int n = 0;
          for (pair<string, void*> value : input) {
            switch (n) {
              case 0:
                _fileSuffix += value.first;
                _genMatA = *static_cast<Mat<double>*>(value.second);
                break;
              case 1:
                _fileSuffix += "," + value.first;
                _colInds = *static_cast<Col<uword>*>(value.second);
                break;
              case 2:
                _fileSuffix += "," + value.first;
                _genMatB = *static_cast<Mat<double>*>(value.second);
                break;
            }
            ++n;
          }

          cout << "Using input: " << _fileSuffix << endl;

          _copyOfGenMatA = _genMatA;
          _copyOfColInds = _colInds;
          _copyOfGenMatB = _genMatB;

          expectedColsEqual();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedColsPlus();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedColsMinus();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedColsElemTimes();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedColsElemDivide();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedEach_colEqual();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedEach_colPlus();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedEach_colMinus();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedEach_colElemTimes();

          _genMatA = _copyOfGenMatA;
          _colInds = _copyOfColInds;
          _genMatB = _copyOfGenMatB;
          expectedEach_colElemDivide();
        }

        cout << "done." << endl;
      }

    protected:
      Mat<double> _genMatA;
      Mat<double> _copyOfGenMatA;

      Col<uword> _colInds;
      Col<uword> _copyOfColInds;

      Mat<double> _genMatB;
      Mat<double> _copyOfGenMatB;

      void expectedColsEqual() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        if(_genMatB.n_cols != _colInds.n_elem) {
          return;
        }

        cout << "- Compute expectedColsEqual() ... ";

        _genMatA.cols(_colInds) = _genMatB;
        save<double>("Mat.colsEqual", _genMatA);

        cout << "done." << endl;
      }

      void expectedColsPlus() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        if(_genMatB.n_cols != _colInds.n_elem) {
          return;
        }

        cout << "- Compute expectedColsPlus() ... ";

        _genMatA.cols(_colInds) += _genMatB;
        save<double>("Mat.colsPlus", _genMatA);

        cout << "done." << endl;
      }

      void expectedColsMinus() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        if(_genMatB.n_cols != _colInds.n_elem) {
          return;
        }

        cout << "- Compute expectedColsMinus() ... ";

        _genMatA.cols(_colInds) -= _genMatB;
        save<double>("Mat.colsMinus", _genMatA);

        cout << "done." << endl;
      }

      void expectedColsElemTimes() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        if(_genMatB.n_cols != _colInds.n_elem) {
          return;
        }

        cout << "- Compute expectedColsElemTimes() ... ";

        _genMatA.cols(_colInds) %= _genMatB;
        save<double>("Mat.colsElemTimes", _genMatA);

        cout << "done." << endl;
      }

      void expectedColsElemDivide() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        if(_genMatB.n_cols != _colInds.n_elem) {
          return;
        }

        cout << "- Compute expectedColsElemDivide() ... ";

        _genMatA.cols(_colInds) /= _genMatB;
        save<double>("Mat.colsElemDivide", _genMatA);

        cout << "done." << endl;
      }

      void expectedEach_colEqual() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(!_genMatB.is_colvec()) {
          return;
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        cout << "- Compute expectedEach_colEqual() ... ";

        _genMatA.each_col(_colInds) = _genMatB;
        save<double>("Mat.each_colEqual", _genMatA);

        cout << "done." << endl;
      }

      void expectedEach_colPlus() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(!_genMatB.is_colvec()) {
          return;
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        cout << "- Compute expectedEach_colPlus() ... ";

        _genMatA.each_col(_colInds) += _genMatB;
        save<double>("Mat.each_colPlus", _genMatA);

        cout << "done." << endl;
      }

      void expectedEach_colMinus() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(!_genMatB.is_colvec()) {
          return;
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        cout << "- Compute expectedEach_colMinus() ... ";

        _genMatA.each_col(_colInds) -= _genMatB;
        save<double>("Mat.each_colMinus", _genMatA);

        cout << "done." << endl;
      }

      void expectedEach_colElemTimes() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(!_genMatB.is_colvec()) {
          return;
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        cout << "- Compute expectedEach_colElemTimes() ... ";

        _genMatA.each_col(_colInds) %= _genMatB;
        save<double>("Mat.each_colElemTimes", _genMatA);

        cout << "done." << endl;
      }

      void expectedEach_colElemDivide() {
        for(int j = 0; j < _colInds.n_elem; j++) {
          if(_colInds.at(j) >= _genMatA.n_cols) {
            return;
          }
        }

        if(!_genMatB.is_colvec()) {
          return;
        }

        if(_genMatB.n_rows != _genMatA.n_rows) {
          return;
        }

        cout << "- Compute expectedEach_colElemDivide() ... ";

        _genMatA.each_col(_colInds) /= _genMatB;
        save<double>("Mat.each_colElemDivide", _genMatA);

        cout << "done." << endl;
      }

  };
}


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_FREXP_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_FREXP_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>

#include <boost/simd/meta/hierarchy/simd.hpp>
#include <boost/simd/detail/constant/limitexponent.hpp>
#include <boost/simd/detail/constant/mask1frexp.hpp>
#include <boost/simd/detail/constant/mask2frexp.hpp>
#include <boost/simd/detail/constant/maxexponentm1.hpp>
#include <boost/simd/constant/nbmantissabits.hpp>
#include <boost/simd/function/bitwise_and.hpp>
#include <boost/simd/function/bitwise_andnot.hpp>
#include <boost/simd/function/bitwise_cast.hpp>
#include <boost/simd/function/bitwise_or.hpp>
#include <boost/simd/function/if_else_zero.hpp>
#include <boost/simd/function/is_greater.hpp>
#include <boost/simd/function/is_nez.hpp>
#include <boost/simd/function/logical_notand.hpp>
#include <boost/simd/function/minus.hpp>
#include <boost/simd/function/multiplies.hpp>
#include <boost/simd/function/if_plus.hpp>
#include <boost/simd/function/shr.hpp>
#include <boost/simd/detail/dispatch/meta/as_integer.hpp>
#include <utility>

#ifndef BOOST_SIMD_NO_DENORMALS
#include <boost/simd/function/is_less.hpp>
#include <boost/simd/function/is_nez.hpp>
#include <boost/simd/function/if_else.hpp>
#include <boost/simd/function/abs.hpp>
#include <boost/simd/function/logical_and.hpp>
#include <boost/simd/constant/twotonmb.hpp>
#include <boost/simd/constant/smallestposval.hpp>
#endif

namespace boost { namespace simd { namespace ext
{
   namespace bd = boost::dispatch;
   namespace bs = boost::simd;
   BOOST_DISPATCH_OVERLOAD(frexp_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::floating_<A0>, X>
                          )
   {
     using i_t = bd::as_integer_t<A0, signed>;
     BOOST_FORCEINLINE std::pair<A0,i_t> operator()(A0 const& a0) const
     {
       A0 r0;
       i_t r1;
       using s_type = bd::scalar_of_t<A0>;
#ifndef BOOST_SIMD_NO_DENORMALS
       auto test = logical_and(is_less(bs::abs(a0), Smallestposval<A0>()), is_nez(a0));
       A0 aa0 = if_else(test, Twotonmb<A0>()*a0, a0);
       i_t t = if_else_zero(test,Nbmantissabits<A0>());
#else
       A0 aa0 = a0;
#endif
       r1 = simd::bitwise_cast<i_t>(bitwise_and(aa0, Mask1frexp<A0>())); //extract exp.
       A0 x = bitwise_andnot(aa0, Mask1frexp<A0>());
       r1 = shr(r1,Nbmantissabits<s_type>()) - Maxexponentm1<A0>();
       r0 = bitwise_or(x,Mask2frexp<A0>());
       auto test0 = is_nez(aa0);
       auto test1 = is_greater(r1,Limitexponent<A0>());
       r1 = if_else_zero(logical_notand(test1, test0), r1);
#ifndef BOOST_SIMD_NO_DENORMALS
       r1 -= t ;
#endif
       r0 = if_else_zero(test0, if_plus(test1,r0,aa0));
       return {r0, r1};
     }
   };

  BOOST_DISPATCH_OVERLOAD( frexp_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , boost::simd::fast_tag
                          , bs::pack_< bd::floating_<A0>, X>
                          )
  {
    using i_t = bd::as_integer_t<A0, signed>;
    using sA0 = bd::scalar_of_t<A0>;
    BOOST_FORCEINLINE std::pair<A0,i_t> operator() (const fast_tag &
                                                   , A0 const& a0 ) const BOOST_NOEXCEPT
    {
      i_t r1  = bitwise_cast<i_t>(bitwise_and(Mask1frexp<A0>(), a0));
      A0  x = bitwise_andnot(a0, Mask1frexp<A0>());
      return {bitwise_or(x,Mask2frexp<A0>()), shr(r1,Nbmantissabits<sA0>()) - Maxexponentm1<A0>()};
    }
  };

} } }

#endif


/*
 * Copyright (c) 2013 Masahide Kashiwagi (kashi@waseda.jp)
 */

#ifndef MAKE_CANDIDATE_HPP
#define MAKE_CANDIDATE_HPP

#include <boost/numeric/ublas/vector.hpp>

/*
 * calculate radius of candidate set from newton step vector
 */

namespace kv {

template <class T> void make_candidate(boost::numeric::ublas::vector<T>& x)
{
	int n = x.size();
	int i;

#ifdef NEWTON_TWICE
	T m(0.);
	for (i=0; i<n; i++) {
		if (x(i) > m) m = x(i);
	}
	for (i=0; i<n; i++) x(i) = 2. * m;
#else
	T av(0.);

	for (i=0; i<n; i++) av += x(i);

	av /= n;

	for (i=0; i<n; i++) x(i) += av;
#endif
}

} // namespace kv

#endif // MAKE_CANDIDATE_HPP


#include <iostream>
//#include <iomanip>
//#include <fstream>

//#include <boost/numeric/ublas/matrix.hpp>
//#include <boost/numeric/ublas/vector.hpp>
//#include <boost/numeric/ublas/io.hpp>

#include <vector>
#include <cmath>
#include <cstring>

//#include <unistd.h>

#include "NRGclasses.hpp"
#include "NRGfunctions.hpp"
#include "DM_NRG.hpp"
#include "NRGOpMatRules.hpp"

#ifndef pi
#define pi 3.141592653589793238462643383279502884197169
#endif

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

  CNRGCodeHandler ThisCode;

  //CNRGbasisarray AcutN;
  CNRGbasisarray* AcutN;
  CNRGbasisarray AbasisN;

  //CNRGbasisarray AcutNp1;
  CNRGbasisarray AbasisNp1;

  CNRGmatrix** OpArrayN;

  CNRGmatrix* RhoN;
  vector<double> ParamsTemp;
  double betabar, DM,TM;
  // 0 - betabar; 1 - TM; 2 - DM ?

  char CNsites[8];
  char CNmat[8];
  char arqname[32];
  char ext[32];

  int NshellMax=3;
  int NFermiOps=2;

  ThisCode.NumNRGmats=0;
  ThisCode.pAcut=&AcutN[NshellMax];
  ThisCode.pAbasis=&AbasisN;
  //ThisCode.MatArray=MatArray;

  // Set betabar
  betabar=0.727;
  ParamsTemp.push_back(betabar);

  // Tricky

  OpArrayN=new CNRGmatrix* [NFermiOps];
  for (int iop=0;iop<NFermiOps;iop++){
    OpArrayN[iop]=new CNRGmatrix [NshellMax+1];
  }

  AcutN = new CNRGbasisarray [NshellMax+1];
  RhoN = new CNRGmatrix [NshellMax+1];

  ThisCode.ReadGenPars("");

  // This for now
  ThisCode.Nsitesmax=NshellMax;

  cout << "Lambda = " << ThisCode.Lambda << endl;
  cout << "Nsitesmax = " << ThisCode.Nsitesmax << endl;

  // Read last Nshell

  AcutN[NshellMax].Nshell=NshellMax;
  AbasisNp1.Nshell=NshellMax;
  //ThisCode.ReadArrays("test"); // ReadsInto pAcutN
  // Not too handy...

  sprintf(CNsites,"%d",NshellMax);
  strcpy(ext,"test_N");
  strcat(ext,CNsites);
  strcat(ext,".bin");

  // Read Abasis
  strcpy(arqname,"Abasis_");
  strcat(arqname,ext);
  AbasisNp1.ReadBin(arqname);

  // Read Acut
  strcpy(arqname,"Acut_");
  strcat(arqname,ext);
  AcutN[NshellMax].ReadBin(arqname);

  // Read Operators
  for (int iop=0;iop<NFermiOps;iop++){
    sprintf(CNmat,"%d",iop);
    strcpy(arqname,"Mat");
    strcat(arqname,CNmat);
    strcat(arqname,"_");
    strcat(arqname,ext);
    OpArrayN[iop][NshellMax].ReadBin(arqname);
    // Need a better way to do this but for now it will do:
    // Actually, from Mat block it works!
    //OpArrayN[iop][NshellMax].CheckForMatEl=OneChQSz_cd_check;

  }
  // end read operators

  //AcutN[NshellMax].PrintAll();

  // Set density matrix at the LAST NRG iteration

  DM_NRG_SetRhoNmax(ParamsTemp,&AcutN[NshellMax],&RhoN[NshellMax]);

  //RhoN[NshellMax].PrintAllBlocks();

  // Calculate reduced density matrices

  for (int Nshell=NshellMax-1;Nshell>=0;Nshell--){

    AcutN[Nshell].ClearAll();
    AbasisN.ClearAll();
    AcutN[Nshell].Nshell=Nshell;
    AbasisN.Nshell=Nshell;
    //ThisCode.ReadArrays("test"); // ReadsInto pAcutN
    // Not too handy...

    sprintf(CNsites,"%d",Nshell);
    strcpy(ext,"test_N");
    strcat(ext,CNsites);
    strcat(ext,".bin");

    // Read Abasis
    strcpy(arqname,"Abasis_");
    strcat(arqname,ext);
    AbasisN.ReadBin(arqname);

    // Read Acut
    strcpy(arqname,"Acut_");
    strcat(arqname,ext);
    AcutN[Nshell].ReadBin(arqname);

    // Set ChildStates in AcutN
    DM_NRG_SetChildSt(&AcutN[Nshell],&AbasisNp1);

    // Set RhoN from RhoNp1

    DM_NRG_CalcRhoN(ParamsTemp,
		    &AcutN[Nshell],&AcutN[Nshell+1],&AbasisNp1,
		    &RhoN[Nshell],
		    &RhoN[Nshell+1]);

    //RhoN[Nshell].PrintAllBlocks();

    // Update AbasisNp1
    AbasisNp1.ClearAll();
    AbasisNp1=AbasisN;

    // Read Operators
    for (int iop=0;iop<NFermiOps;iop++){
      sprintf(CNmat,"%d",iop); // Get all SavedMatrices
      strcpy(arqname,"Mat");
      strcat(arqname,CNmat);
      strcat(arqname,"_");
      strcat(arqname,ext);
      OpArrayN[iop][Nshell].ReadBin(arqname);
      // Need a better way to do this but for now it will do:
      // Not needed!
      //OpArrayN[iop][Nshell].CheckForMatEl=OneChQSz_cd_check;

    }
    // end read operators

  }
  // end loop in Nshell

  // Given AcutN, rhoN and the Operators, calculate the spectral density

  DM_NRG_CalcSpecFuncs(&ThisCode,AcutN,RhoN,OpArrayN);

  delete[] RhoN;
  delete[] AcutN;
  for (int iop=NFermiOps-1;iop>=0;iop--){
    delete[] OpArrayN[iop];
  }
  delete[] OpArrayN;

}
// end MAIN


//          Copyright Gavin Band 2008 - 2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <iostream>
#include <iomanip>
#include <vector>
#include <utility>
#include <algorithm>
#include <boost/format.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include "metro/regression/Logistic.hpp"
#include "metro/intersect_ranges.hpp"
#include "metro/summation.hpp"
#include "genfile/string_utils.hpp"
#include "genfile/Error.hpp"

// #define DEBUG_LOGLIKELIHOOD 2

namespace metro {
	namespace regression {

		namespace {
			std::string standard_parameter_name( std::string const& predictor_name, std::string const& outcome_name ) {
				return predictor_name + "/" + outcome_name ;
			}
		}

		Logistic::UniquePtr Logistic::create(
			regression::Design& design
		) {
			return Logistic::UniquePtr(
				new Logistic( design )
			) ;
		}

		Logistic::UniquePtr Logistic::create(
			regression::Design::UniquePtr design
		) {
			return Logistic::UniquePtr(
				new Logistic( design )
			) ;
		}

		namespace {
			void check_design( regression::Design const& design ) {
				// Verify design looks sane.
				// Right now we handle only a bernoulli outcome, i.e.
				// each sample must have a 1 in column 0 or 1 of the outcome matrix.
				Logistic::Matrix const& outcome = design.outcome() ;
				if( outcome.cols() != 2 ) {
					throw genfile::BadArgumentError(
						"metro::case_control::Logistic::check_design()",
						"design",
						"Expected outcome to have 2 columns (count of fail and success outcomes) with row sums == 1"
					) ;
				}
				regression::Design::SampleRanges const& ranges = design.nonmissing_samples() ;
				for( std::size_t range_i = 0; range_i < ranges.size(); ++range_i ) {
					for( int i = ranges[range_i].begin(); i < ranges[range_i].end(); ++i ) {
						if(
							(outcome.row(i).sum() == outcome.row(i).sum())
							&& (
								( outcome.row(i).sum() != 1.0 )
								|| ( outcome(i,0) != 1.0 && outcome(i,1) != 1.0 )
							)
						) {
							throw genfile::BadArgumentError(
								"metro::case_control::Logistic::check_design()",
								"design",
								( boost::format( "Outcome (%f for individual %d) has non-missing level other than zero or one." ) % outcome(i) % (i+1) ).str()
							) ;
						}
					}
				}
			}
		}

		Logistic::Logistic(
			regression::Design::UniquePtr design
		):
			m_design( design.release() ),
			m_design_owned( true ),
			m_get_parameter_name( &standard_parameter_name ),
			m_parameters( Vector::Zero( m_design->matrix().cols() ) ),
			m_state( e_Uncomputed )
		{
			check_design( *m_design ) ;
		}

		Logistic::Logistic(
			regression::Design& design
		):
			m_design( &design ),
			m_design_owned( false ),
			m_get_parameter_name( &standard_parameter_name ),
			m_parameters( Vector::Zero( m_design->matrix().cols() ) ),
			m_state( e_Uncomputed )
		{
			assert( m_design != 0 ) ;
			check_design( *m_design ) ;
		}

		Logistic::~Logistic() {
			if( m_design_owned ) {
				delete m_design ;
			}
		}

		std::string Logistic::get_summary() const {
			using genfile::string_utils::to_string ;
			return "Logistic( "
				+ to_string( m_design->outcome().rows() )
				+ " samples )" ;
		}

		void Logistic::set_parameter_naming_scheme( Logistic::GetParameterName get_parameter_name ) {
			assert( get_parameter_name ) ;
			m_get_parameter_name = get_parameter_name ;
		}

		std::string Logistic::get_parameter_name( std::size_t i ) const {
			IntegerMatrix const identity = identify_parameters() ;
			return m_get_parameter_name( m_design->get_predictor_name( identity(i,1) ), m_design->get_outcome_name(identity(i,0)) ) ;
		}

		int Logistic::number_of_parameters() const {
			return m_design->matrix().cols() ;
		}

		LogLikelihood::IntegerMatrix Logistic::identify_parameters() const {
			IntegerMatrix result = IntegerMatrix::Zero( m_design->matrix().cols(), 2 ) ;
			// Each parameter corresponds to an effect for the non-baseline outcome level
			// and a column of the design matrix.
			result.col(0).setConstant( 1.0 ) ;
			// There is one parameter per design matrix column.
			for( int i = 0; i < m_design->matrix().cols(); ++i ) {
				result( i, 1 ) = i ;
			}
			return result ;
		}

		int Logistic::number_of_outcomes() const {
			return 2 ;
		}

		void Logistic::evaluate_at( Point const& parameters, int const numberOfDerivatives ) {
			evaluate_at_impl( parameters, m_design->nonmissing_samples(), numberOfDerivatives ) ;
		}

		void Logistic::evaluate_at_impl(
			Point const& parameters,
			std::vector< metro::SampleRange > const& included_samples,
			int const numberOfDerivatives
		) {
//			m_state = eUncomputed ;
			assert( parameters.size() == m_design->matrix().cols() ) ;
			assert( numberOfDerivatives < 3 ) ;

			m_state = e_Uncomputed ;
			m_parameters = parameters ;
			m_included_samples = included_samples ;

#if DEBUG_LOGLIKELIHOOD
			std::cerr << std::fixed << std::setprecision(4) ;
			int const N = m_design->outcome().rows() ;
			std::cerr << "==== Logistic::evaluate_at() ====\n" ;
			std::cerr << "  m_state: " << ( boost::format( "0x%x" ) % m_state ).str() << ", "
				<< "Number of samples: " << N << ", "
				<< "Included samples:" ;
			for( std::size_t i = 0; i < included_samples.size(); ++i ) {
				std::cerr << " " << included_samples[i].begin() << "-" << included_samples[i].end() ;
			}
			std::cerr << "\n" ;
			std::cerr << "  Params: " << parameters.transpose() << ".\n" ;
			std::cerr << "  Phenotypes: " << m_design->outcome().col(1).head( std::min( N, 5 ) ).transpose() << "...\n";
			//std::cerr << "  Predictor levels: " << m_design->get_predictor_levels().transpose() << ".\n" ;
#endif
			evaluate( numberOfDerivatives ) ;
		}

		void Logistic::evaluate( int const numberOfDerivatives ) {
			bool computeFunction = ( m_state == e_Uncomputed ) ;
			bool compute1stDerivative = ( (numberOfDerivatives > 0) & !(m_state & e_Computed1stDerivative )) ;
			bool compute2ndDerivative = ( (numberOfDerivatives > 1) & !(m_state & e_Computed2ndDerivative )) ;

			// Calculate log-likelihood if needed.
			if( computeFunction ) {
	 			calculate_outcome_probabilities( m_parameters, m_design->outcome(), &m_outcome_probabilities ) ;
				m_A = m_design->get_predictor_level_probabilities().array() * m_outcome_probabilities.array() ;
				compute_value_of_function( m_A, m_included_samples ) ;
				m_state |= e_ComputedFunction ;
				// (m_state | e_ComputedFunction) = 1 implies m_A and m_outcome_probabilities, as well as function value, are computed
			}

#if DEBUG_LOGLIKELIHOOD
			std::cerr << "  " << ( computeFunction ? "(computed) " : "(memoized) " ) << "function value = " << m_value_of_function << "\n" ;
#endif

			if( compute1stDerivative ) {
				compute_value_of_first_derivative( m_A, m_included_samples, &m_B ) ;
				m_state |= e_Computed1stDerivative ;
				// m_state | e_Computed1stDerivative implies m_B, as well as 1st derivative, are computed
			}
#if DEBUG_LOGLIKELIHOOD
			if( m_state & e_Computed1stDerivative ) {
				std::cerr << "  " << ( compute1stDerivative ? "(computed) " : "(memoized) " ) << "derivative = " << m_value_of_first_derivative.transpose() << "\n" ;
			} else {
				std::cerr << "  (1st derivative not computed).\n" ;
			}
#endif

			if( compute2ndDerivative ) {
				compute_value_of_second_derivative( m_B, m_included_samples ) ;
				m_state |= e_Computed2ndDerivative ;
			}
#if DEBUG_LOGLIKELIHOOD
			if( m_state & e_Computed2ndDerivative ) {
				std::cerr << "  " << ( compute2ndDerivative ? "(computed) " : "(memoized) " ) << "2nd derivative = \n"
					<< m_value_of_second_derivative << ".\n" ;
			} else {
				std::cerr << "  (2nd derivative not computed).\n" ;
			}
			std::cerr << "====\n" ;
#endif
		}

		Logistic::Point const& Logistic::parameters() const {
			return m_parameters ;
		}

		// Calculate P( outcome | genotype, covariates, parameters ).
		void Logistic::calculate_outcome_probabilities(
			Vector const& parameters,
			Matrix const& outcome,
			Logistic::Matrix* result
		) const {
			assert( outcome.cols() == 2 ) ;
			result->resize( outcome.rows(), m_design->get_number_of_predictor_levels() ) ;
			Vector linear_combination ;
			int const number_of_predictor_levels = m_design->get_number_of_predictor_levels() ;
			for( int g = 0; g < number_of_predictor_levels; ++g ) {
				Matrix const& design_matrix = m_design->set_predictor_level( g ).matrix() ;
				result->col( g ) = evaluate_mean_function( design_matrix * parameters, outcome ) ;
			}
		}

		Logistic::Vector Logistic::evaluate_mean_function( Vector const& linear_combinations, Matrix const& outcomes ) const {
			assert( linear_combinations.size() == outcomes.rows() ) ;
			// Only the 2nd column of the outcome (i.e. outcome is not baseline) is used in this calculation.
			Vector exps = linear_combinations.array().exp() ;
			Vector ones = Vector::Ones( linear_combinations.size() ) ;
			return ( ones.array() + outcomes.col(1).array() * ( exps.array() - ones.array() ) )  / ( ones + exps ).array() ;
		}

		void Logistic::compute_value_of_function( Matrix const& V, std::vector< metro::SampleRange > const& included_samples ) {
			m_value_of_function = 0.0 ;
			for( std::size_t i = 0; i < included_samples.size(); ++i ) {
				int const start_row = included_samples[i].begin() ;
				int const end_row = included_samples[i].end() ;
				m_value_of_function += neumaier_sum(
					V.block( start_row, 0, end_row - start_row, V.cols() ).rowwise().sum().array().log()
				) ;
			}
		}

		void Logistic::compute_value_of_first_derivative( Matrix const& A, std::vector< metro::SampleRange > const& included_samples, Matrix* B ) {
			int const N = m_design->outcome().rows() ;
			int const D = m_design->matrix().cols() ;
			int const N_predictor_levels = m_design->get_number_of_predictor_levels() ;
			// ...and its first derivative...
			m_value_of_first_derivative = Vector::Zero( D ) ;
			(*B) = A ;
			{
				RowVector ones( RowVector::Ones( N_predictor_levels )) ;
				for( int i = 0; i < B->rows(); ++i ) {
					B->row(i) /= B->row(i).sum() ;
					B->row(i).array() *= ( ones - m_outcome_probabilities.row(i) ).array() ;
				}
			}

			{
				m_first_derivative_terms.setZero( m_design->matrix().rows(), m_design->matrix().cols() ) ;
				Vector signs = (( m_design->outcome().col(1) * 2.0 ) - Vector::Ones( N ) ) ; // == (-1)^{phenotype + 1}
				for( int g = 0; g < N_predictor_levels; ++g ) {
					Matrix const& design_matrix = m_design->set_predictor_level( g ).matrix() ;
#if DEBUG_LOGLIKELIHOOD
					std::cerr << "Logistic::compute_value_of_first_derivative(): design_matrix for predictor level " << g << " =\n"
						<< design_matrix.topRows( std::min( N, 5 ) ) << "\n" ;
#endif
					//m_design->matrix().block( 0, 1, m_design->matrix().rows(), predictor_levels.cols() ).rowwise() = predictor_levels.row( g ) ;
					for( std::size_t i = 0; i < included_samples.size(); ++i ) {
						int const start_row = included_samples[i].begin() ;
						int const end_row = included_samples[i].end() ;
						MatrixBlock block = m_first_derivative_terms.block( start_row, 0, end_row - start_row, m_first_derivative_terms.cols() ) ;
						// multiply ith row of design matrix by sign times ith entry of column of B.
						block += (
								signs.segment( start_row, end_row - start_row ).array()
								* B->col( g ).segment( start_row, end_row - start_row ).array()
							).matrix().asDiagonal()
							* design_matrix.block( start_row, 0, end_row - start_row, design_matrix.cols() )
						;
					}
				}
				m_value_of_first_derivative = m_first_derivative_terms.colwise().sum() ;
			}
		}

		void Logistic::compute_value_of_second_derivative( Matrix const& B, std::vector< metro::SampleRange > const& included_samples ) {
			int const D = m_design->matrix().cols() ;
			int const N_predictor_levels = m_design->get_number_of_predictor_levels() ;
			m_value_of_second_derivative = Matrix::Zero( D, D ) ;
			// Compute second derivative...
			for( int row_i = 0; row_i < D; ++row_i ) {
				MatrixBlock resultRow = m_value_of_second_derivative.block(row_i, 0, 1, D ) ;
				for( int g1 = 0; g1 < N_predictor_levels; ++g1 ) {
					Matrix const& design_matrix = m_design->set_predictor_level( g1 ).matrix() ;
					for( std::size_t sample_i = 0; sample_i < included_samples.size(); ++sample_i ) {
						int const start_row = included_samples[sample_i].begin() ;
						int const end_row = included_samples[sample_i].end() ;
						ConstMatrixBlock design_matrix_block = design_matrix.block( start_row, 0, end_row - start_row, design_matrix.cols() ) ;
						resultRow += (
								B.col(g1).segment( start_row, end_row - start_row ).array()
								* (
									Vector::Constant( end_row - start_row, 1.0 )
									- 2.0 * m_outcome_probabilities.col( g1 ).segment( start_row, end_row - start_row )
								).array()
								* design_matrix_block.col( row_i ).array()
							).matrix().transpose()
							* design_matrix_block
						;
					}
				}
				resultRow -= ( m_first_derivative_terms.col(row_i).asDiagonal() * m_first_derivative_terms ).colwise().sum() ;
			}
		}

		double Logistic::get_value_of_function() const {
			return m_value_of_function ;
		}

		Logistic::Vector Logistic::get_value_of_first_derivative() const {
			return m_value_of_first_derivative ;
		}

		Logistic::Matrix Logistic::get_value_of_second_derivative() const {
			return m_value_of_second_derivative ;
		}
	}
}


/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 *  @file  testProjectionFactorPPPC.cpp
 *  @brief Unit tests for Pose+Transform+Calibration ProjectionFactor Class
 *  @author Chris Beall
 *  @date Jul 29, 2014
 */

#include <gtsam/base/numericalDerivative.h>
#include <gtsam/base/TestableAssertions.h>
#include <gtsam_unstable/slam/ProjectionFactorPPPC.h>
#include <gtsam/inference/Symbol.h>
#include <gtsam/geometry/Cal3DS2.h>
#include <gtsam/geometry/Cal3_S2.h>
#include <gtsam/geometry/Pose3.h>
#include <gtsam/geometry/Point3.h>
#include <gtsam/geometry/Point2.h>

#include <CppUnitLite/TestHarness.h>

#include <boost/bind/bind.hpp>

using namespace boost::placeholders;
using namespace std;
using namespace gtsam;

// make a realistic calibration matrix
static double fov = 60; // degrees
static size_t w=640,h=480;
static Cal3_S2::shared_ptr K1(new Cal3_S2(fov,w,h));

// Create a noise model for the pixel error
static SharedNoiseModel model(noiseModel::Unit::Create(2));

// Convenience for named keys
using symbol_shorthand::X;
using symbol_shorthand::L;
using symbol_shorthand::T;
using symbol_shorthand::K;

typedef ProjectionFactorPPPC<Pose3, Point3, Cal3_S2> TestProjectionFactor;

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, nonStandard ) {
  ProjectionFactorPPPC<Pose3, Point3, Cal3DS2> f;
}

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, Constructor) {
  Point2 measurement(323.0, 240.0);
  TestProjectionFactor factor(measurement, model, X(1), T(1), L(1), K(1));
  // TODO: Actually check something
}

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, Equals ) {
  // Create two identical factors and make sure they're equal
  Point2 measurement(323.0, 240.0);

  TestProjectionFactor factor1(measurement, model, X(1), T(1), L(1), K(1));
  TestProjectionFactor factor2(measurement, model, X(1), T(1), L(1), K(1));

  CHECK(assert_equal(factor1, factor2));
}

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, Error ) {
  // Create the factor with a measurement that is 3 pixels off in x
  Point2 measurement(323.0, 240.0);
  TestProjectionFactor factor(measurement, model, X(1), T(1), L(1), K(1));

  // Set the linearization point
  Pose3 pose(Rot3(), Point3(0,0,-6));
  Point3 point(0.0, 0.0, 0.0);

  // Use the factor to calculate the error
  Vector actualError(factor.evaluateError(pose, Pose3(), point, *K1));

  // The expected error is (-3.0, 0.0) pixels / UnitCovariance
  Vector expectedError = Vector2(-3.0, 0.0);

  // Verify we get the expected error
  CHECK(assert_equal(expectedError, actualError, 1e-9));
}

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, ErrorWithTransform ) {
  // Create the factor with a measurement that is 3 pixels off in x
  Point2 measurement(323.0, 240.0);
  Pose3 transform(Rot3::RzRyRx(-M_PI_2, 0.0, -M_PI_2), Point3(0.25, -0.10, 1.0));
  TestProjectionFactor factor(measurement, model, X(1),T(1), L(1), K(1));

  // Set the linearization point. The vehicle pose has been selected to put the camera at (-6, 0, 0)
  Pose3 pose(Rot3(), Point3(-6.25, 0.10 , -1.0));
  Point3 point(0.0, 0.0, 0.0);

  // Use the factor to calculate the error
  Vector actualError(factor.evaluateError(pose, transform, point, *K1));

  // The expected error is (-3.0, 0.0) pixels / UnitCovariance
  Vector expectedError = Vector2(-3.0, 0.0);

  // Verify we get the expected error
  CHECK(assert_equal(expectedError, actualError, 1e-9));
}

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, Jacobian ) {
  // Create the factor with a measurement that is 3 pixels off in x
  Point2 measurement(323.0, 240.0);
  TestProjectionFactor factor(measurement, model, X(1), T(1), L(1), K(1));

  // Set the linearization point
  Pose3 pose(Rot3(), Point3(0,0,-6));
  Point3 point(0.0, 0.0, 0.0);

  // Use the factor to calculate the Jacobians
  Matrix H1Actual, H2Actual, H3Actual, H4Actual;
  factor.evaluateError(pose, Pose3(), point, *K1, H1Actual, H2Actual, H3Actual, H4Actual);

  // The expected Jacobians
  Matrix H1Expected = (Matrix(2, 6) << 0., -554.256, 0., -92.376, 0., 0., 554.256, 0., 0., 0., -92.376, 0.).finished();
  Matrix H3Expected = (Matrix(2, 3) << 92.376, 0., 0., 0., 92.376, 0.).finished();

  // Verify the Jacobians are correct
  CHECK(assert_equal(H1Expected, H1Actual, 1e-3));
  CHECK(assert_equal(H3Expected, H3Actual, 1e-3));

  // Verify H2 and H4 with numerical derivatives
  Matrix H2Expected = numericalDerivative11<Vector, Pose3>(
      boost::bind(&TestProjectionFactor::evaluateError, &factor, pose, _1, point,
          *K1, boost::none, boost::none, boost::none, boost::none), Pose3());

  Matrix H4Expected = numericalDerivative11<Vector, Cal3_S2>(
      boost::bind(&TestProjectionFactor::evaluateError, &factor, pose, Pose3(), point,
          _1, boost::none, boost::none, boost::none, boost::none), *K1);

  CHECK(assert_equal(H2Expected, H2Actual, 1e-5));
  CHECK(assert_equal(H4Expected, H4Actual, 1e-5));
}

/* ************************************************************************* */
TEST( ProjectionFactorPPPC, JacobianWithTransform ) {
  // Create the factor with a measurement that is 3 pixels off in x
  Point2 measurement(323.0, 240.0);
  Pose3 body_P_sensor(Rot3::RzRyRx(-M_PI_2, 0.0, -M_PI_2), Point3(0.25, -0.10, 1.0));
  TestProjectionFactor factor(measurement, model, X(1), T(1), L(1), K(1));

  // Set the linearization point. The vehicle pose has been selected to put the camera at (-6, 0, 0)
  Pose3 pose(Rot3(), Point3(-6.25, 0.10 , -1.0));
  Point3 point(0.0, 0.0, 0.0);

  // Use the factor to calculate the Jacobians
  Matrix H1Actual, H2Actual, H3Actual, H4Actual;
  factor.evaluateError(pose, body_P_sensor, point, *K1, H1Actual, H2Actual, H3Actual, H4Actual);

  // The expected Jacobians
  Matrix H1Expected = (Matrix(2, 6) << -92.376, 0., 577.350, 0., 92.376, 0., -9.2376, -577.350, 0., 0., 0., 92.376).finished();
  Matrix H3Expected = (Matrix(2, 3) << 0., -92.376, 0., 0., 0., -92.376).finished();

  // Verify the Jacobians are correct
  CHECK(assert_equal(H1Expected, H1Actual, 1e-3));
  CHECK(assert_equal(H3Expected, H3Actual, 1e-3));

  // Verify H2 and H4 with numerical derivatives
  Matrix H2Expected = numericalDerivative11<Vector, Pose3>(
      boost::bind(&TestProjectionFactor::evaluateError, &factor, pose, _1, point,
          *K1, boost::none, boost::none, boost::none, boost::none), body_P_sensor);

  Matrix H4Expected = numericalDerivative11<Vector, Cal3_S2>(
      boost::bind(&TestProjectionFactor::evaluateError, &factor, pose, body_P_sensor, point,
          _1, boost::none, boost::none, boost::none, boost::none), *K1);

  CHECK(assert_equal(H2Expected, H2Actual, 1e-5));
  CHECK(assert_equal(H4Expected, H4Actual, 1e-5));

}

/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
/* ************************************************************************* */


/******************************************************************************
 *
 * AMDiS - Adaptive multidimensional simulations
 *
 * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
 * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
 *
 * Authors:
 * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * This file is part of AMDiS
 *
 * See also license.opensource.txt in the distribution.
 *
 ******************************************************************************/

// Created by Roman Weissflog & Philipp Schulz

/** \file Bubble.h */

#ifndef AMDIS_BUBBLE_H
#define AMDIS_BUBBLE_H

#include <list>
#include <boost/numeric/mtl/mtl.hpp>
#include "AbstractFunction.h"
#include "BasisFunction.h"
#include "FixVec.h"

namespace AMDiS
{

  /** \ingroup FEMSpace
  * \brief
  * Lagrange basis functions plus Bubble function. Sub class of BasisFunction
  */

  class Bubble : public BasisFunction
  {
  public:
    /// Creator class used in the BasisFunctionCreatorMap.
    class Creator : public BasisFunctionCreator
    {
    public:
      virtual ~Creator() {}

      /// Returns a new Lagrange object.
      BasisFunction* create()
      {
        return getBubble(this->dim, this->dim + 1); // has to be generalized in later versions of bubble functions
      }
    };

  protected:
    /// Constructs lagrange/bubble basis functions with the given dim and degree.
    /// Constructor is protected to avoid multiple instantiation of identical
    /// basis functions. Use \ref getBubble instead.
    Bubble(int dim_, int degree_);

    /** \brief
    * destructor
    */
    virtual ~Bubble();

  public:
    /// Returns a pointer to lagrange and bubble basis functions with the given dim and
    /// degree. Multiple instantiation of identical basis functions is avoided
    /// by rembering once created basis functions in \ref allBasFcts.
    static Bubble* getBubble(int dim, int degree);

    /// Implements BasisFunction::interpol
    void interpol(const ElInfo*, int, const int*,
                  AbstractFunction<double, WorldVector<double>>*,
                  mtl::dense_vector<double>&) const override;

    /// Implements BasisFunction::interpol
    void interpol(const ElInfo*, int,
                  const int* b_no,
                  AbstractFunction<WorldVector<double>, WorldVector<double>>*,
                  mtl::dense_vector<WorldVector<double>>&) const override;

    /// Returns the barycentric coordinates of the i-th basis function.
    DimVec<double>* getCoords(int i) const override;

    /// Implements BasisFunction::getBound
    void getBound(const ElInfo*, BoundaryType*) const override;

    /** \brief
    * Calculates the local vertex indices which are involved in evaluating
    * the nodeIndex-th DOF at the positionIndex-th part of type position
    * (VERTEX/EDGE/FACE/CENTER). nodeIndex determines the permutation
    * of the involved vertices. So in 1d for lagrange4 there are two DOFs at
    * the CENTER (which is an edge in this case). Then vertices[0] = {0, 1} and
    * vertices[1] = {1, 0}. This allows to use the same local basis function
    * for all DOFs at the same position.
    */
    static void setVertices(int dim, int degree,
                            GeoIndex position, int positionIndex, int nodeIndex,
                            int** vertices);

    /// Implements BasisFunction::refineInter
    inline void refineInter(DOFIndexed<double>* drv, RCNeighbourList* list, int n) override
    {
      if (refineInter_fct)
        (*refineInter_fct)(drv, list, n, this);
    }

    /// Implements BasisFunction::coarseRestrict
    inline void coarseRestr(DOFIndexed<double>* drv, RCNeighbourList* list, int n) override
    {
      if (coarseRestr_fct)
        (*coarseRestr_fct)(drv, list, n, this);
    }

    /// Implements BasisFunction::coarseInter
    inline void coarseInter(DOFIndexed<double>* drv, RCNeighbourList* list, int n) override
    {
      if (coarseInter_fct)
        (*coarseInter_fct)(drv, list, n, this);
    }

    /// Implements BasisFunction::getLocalIndices().
    void getLocalIndices(const Element* el,
                         const DOFAdmin* admin,
                         std::vector<DegreeOfFreedom>& dofs) const override;

    /// Implements BasisFunction::getLocalDofPtrVec()
    /// Returns an vector filled with all DOFs per position
    void getLocalDofPtrVec(const Element* el,
                           const DOFAdmin* admin,
                           std::vector<const DegreeOfFreedom*>& vec) const override;

    /// Implements BasisFunction::l2ScpFctBas
    void l2ScpFctBas(Quadrature* q,
                     AbstractFunction<double, WorldVector<double>>* f,
                     DOFVector<double>* fh) override;

    /// Implements BasisFunction::l2ScpFctBas
    void l2ScpFctBas(Quadrature* q,
                     AbstractFunction<WorldVector<double>, WorldVector<double>>* f,
                     DOFVector<WorldVector<double>>* fh) override;

    static void clear();

    /// Implements BasisFunction::isnodal
    bool isNodal() const override
    {
      return false;
    }

  protected:
    /// sets the barycentric coordinates (stored in \ref bary) of the local
    /// basis functions.
    void setBary();

    /// Implements BasisFunction::setNDOF
    void setNDOF() override;

    /// Sets used function pointers
    void setFunctionPointer();

    /// Used by \ref getVec
    int* orderOfPositionIndices(const Element* el,
                                GeoIndex position,
                                int positionIndex) const override;

  private:
    /// barycentric coordinates of the locations of all basis functions
    std::vector<DimVec<double>*>* bary;

    /** \name static dim-degree-arrays
    * \{
    */
    static std::vector<DimVec<double>*> baryDimDegree;
    static DimVec<int>* ndofDimDegree;
    static int nBasFctsDimDegree;
    static std::vector<BasFctType*> phifunc;
    static std::vector<GrdBasFctType*> grdPhifunc;
    static std::vector<D2BasFctType*> D2Phifunc;
    /** \} */

    /// List of all used BasisFunctions in the whole program. Avoids duplicate
    /// instantiation of identical BasisFunctions.
    static Bubble* Singleton;

  protected:
    /// Pointer to the used refineInter function
    void (*refineInter_fct)(DOFIndexed<double>*, RCNeighbourList*, int, BasisFunction*);

    static void  refineInter2_1d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);
    static void  refineInter3_2d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);
    static void  refineInter4_3d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);

    /// Pointer to the used coarseRestr function
    void (*coarseRestr_fct)(DOFIndexed<double>*, RCNeighbourList*, int, BasisFunction*);

    static void  coarseRestr2_1d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);
    static void  coarseRestr3_2d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);
    static void  coarseRestr4_3d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);

    /// Pointer to the used coarseInter function
    void (*coarseInter_fct)(DOFIndexed<double>*, RCNeighbourList*, int, BasisFunction*);

    static void  coarseInter2_1d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);
    static void  coarseInter3_2d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);
    static void  coarseInter4_3d(DOFIndexed<double>*, RCNeighbourList*, int,
                                 BasisFunction*);

    /// AbstractFunction which implements lagrange/bubble basis functions
    class Phi : public BasFctType
    {
    public:
      /// Constructs the local lagrange/bubble basis function for the given position,
      /// positionIndex and nodeIndex. owner_ is a pointer to the Bubble
      /// object this basis function belongs to.
      Phi(Bubble* owner, GeoIndex position, int positionIndex, int nodeIndex);

      /// Destructor
      virtual ~Phi();

    private:
      /// vertices needed for evaluation of this function
      int* vertices;

      /// Pointer to the evaluating function
      double (*func)(const DimVec<double>& lambda, int* vert);

      /// Returns \ref func(lambda, vertices)
      inline double operator()(const DimVec<double>& lambda) const override
      {
        return func(lambda, vertices);
      }

      // ====== Lagrange, degree = 1 =====================================
      // vertex
      inline static double phi1v(const DimVec<double>& lambda, int* vertices)
      {
        return lambda[vertices[0]];
      }

      // ====== Bubble ===================================================
      // 1d
      inline static double phi2c(const DimVec<double>& lambda, int* vertices)
      {
        return (4.0 * lambda[vertices[0]] * lambda[vertices[1]]);
      }

      // 2d
      inline static double phi3c(const DimVec<double>& lambda, int* vertices)
      {
        return 27.0 * lambda[vertices[0]] * lambda[vertices[1]] * lambda[vertices[2]];
      }

      // 3d
      inline static double phi4c(const DimVec<double>& lambda, int* vertices)
      {
        return 256.0 * lambda[vertices[0]] * lambda[vertices[1]] *
               lambda[vertices[2]] * lambda[vertices[3]];
      }
    };

    /// AbstractFunction which implements gradients of Lagrange/Bubble basis functions.
    /// See \ref Phi
    class GrdPhi : public GrdBasFctType
    {
    public:
      GrdPhi(Bubble* owner, GeoIndex position, int positionIndex, int nodeIndex);

      virtual ~GrdPhi();
    private:
      int* vertices;

      void (*func)(const DimVec<double>& lambda,
                   int* vertices_,
                   mtl::dense_vector<double>& result);

      inline void operator()(const DimVec<double>& lambda,
                             mtl::dense_vector<double>& result) const override
      {
        func(lambda, vertices, result);
      }

      // ====== Lagrange1 ================================================
      // vertex
      inline static void grdPhi1v(const DimVec<double>&,
                                  int* vertices,
                                  mtl::dense_vector<double>& result)
      {
        result = 0.0;
        result[vertices[0]] = 1.0;
      }

      // ======= Bubble ==================================================
      inline static void grdPhi2c(const DimVec<double>& lambda,
                                  int* vertices,
                                  mtl::dense_vector<double>& result)
      {
        result = 0.0;
        result[vertices[0]] = 4.0 * lambda[vertices[1]];
        result[vertices[1]] = 4.0 * lambda[vertices[0]];
      }

      inline static void grdPhi3c(const DimVec<double>& lambda,
                                  int* vertices,
                                  mtl::dense_vector<double>& result)
      {
        result = 0.0;
        result[vertices[0]] = 27.0 * lambda[vertices[1]] * lambda[vertices[2]];
        result[vertices[1]] = 27.0 * lambda[vertices[0]] * lambda[vertices[2]];
        result[vertices[2]] = 27.0 * lambda[vertices[0]] * lambda[vertices[1]];
      }

      inline static void grdPhi4c(const DimVec<double>& lambda,
                                  int* vertices,
                                  mtl::dense_vector<double>& result)
      {
        result = 0.0;
        result[0] =
          256.0 * lambda[vertices[1]] * lambda[vertices[2]] * lambda[vertices[3]];
        result[1] =
          256.0 * lambda[vertices[0]] * lambda[vertices[2]] * lambda[vertices[3]];
        result[2] =
          256.0 * lambda[vertices[0]] * lambda[vertices[1]] * lambda[vertices[3]];
        result[3] =
          256.0 * lambda[vertices[0]] * lambda[vertices[1]] * lambda[vertices[2]];
      }
    };

    /// AbstractFunction which implements second derivatives of Lagrange/Bubble basis
    /// functions. See \ref Phi
    class D2Phi : public D2BasFctType
    {
    public:
      D2Phi(Bubble* owner, GeoIndex position, int positionIndex, int nodeIndex);

      virtual ~D2Phi();

    private:
      int* vertices;

      void (*func)(const DimVec<double>& lambda, int* vertices_, DimMat<double>& result);

      inline void operator()(const DimVec<double>& lambda, DimMat<double>& result) const override
      {
        return func(lambda, vertices, result);
      }

      // ===== Lagrange1 ================================================
      // vertex
      inline static void D2Phi1v(const DimVec<double>&, int*, DimMat<double>& result)
      {
        result.set(0.0);
      }

      // ===== Bubble ===================================================
      inline static void D2Phi2c(const DimVec<double>&, int* vertices,
                                 DimMat<double>& result)
      {
        result.set(0.0);
        result[vertices[0]][vertices[1]] = 4.0;
        result[vertices[1]][vertices[0]] = 4.0;
      }

      inline static void D2Phi3c(const DimVec<double>& lambda, int* vertices,
                                 DimMat<double>& result)
      {
        result.set(0.0);
        result[vertices[0]][vertices[1]] =
          result[vertices[1]][vertices[0]] = 27.0 * lambda[vertices[2]];
        result[vertices[0]][vertices[2]] =
          result[vertices[2]][vertices[0]] = 27.0 * lambda[vertices[1]];
        result[vertices[1]][vertices[2]] =
          result[vertices[2]][vertices[1]] = 27.0 * lambda[vertices[0]];
      }

      inline static void D2Phi4c(const DimVec<double>& lambda, int* vertices,
                                 DimMat<double>& result)
      {
        result.set(0.0);
        result[vertices[0]][vertices[1]] =
          result[vertices[1]][vertices[0]] =
            256.0 * lambda[vertices[2]] * lambda[vertices[3]];
        result[vertices[0]][vertices[2]] =
          result[vertices[2]][vertices[0]] =
            256.0 * lambda[vertices[1]] * lambda[vertices[3]];
        result[vertices[0]][vertices[3]] =
          result[vertices[3]][vertices[0]] =
            256.0 * lambda[vertices[1]] * lambda[vertices[2]];
        result[vertices[1]][vertices[2]] =
          result[vertices[2]][vertices[1]] =
            256.0 * lambda[vertices[0]] * lambda[vertices[3]];
        result[vertices[1]][vertices[3]] =
          result[vertices[3]][vertices[1]] =
            256.0 * lambda[vertices[0]] * lambda[vertices[2]];
        result[vertices[2]][vertices[3]] =
          result[vertices[3]][vertices[2]] =
            256.0 * lambda[vertices[0]] * lambda[vertices[1]];
      }
    };
  };
}

#endif // AMDIS_Bubble_H