#ifndef STAN_MATH_PRIM_PROB_SKEW_DOUBLE_EXPONENTIAL_RNG_HPP
#define STAN_MATH_PRIM_PROB_SKEW_DOUBLE_EXPONENTIAL_RNG_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/log1m.hpp>
#include <stan/math/prim/fun/max_size.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <cmath>

namespace stan {
namespace math {

/** \ingroup prob_dists
 * Return a skew double exponential random variate with the given location
 * scale and skewness using the specified random number generator.
 *
 * mu, sigma and tau can each be a scalar or a one-dimensional container. Any
 * non-scalar inputs must be the same size.
 *
 * @tparam T_loc Type of location parameter
 * @tparam T_scale Type of scale parameter
 * @tparam T_skewness Type of skewness parameter
 * @tparam RNG class of random number generator
 * @param mu (Sequence of) location parameter(s)
 * @param sigma (Sequence of) scale parameter(s)
 * @param tau (Sequence of) skewness parameter(s)
 * @param rng random number generator
 * @return (Sequence of) double exponential random variate(s)
 * @throw std::domain_error if mu is infinite or sigma is nonpositive or tau is
 *  not bound between 0.0 and 1.0
 * @throw std::invalid_argument if non-scalar arguments are of different
 * sizes
 */
template <typename T_loc, typename T_scale, typename T_skewness, class RNG>
inline typename VectorBuilder<true, double, T_loc, T_scale, T_skewness>::type
skew_double_exponential_rng(const T_loc& mu, const T_scale& sigma,
                            const T_skewness& tau, RNG& rng) {
  using boost::variate_generator;
  using boost::random::uniform_real_distribution;
  using T_mu_ref = ref_type_t<T_loc>;
  using T_sigma_ref = ref_type_t<T_scale>;
  using T_tau_ref = ref_type_t<T_skewness>;
  static const char* function = "skew_double_exponential_rng";
  check_consistent_sizes(function, "Location parameter", mu, "Scale Parameter",
                         sigma, "Skewness Parameter", tau);
  T_mu_ref mu_ref = mu;
  T_sigma_ref sigma_ref = sigma;
  T_tau_ref tau_ref = tau;
  check_finite(function, "Location parameter", mu_ref);
  check_positive_finite(function, "Scale parameter", sigma_ref);
  check_bounded(function, "Skewness parameter", tau_ref, 0.0, 1.0);

  scalar_seq_view<T_mu_ref> mu_vec(mu_ref);
  scalar_seq_view<T_sigma_ref> sigma_vec(sigma_ref);
  scalar_seq_view<T_tau_ref> tau_vec(tau_ref);
  size_t N = max_size(mu, sigma, tau);
  VectorBuilder<true, double, T_loc, T_scale, T_skewness> output(N);

  variate_generator<RNG&, uniform_real_distribution<> > z_rng(
      rng, uniform_real_distribution<>(0.0, 1.0));
  for (size_t n = 0; n < N; ++n) {
    double z = z_rng();
    if (z < tau_vec[n]) {
      output[n]
          = log(z / tau_vec[n]) * sigma_vec[n] / (2.0 * (1.0 - tau_vec[n]))
            + mu_vec[n];
    } else {
      output[n] = log((1.0 - z) / (1.0 - tau_vec[n])) * (-sigma_vec[n])
                      / (2.0 * tau_vec[n])
                  + mu_vec[n];
    }
  }

  return output.data();
}

}  // namespace math
}  // namespace stan
#endif


/*  _______________________________________________________________________

    DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
    Copyright 2014 Sandia Corporation.
    This software is distributed under the GNU Lesser General Public License.
    For more information, see the README file in the top Dakota directory.
    _______________________________________________________________________ */

//- Class:	 NonDGPImpSampling
//- Description: Implementation code for NonDGPImpSampling class
//- Owner:       Laura Swiler and Keith Dalbey
//- Checked by:
//- Version:

#include "NonDGPImpSampling.hpp"
#include "dakota_system_defs.hpp"
#include "dakota_data_types.hpp"
#include "dakota_data_io.hpp"
#include "DakotaModel.hpp"
#include "DakotaResponse.hpp"
#include "NonDLHSSampling.hpp"
#include "ProblemDescDB.hpp"
#include "DataFitSurrModel.hpp"
#include "pecos_data_types.hpp"
#include "pecos_stat_util.hpp"
#include "DakotaApproximation.hpp"
#include <boost/lexical_cast.hpp>

static const char rcsId[]="@(#) $Id: NonDGPImpSampling.cpp 7035 2010-10-22 21:45:39Z mseldre $";

namespace Dakota {

/** This constructor is called for a standard letter-envelope iterator
    instantiation.  In this case, set_db_list_nodes has been called and
    probDescDB can be queried for settings from the method specification. */
NonDGPImpSampling::NonDGPImpSampling(ProblemDescDB& problem_db, Model& model):
  NonDSampling(problem_db, model)
{
  // sampleType default in DataMethod.cpp is SUBMETHOD_DEFAULT (0).
  // Enforce an LHS default for this method.
  if (!sampleType)
    sampleType = SUBMETHOD_LHS;

  samplingVarsMode = ACTIVE_UNIFORM;
  String sample_reuse, approx_type("global_kriging");/*("global_kriging");*/
  UShortArray approx_order; // not used by GP/kriging
  short corr_order = -1, data_order = 1, corr_type = NO_CORRECTION;
  if (probDescDB.get_bool("method.derivative_usage")) {
    if (iteratedModel.gradient_type() != "none") data_order |= 2;
    if (iteratedModel.hessian_type()  != "none") data_order |= 4;
  }
  unsigned short sample_type = SUBMETHOD_DEFAULT;
  statsFlag = true; //print computed probability levels at end
  bool vary_pattern = false; // for consistency across outer loop invocations
  // get point samples file
  const String& import_pts_file
    = probDescDB.get_string("method.import_build_points_file");
  // BMA: This was previously using numSamples = initial_samples from base class
  numSamples = probDescDB.get_int("method.build_samples");
  int samples = numSamples;
  if (!import_pts_file.empty())
    { samples = 0; sample_reuse = "all"; }

  gpBuild.assign_rep(new NonDLHSSampling(iteratedModel, sample_type,
     samples, randomSeed, rngName, varyPattern, ACTIVE_UNIFORM), false);
  //distribution 1 which is the distribution that the initial set of samples
  //used to build the initial GP are drawn from this should "ALWAYS" be
  //uniform in the input of the GP (even if the nominal distribution is not
  //uniform) because it is a set of samples to build a good GP and nothing
  //else.  Rho 0 is the nonminal distribution of the input variable

  ActiveSet gp_set = iteratedModel.current_response().active_set(); // copy
  gp_set.request_values(1); // no surr deriv evals, but GP may be grad-enhanced
  gpModel.assign_rep(new DataFitSurrModel(gpBuild, iteratedModel,
    gp_set, approx_type, approx_order, corr_type, corr_order, data_order,
    outputLevel, sample_reuse, import_pts_file,
    probDescDB.get_ushort("method.import_build_format"),
    probDescDB.get_bool("method.import_build_active_only"),
    probDescDB.get_string("method.export_approx_points_file"),
    probDescDB.get_ushort("method.export_approx_format")), false);
  vary_pattern = true; // allow seed to run among multiple approx sample sets
  // need to add to input spec
  numEmulEval = probDescDB.get_int("method.nond.samples_on_emulator");
  if (numEmulEval==0)
    numEmulEval = 10000;
  construct_lhs(gpEval, gpModel, sample_type, numEmulEval, randomSeed,
		rngName, vary_pattern);
  if (maxIterations < 0)
    numPtsAdd = 150;
  else
    numPtsAdd = maxIterations;

  //construct sampler to generate one draw from rhoOne distribution, with
  //seed varying between invocations
  construct_lhs(sampleRhoOne, iteratedModel, sample_type, 1, randomSeed,
		rngName, vary_pattern);
}

NonDGPImpSampling::~NonDGPImpSampling()
{ }

bool NonDGPImpSampling::resize()
{
  bool parent_reinit_comms = NonDSampling::resize();

  Cerr << "\nError: Resizing is not yet supported in method "
       << method_enum_to_string(methodName) << "." << std::endl;
  abort_handler(METHOD_ERROR);

  return parent_reinit_comms;
}

void NonDGPImpSampling::derived_init_communicators(ParLevLIter pl_iter)
{
  iteratedModel.init_communicators(pl_iter, maxEvalConcurrency);

  // gpBuild and gpEval use NoDBBaseConstructor, so no need to
  // manage DB list nodes at this level
  //gpBuild.init_communicators(pl_iter);
  gpEval.init_communicators(pl_iter);
}

void NonDGPImpSampling::derived_set_communicators(ParLevLIter pl_iter)
{
  NonD::derived_set_communicators(pl_iter);

  // gpBuild and gpEval use NoDBBaseConstructor, so no need to
  // manage DB list nodes at this level
  //gpBuild.set_communicators(pl_iter);
  gpEval.set_communicators(pl_iter);
}

void NonDGPImpSampling::derived_free_communicators(ParLevLIter pl_iter)
{
  gpEval.free_communicators(pl_iter);
  //gpBuild.free_communicators(pl_iter);

  iteratedModel.free_communicators(pl_iter, maxEvalConcurrency);
}

/** Calculate the failure probabilities for specified probability levels
    using Gaussian process based importance sampling. */
void NonDGPImpSampling::core_run()
{
  numPtsTotal = numSamples + numPtsAdd;

  // Build initial GP model.  This will be built over the initial LHS sample set
  // defined in the constructor.
  gpModel.build_approximation();

  gpCvars.resize(numEmulEval);
  RealVector temp_cvars;
  gpVar.resize(numEmulEval);
  gpMeans.resize(numEmulEval);
  indicator.resize(numPtsTotal);
  expIndicator.resize(numEmulEval);
  rhoDraw.resize(numEmulEval);
  normConst.resize(numPtsAdd);
  rhoMix.resize(numPtsTotal);
  //RealVector rhoEmul0(numEmulEval);
  //RealVector rhoEmul2(numEmulEval);
  int num_problem_vars=iteratedModel.acv();
  RealVector c_upper = iteratedModel.continuous_upper_bounds(),
             c_lower = iteratedModel.continuous_lower_bounds();

  int i,j,k;

// This piece of code prints out the build points, not the approximation points.
// const Pecos::SurrogateData& gp_data = gpModel.approximation_data(0);
//  for (j = 0; j < numSamples; j++) {
//    Cout << " Surrogate Vars " << gp_data.continuous_variables(j) << '\n';
//    Cout << " Surrogate Response " << gp_data.response_function(j);
//  }

// We have built the initial GP.  Now we need to go through, per response function
// and response level and calculate the failure probability.
// We will need to add error handling:  we will only be calculating
// results per response level, not probability level or reliability index.

  size_t resp_fn_count, level_count, iter;
  RealVector new_X;
  initialize_level_mappings();
  ParLevLIter pl_iter = methodPCIter->mi_parallel_level_iterator(miPLIndex);

  for (resp_fn_count=0; resp_fn_count<numFunctions; resp_fn_count++) {
    size_t num_levels = requestedRespLevels[resp_fn_count].length();
    const Pecos::SurrogateData& gp_data = gpModel.approximation_data(resp_fn_count);
    for (level_count=0; level_count<num_levels; level_count++) {
      Cout << "Starting calculations for response function " << resp_fn_count+1 << '\n';
      Cout << "Starting calculations for level  " << level_count+1 << '\n';
      Cout << "Threshold level is " << requestedRespLevels[resp_fn_count][level_count] << '\n';
      Real z = requestedRespLevels[resp_fn_count][level_count];
       // Calculate indicator over the true function evaluations
      double cdfMult = (cdfFlag?1.0:-1.0);
      for (j = 0; j < numSamples; j++) {
        indicator(j) = static_cast<double>((z-gp_data.response_function(j))*cdfMult>0.0);
        if (outputLevel > NORMAL_OUTPUT)
          Cout << "indicator(" << j << ")=" << indicator(j) << '\n';
      }

      // rho0 is the original PDF, rho1 is the compon importance pdf, rho2 is the
      // distribution used to generate candidate points for the emulator
      // For the initial implementation, we assume rho1 is uniform, and
      // rho0 and rho2 are uniform also with the same distribution.
      double rho0const, rho1const, rho2const;
      rho0const = 1.0;
      for (i = 0; i < num_problem_vars; i++)
        rho0const = rho0const/(c_upper[i]-c_lower[i]);
      rho1const = rho0const;
      rho2const = rho0const;

       // Here we loop over the number of points added,
       // where each time we calculate the expected indicator function
       // and add to the approximation.
      for (k = 0; k < numPtsAdd; k++) {
	// generate new set of emulator samples.
	// Note this will have a different seed each time.
        gpEval.run(pl_iter);
         // obtain results
        const RealMatrix&  all_samples = gpEval.all_samples();
        const IntResponseMap& all_resp = gpEval.all_responses();
        for (i = 0; i< numEmulEval; i++) {
          temp_cvars = Teuchos::getCol(Teuchos::View,
	    const_cast<RealMatrix&>(all_samples), i);
          gpCvars[i] = temp_cvars;
          //Cout << "input is " << gpCvars[i] << '\n';
	  // update gpModel currentVariables for use in approx_variances()
	  gpModel.continuous_variables(temp_cvars);
          gpVar[i]
	    = gpModel.approximation_variances(gpModel.current_variables());
          //Cout << "variance is " << gpVar[i];
        }

        IntRespMCIter resp_it = all_resp.begin();
        for (j=0, resp_it=all_resp.begin(); j<numEmulEval; ++j, ++resp_it) {
          RealVector temp_resp(numFunctions);
            for (i=0; i<numFunctions; i++)
              temp_resp(i) = resp_it->second.function_value(i);
            gpMeans[j]=temp_resp;
            //Cout << "output is " << gpMeans[j] << '\n';
        }

       // calculate expected indicator function;
        expIndicator = calcExpIndicator(resp_fn_count,z);
       // calculate distribution pdfs required to calculate the draw distribution
       // distribution_pdf(rhoEmul2);
       // distribution_pdf(rhoEmul0);
       // FOR NOW, we assume distribution 0 and 2 are the same,
       // but in general rhoDrawThis = expIndicator * rhoEmul0/rhoEmul2;
        for (i = 0; i< numEmulEval; i++)
          rhoDraw(i) = expIndicator(i)*rho0const/rho2const;

       // calculate the normalization constant
        Cout << "numEmulEval " << numEmulEval << '\n';
        Cout << "size exp indicator " << expIndicator.length() << '\n';
	double temp_sum_nc=0.0;
        normConst(k)=0.0;
        for (j = 0; j < numEmulEval; j++) {
	  temp_sum_nc+=rhoDraw(j);
        }
	temp_sum_nc/=numEmulEval;
        normConst(k)=temp_sum_nc;
        Real temp_norm_const = normConst(k);
        Cout << "norm const " << k << "=" << temp_sum_nc << "=" << normConst(k) <<  "\n";
       // calculate the draw distribution
        rhoDrawThis.resize(0);
        xDrawThis.resize(0);
        expIndThis.resize(0);
        calcRhoDraw();

        iter = 1;
        while ((iter<20) && (temp_norm_const*numEmulEval<25)) {
	  iter = iter+1;
          gpEval.run(pl_iter);
           // obtain results
          const RealMatrix&  this_samples = gpEval.all_samples();
          const IntResponseMap& this_resp = gpEval.all_responses();
          for (i = 0; i< numEmulEval; i++) {
	    temp_cvars = Teuchos::getCol(Teuchos::View,
	       const_cast<RealMatrix&>(this_samples), i);
            gpCvars[i] = temp_cvars;
            //Cout << "input is " << gpCvars[i] << '\n';
	    // update gpModel currentVariables for use in approx_variances()
	    gpModel.continuous_variables(temp_cvars);
            gpVar[i]
	      = gpModel.approximation_variances(gpModel.current_variables());
            //Cout << "variance is " << gpVar[i];
           }

          resp_it = this_resp.begin();
          for (j=0, resp_it=this_resp.begin(); j<numEmulEval; ++j, ++resp_it) {
            RealVector temp_resp(numFunctions);
            for (i=0; i<numFunctions; i++)
              temp_resp(i) = resp_it->second.function_value(i);
            gpMeans[j]=temp_resp;
            //Cout << "output is " << gpMeans[j] << '\n';
          }

       // calculate expected indicator function;
          expIndicator = calcExpIndicator(resp_fn_count,z);
          for (j = 0; j < numEmulEval; j++)
            rhoDraw(j)=expIndicator(j)*rho0const/rho2const;
          Real temp_norm_this=0.0;
          for (j = 0; j < numEmulEval; j++)
	    temp_norm_this+=rhoDraw(j);
          temp_norm_this/=numEmulEval;
          temp_norm_const = temp_norm_const+temp_norm_this;
          calcRhoDraw();
        }

       // xDrawThis, rhoDrawThis, and expIndThis should be populated now
        normConst(k)=temp_norm_const/iter;
        if (outputLevel > NORMAL_OUTPUT)
          Cout << "NormConst " << k << " =  " << normConst(k) << '\n';

        int num_eval_kept = xDrawThis.size();
        Real est_prob_hit_failregion;

        if (num_eval_kept==0) {
	  normConst(k)=0.0;
          sampleRhoOne.run(pl_iter);
         // obtain results
          const RealMatrix&  rho1_samples = sampleRhoOne.all_samples();
          // For now, we always only draw one sample
            new_X = Teuchos::getCol(Teuchos::View,
	      const_cast<RealMatrix&>(rho1_samples), 0);
            Cout << "Draw from Rho One is " << new_X << '\n';
        }
        else
          new_X = drawNewX(k);

         // add new_X to the build points and append approximation
        iteratedModel.continuous_variables(new_X);
        iteratedModel.evaluate();
        IntResponsePair resp_truth(iteratedModel.evaluation_id(),
                                   iteratedModel.current_response());
        gpModel.append_approximation(iteratedModel.current_variables(), resp_truth, true);
	indicator(numSamples+k) = static_cast<double>((z-gp_data.response_function(numSamples+k))*cdfMult>0.0);
        //if (gp_data.response_function(numSamples+k-1)<z)
	//indicator(numSamples+k-1)=1;
        //else indicator(numSamples+k-1)=0;
        Cout << "Done with iteration k ";
      }
      RealVectorArray gp_final_data(numPtsTotal);
      for (j = 0; j < numPtsTotal; j++)
        gp_final_data[j]=gp_data.continuous_variables(j);
      Cout << "GP final data size " <<  gp_final_data.size() << '\n';
//
//This is where we need some re-architecting.  I want to evaluate the GPmodel at a
//set of pre-defined points.  We will need to use a parameter list study.
//something like the following
//Iterator listStudy;
//The list of points will be the full X data, consisting of the original plus added points
//We have this stored in the Surrogate data
//VariablesArray list_points;
//list_points.resize(numPtsTotal);
//for (j = 0; j < numSamples; j++) {
//    list_points[j]=gp_data.continuous_variables(j);
//}
//
//listStudy.assign_rep(new ParamStudy(gpModel,"LIST", list_points));
//
      rhoOne.resize(numPtsTotal);
//not sure if I have this correct
//for now, since we are assuming rho0=rho1=rho2=all uniform, just set rho1 to 1.
      for (j = 0; j < numPtsTotal; j++)
        rhoOne(j)=rho1const; //for uniform this should be 1.0/prod(xmax-xmin) across all dimensions... ok now I see this isn't rhoOne it's rhoOne/rhoZero... if rho0=rho1=rho2 this should be ok

      for (j = 0; j < numPtsTotal; j++)
        rhoMix(j)=rhoOne(j)*numSamples;

      for (j = numPtsAdd-1; j>=0; j--){
        if (normConst(j)==0.0) {
          for (k = 0; k < numPtsTotal; k++)
            rhoMix(k)=rhoMix(k)+rhoOne(k);
        }
        else {
          RealVector this_mean;
          RealVector this_var;
          RealVector exp_ind_this(numPtsTotal);
          for (k = 0; k < numPtsTotal; k++){
            gpModel.continuous_variables(gp_final_data[k]);
            gpModel.evaluate();
            this_mean = gpModel.current_response().function_values();
            this_var
	      = gpModel.approximation_variances(gpModel.current_variables());
            exp_ind_this(k) = calcExpIndPoint(resp_fn_count,z,this_mean,this_var);
            if (outputLevel > NORMAL_OUTPUT)
              Cout << "exp_ind_final " << k << " " <<  exp_ind_this(k) << '\n';
          }
          for (k = 0; k < numPtsTotal; k++)
            rhoMix(k)=rhoMix(k)+exp_ind_this(k)*rho0const/normConst(j);
	  //the 1.0 here is reall rhoZero/rhoZero (ok for rho0=rho1=rho2)
          gpModel.pop_approximation(false, true);
          //gpModel.update_approximation(true);
          Cout << "Size of build data set " << gp_data.points() << '\n';
        }
//Since we need to evaluate the SUCCESSIVE SEQUENCES of GPs built using numSamples-->numPtsTotal
//it might be most efficient to "pop" the data and go backward:
//listStudy.run(pl_iter);
//obtain results and expected indicator functions
//gpModel.pop_approximation();
//
      }
      if (outputLevel > NORMAL_OUTPUT) {
        Cout << "rhoMix " << rhoMix << '\n';
        Cout << "indicator " << indicator << '\n';
      }
      for (j = 0; j < numPtsTotal; j++) {
	Real yada=rhoMix(j);
        rhoMix(j)=yada/numPtsTotal;
      }
      Real prob_mix=0.0;
      for (j = 0; j < numPtsTotal; j++)
        prob_mix+=rho0const*indicator(j)/rhoMix(j);
      //the 1.0 here is reall rhoZero/rhoZero (ok for rho0=rho1=rho2)
      prob_mix/=numPtsTotal;
      Cout << "Prob Mix IS " << prob_mix << '\n';

      Real fract_fail_mix = 0.0;
      for (j = 0; j < numPtsTotal; j++)
        fract_fail_mix+=indicator(j);
      fract_fail_mix/=numPtsTotal;
      Cout << "Fraction Fail IS " << fract_fail_mix << '\n';
      finalProb = prob_mix;
      computedProbLevels[resp_fn_count][level_count]=finalProb;
    }
  }
}

RealVector NonDGPImpSampling::drawNewX(int this_k)
{
  int i,j,templength;
  templength = xDrawThis.size();
  RealVector binEnds;
  binEnds.size(templength);
  Real cum_sum = 0.;
  Real est_prob_hit_failregion = 0;
  Real yada2;
  //Cout << "templength " << templength << '\n';
  for (i=0; i<templength; i++) {
    Real yada=rhoDrawThis(i);
    rhoDrawThis(i)=yada/normConst(this_k);
    if (i==0)
      binEnds(i)=rhoDrawThis(i);
    else{
      yada=rhoDrawThis(i);
      yada2=binEnds(i-1);
      binEnds(i)=yada+yada2;
    }
  }
  cum_sum = binEnds(templength-1);
  //Cout << "Cum Sum"  << cum_sum << '\n';
  //Cout << "BinEnds " << binEnds << '\n';
  //Cout << "RhoDrawThis " << rhoDrawThis << '\n';
  for (i=0; i<templength; i++) {
    yada2=binEnds(i);
    binEnds(i)=yada2/cum_sum;
  }
  //std::srand(randomSeed);
  double rand_cdf = (double)std::rand()/RAND_MAX;
  //Cout << "randcdf " << rand_cdf << '\n';
  bool found_cdf=false;
  i=0;
  while ((i<templength) && !found_cdf) {
    if (binEnds(i) > rand_cdf)
      found_cdf = true;
    else
      i = i+1;
  }
  for (j=0; j<templength; j++) {
    est_prob_hit_failregion+=expIndThis(j)*rhoDrawThis(j)/cum_sum;
  }
  Cout << "Estimated prob of hitting failure region " << est_prob_hit_failregion << '\n';
  return xDrawThis[i];
}

void NonDGPImpSampling::calcRhoDraw()
{
  int i, templength;
  templength = xDrawThis.size();

  for (i = 0; i<numEmulEval; i++) {
    if (expIndicator(i)!=0.0) {
      xDrawThis.resize(templength+1);
      expIndThis.resize(templength+1);
      rhoDrawThis.resize(templength+1);
      xDrawThis[templength]=gpCvars[i];
      expIndThis(templength)=expIndicator(i);
      // for now this is OK because rho0const = rho2const, will need to change this
      rhoDrawThis(templength)=expIndicator(i);
      templength=templength+1;
    }
  }

  //for (i = 0; i< templength; i++) {
  //  Cout << "xDrawThis  " << i << xDrawThis[i] << '\n';
  //  Cout << "rhoDrawThis  "  << rhoDrawThis[i] << '\n';
  //}
}

RealVector NonDGPImpSampling::calcExpIndicator(const int resp_fn_count, const Real respThresh)
{
  int i, j;
  RealVector ei(numEmulEval);

  Real cdf,snv,stdv;
  for (i = 0; i< numEmulEval; i++) {
    //Cout << "GPmean  " << gpMeans[i][resp_fn_count];
    //Cout << "GPvar  " << gpVar[i][resp_fn_count];
    snv = (respThresh-gpMeans[i][resp_fn_count])*(cdfFlag?1.0:-1.0);
    //this conditional sign maps the problem to the case where the mean being
    //"below" the threshold (i.e. snv > 0) indicates "mostly failure" and the
    //mean being "above" the threshold (i.e. snv < 0) indicates "mostly not
    //failure" this allows the mapped problem to ALWAYS use the cdf (instead
    //of complimentary cdf)

    stdv = std::sqrt(gpVar[i][resp_fn_count]);
    if(std::fabs(snv)>=std::fabs(stdv)*50.0) {
      //this will trap the denominator=0.0 case even if numerator=0.0
      ei(i)=(snv>=0.0)?1.0:0.0;
      //the mean being exactly at the threshold when variance=0.0 is
      //considered to indicate failure
    }
    else{
      snv/=stdv;
      ei(i)= Pecos::NormalRandomVariable::std_cdf(snv);
      //the expected indicator is the fraction of the mapped problem's cdf
      //that fails, the simple mapping is at most a change in sign of the
      //snv and might be the identity mapping (not even a change in sign)
    }

    //Cout << "EI " << ei(i) << " respThresh= " << respThresh << " mu= " << gpMeans[i][resp_fn_count] << " stdv= " << stdv << '\n';
  }
  return ei;
}

Real NonDGPImpSampling::calcExpIndPoint(const int resp_fn_count, const Real respThresh, const RealVector this_mean, const RealVector this_var)
{
  int i, j;
  Real ei;

  Real cdf,snv,stdv;
  //  Cout << "GPmean  " << this_mean(resp_fn_count);
  //  Cout << "GPvar  " << this_var(resp_fn_count);
  snv = (respThresh-this_mean(resp_fn_count))*(cdfFlag?1.0:-1.0);
    //this conditional sign maps the problem to the case where the mean being
    //"below" the threshold (i.e. snv > 0) indicates "mostly failure" and the
    //mean being "above" the threshold (i.e. snv < 0) indicates "mostly not
    //failure" this allows the mapped problem to ALWAYS use the cdf (instead
    //of complimentary cdf)
  stdv = std::sqrt(this_var(resp_fn_count));
  if(std::fabs(snv)>=std::fabs(stdv)*50.0) {
    //this will trap the denominator=0.0 case even if numerator=0.0
    ei=(snv>=0.0)?1.0:0.0;
    //the mean being exactly at the threshold when variance=0.0 is
    //considered to indicate failure
  }
  else{
    snv/=stdv;
    ei= Pecos::NormalRandomVariable::std_cdf(snv);
    //the expected indicator is the fraction of the mapped problem's cdf
    //that fails, the simple mapping is at most a change in sign of the
    //snv and might be the identity mapping (not even a change in sign)
  }

  //Cout << "EI " << ei << " respThresh= " << respThresh << " mu= " << this_mean(resp_fn_count) << " stdv= " << stdv << '\n';

  return ei;
}

void NonDGPImpSampling::print_results(std::ostream& s, short results_state)
{
  if (statsFlag) {
    s << "\nStatistics based on the importance sampling calculations:\n";
    print_level_mappings(s);
  }
}

} // namespace Dakota


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef NT2_LINALG_FUNCTIONS_GALLERY_ORTHOG_HPP_INCLUDED
#define NT2_LINALG_FUNCTIONS_GALLERY_ORTHOG_HPP_INCLUDED
#include <nt2/linalg/functions/orthog.hpp>
#include <nt2/include/functions/whereij.hpp>
#include <nt2/include/functions/sin.hpp>
#include <nt2/include/functions/cos.hpp>
#include <nt2/include/functions/sinpi.hpp>
#include <nt2/include/functions/cospi.hpp>
#include <nt2/include/functions/ric.hpp>
#include <nt2/include/functions/cic.hpp>
#include <nt2/include/functions/cif.hpp>
#include <nt2/include/functions/rif.hpp>
#include <nt2/include/functions/tril.hpp>
#include <nt2/include/functions/from_diag.hpp>
#include <nt2/include/functions/ones.hpp>
#include <nt2/include/functions/eye.hpp>
#include <nt2/include/functions/rec.hpp>
#include <nt2/include/functions/max.hpp>
#include <nt2/include/functions/sqrt.hpp>
#include <nt2/include/constants/two.hpp>
#include <nt2/include/constants/pi.hpp>
#include <nt2/include/constants/half.hpp>
#include <nt2/include/constants/twopi.hpp>
#include <nt2/include/functions/multiplies.hpp>
#include <nt2/include/functions/mul_i.hpp>
#include <nt2/include/functions/exp.hpp>
#include <nt2/include/functions/divides.hpp>
#include <nt2/include/functions/is_eqz.hpp>
#include <nt2/include/functions/is_nez.hpp>
#include <nt2/include/functions/oneminus.hpp>
#include <nt2/include/functions/sqrt.hpp>
#include <nt2/include/functions/horzcat.hpp>
#include <nt2/include/functions/mtimes.hpp>
#include <nt2/include/functions/logical_and.hpp>
#include <boost/mpl/int.hpp>
#include <boost/simd/include/functor.hpp>
#include <boost/dispatch/include/functor.hpp>

namespace nt2
{
  namespace details
  {
    struct isij0
    {
      template < class I, class J> inline
      typename meta::as_logical<I>::type operator()(const I & i , const J& j) const
      {
        return nt2::is_eqz(i*j);
      }
    };
    struct isi0
    {
      template < class I, class J> inline
      typename meta::as_logical<I>::type operator()(const I & i , const J& ) const
      {
        return nt2::is_eqz(i);
      }
    };
    struct isdiagpos
    {
      template < class I, class J> inline
      typename meta::as_logical<I>::type operator()(const I & i , const J& j ) const
      {
        return nt2::logical_and(nt2::is_nez(i), nt2::eq(i, j));
      }
    };
    template < class A0, class K, class T > struct orthog_return{};
  }
#define NT2_ORTHOG(V, K, Body)                                      \
  namespace ext                                                     \
  {                                                                 \
    NT2_FUNCTOR_IMPLEMENTATION( nt2::tag::orthog##K##_, tag::cpu_,  \
                                (A0)(T),                            \
                                (scalar_<integer_<A0> >)            \
                                (target_<scalar_<floating_<T> > > ) \
                              )                                     \
    {                                                               \
      typedef typename T::type t_t;                                 \
      BOOST_DISPATCH_RETURNS(2, (A0 const& n,  T const& t),         \
                             Body                                   \
                            )                                       \
        };                                                          \
  }                                                                 \
  namespace details                                                 \
  {                                                                 \
    template < class A0, class T >                                  \
    struct orthog_return < A0,  boost::mpl::int_<V>, T>             \
      {                                                             \
        typedef typename nt2::meta::as_<T> Target;                  \
        typedef typename nt2::meta::call<nt2::tag::orthog##K##_(A0, \
                                               Target)>::type type; \
      };                                                            \
   }                                                                \
  template<class T>                                                 \
  typename details::orthog_return<ptrdiff_t,                        \
                                  boost::mpl::int_<V>, T>::type     \
                    orthog(ptrdiff_t n, const boost::mpl::int_<V>&) \
  {                                                                 \
    return nt2::orthog##K(n, meta::as_<T>());                       \
  }                                                                 \
/**/

  NT2_ORTHOG(1, 1, (nt2::sinpi(nt2::rif(n,T())*nt2::cif(n,T())/t_t(n+1))*nt2::sqrt(Two<t_t>()/t_t(n+1))))
  NT2_ORTHOG(2, 2, (nt2::sinpi(nt2::rif(n,T())*nt2::cif(n,T())*nt2::Two<t_t>()/t_t(2*n+1))*(Two<t_t>()/nt2::sqrt(t_t(2*n+1)))))
  NT2_ORTHOG(3, 3, (nt2::exp(nt2::mul_i(nt2::ric(n,T())*nt2::cic(n,T())*nt2::Twopi<t_t>()/t_t(n)))/nt2::sqrt(t_t(n))))
  NT2_ORTHOG(4, 4, (nt2::mtimes(nt2::from_diag(nt2::rec(nt2::sqrt(nt2::cath(t_t(n), _(t_t(1), t_t(n-1)))*_(t_t(1), t_t(n))))),
                                nt2::whereij(details::isdiagpos(),
                                             nt2::from_diag(nt2::oneminus(nt2::_(t_t(1), t_t(n)))),
                                             nt2::whereij(details::isi0(),
                                                          nt2::ones(n, T()),
                                                          nt2::tril(nt2::ones(n, T()))
                                                         )
                                            )
                               )
                   )
            )
  NT2_ORTHOG(5, 5,((nt2::cospi(nt2::ric(n,T())*nt2::cic(n,T())*nt2::Two<t_t>()/t_t(n))+
                    nt2::sinpi(nt2::ric(n,T())*nt2::cic(n,T())*nt2::Two<t_t>()/t_t(n)))/nt2::sqrt(t_t(n))))
  NT2_ORTHOG(6, 6, (nt2::cospi((nt2::rif(n, T())-Half<t_t>())*(nt2::cif(n, T())-Half<t_t>())/t_t(n))*nt2::sqrt(nt2::Two<t_t>()/t_t(n))))
  NT2_ORTHOG(7, 7, (nt2::whereij(details::isij0(), nt2::ones(n,T())/nt2::sqrt(t_t(n)),nt2::eye(n,T())-ones(n,T())*(1+rec(sqrt(t_t(n))))/t_t(n-1))))
  NT2_ORTHOG(-1, m1, (nt2::cospi(nt2::ric(n,T())*nt2::cic(n,T())*nt2::rec(nt2::max(t_t(1), t_t(n-1))))))
  NT2_ORTHOG(-2, m2, (nt2::cospi(nt2::ric(n,T())*(nt2::cic(n,T())+nt2::Half<t_t>())*nt2::rec(t_t(n)))))

#undef ORTHOG

  template<int K, class T>
  typename details::orthog_return<ptrdiff_t,  boost::mpl::int_<K>, T>::type
  orthog(ptrdiff_t n)
  {
    return nt2::orthog<T>(n, boost::mpl::int_<K>());
  }

}

#endif


/// @file  cmdet.hpp
/// @brief Declarations for methods based on Cayley-Menger determinants.

#pragma once
#ifndef OGT_EMBED_CMDET_HPP
#define OGT_EMBED_CMDET_HPP

#include <ogt/config.hpp>
#include <Eigen/Dense>
#include <memory>

namespace OGT_NAMESPACE {
namespace embed {

/// Captures a set of Cayley-Menger reference vertices which can be used to find
/// pairwise distances between points, or to embed the set.
///
/// This method is based on:
/// [1]	M. J. Sippl and H. A. Scheraga, "Cayley-Menger coordinates.,"
///     Proceedings of the National Academy of Sciences, Apr. 1986.
struct CMReference {

	/// Construct a concrete instance, given all pairwise squared Euclidean
	/// distances between the reference vertices.
	static std::shared_ptr<CMReference> Create(Eigen::MatrixXd refSqDists);

	/// Virtual destructor.
	virtual ~CMReference() = default;

	/// Find the squared Euclidean distance between two points with the given
	/// squared Euclidean distances to the reference vertices.
	virtual double sqDist(Eigen::VectorXd v1, Eigen::VectorXd v2) = 0;
};

} // end namespace embed
} // end namespace OGT_NAMESPACE
#endif /* OGT_EMBED_CMDET_HPP */


/*
Copyright 2020 Dennis Rohde

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once

#include <boost/python.hpp>
#include <boost/python/numpy.hpp>

#include "types.hpp"
#include "clustering.hpp"
#include "frechet.hpp"

namespace np = boost::python::numpy;
namespace p = boost::python;

namespace Coreset {

class Onemedian_Coreset {

    std::vector<curve_number_t> coreset;
    std::vector<distance_t> lambda;
    const distance_t Lambda = 76;
    distance_t cost;

public:
    Onemedian_Coreset() {}

    inline Onemedian_Coreset(const curve_size_t ell, const Curves &in, const distance_t epsilon, const double constant = 1) {
        compute(ell, in, epsilon, constant);
    }

    inline void compute(const curve_size_t ell, const Curves &in, const distance_t epsilon, const double eps, const bool round = true, const double constant = 1) {
        const auto n = in.size();
        const auto m = in.get_m();
        auto distances = Clustering::Distance_Matrix(in.size(), in.size());
        const auto c_approx = Clustering::arya(1, ell, in, distances, false);
        const auto center = c_approx.centers[0];
        cost = c_approx.value;
        if (cost == 0) {
            std::cerr << "WARNING: cost is zero, coreset construction not possible - check your input" << std::endl;
            return;
        }
        std::vector<double> probabilities(n);
        lambda = std::vector<distance_t>(n);

        for (curve_number_t i = 0; i < n; ++i) {
            lambda[i] = 52.0 / n + 24.0 / cost * Frechet::Continuous::distance(in[i], center).value;
            probabilities[i] = (lambda[i]) / Lambda;
        }

        auto prob_gen = Random::Custom_Probability_Generator<double>(probabilities);
        const std::size_t ssize = std::ceil(constant * 1/epsilon * 1/epsilon * std::log(m));
        const auto coreset_ind = prob_gen.get(ssize);
        for (curve_number_t i = 0; i < ssize; ++i) {
            coreset.push_back(coreset_ind[i]);
        }
    }

    inline np::ndarray get_lambda() const {
        np::dtype dt = np::dtype::get_builtin<distance_t>();
        p::list l;
        np::ndarray result = np::array(l, dt);
        for (const auto &elem: lambda) {
            l.append(elem);
        }
        result = np::array(l, dt);
        return result;
    }

    inline distance_t get_Lambda() const {
        return Lambda;
    }

    inline np::ndarray get_curves() const {
        np::dtype dt = np::dtype::get_builtin<curve_number_t>();
        p::list l;
        np::ndarray result = np::array(l, dt);
        for (const auto &elem: coreset) {
            l.append(elem);
        }
        result = np::array(l, dt);
        return result;
    }

    inline distance_t get_cost() const {
        return cost;
    }

};

};


//#include <Rcpp.h>
//#include <armadillo>
#include <RcppArmadillo.h>
#include <Rmath.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include <R_ext/Utils.h>
#include "MIMOSA.h"
//#define DEBUG2
//#define NDEBUG
/*
 * 18 parameters
 */
 // [[register]]
RcppExport SEXP fitMCMC(SEXP _stim, SEXP _unstim, SEXP _alphas, SEXP _alphau, SEXP _q, SEXP _z,SEXP _iter, SEXP _burn, SEXP _thin, SEXP _tune,SEXP _outfile, SEXP _filter, SEXP _upper, SEXP _lower, SEXP _bfilter, SEXP _fast, SEXP _exprate, SEXP _pXi){
	BEGIN_RCPP
	ntune=0;
	//TODO add argument to pass the complete list of unstimulated samples.
	using namespace Rcpp;
	using namespace arma;
	using namespace std;
	bool fixed = false;

	RNGScope globalscope;
	//			printf("%f %f %f %f\n",exp(normconstIBeta(15,3000,30,3000)),(normconstMC(30,3000,15,3000)),(exp(normconstIBeta(3000,30,3000,15))),(normconstMC(3000,15,3000,30)));
	//			exit(0);
	/*
	 * Copy R variables to standard vectors
	 */
	Rcpp::LogicalVector rfilter(_filter);
	std::vector<bool> filter(rfilter.length(),0);
	filter.resize(rfilter.length());
	copy(rfilter.begin(),rfilter.end(),filter.begin());

	FILTER = Rcpp::as<bool> (_bfilter);
	FAST = Rcpp::as<bool> (_fast);
	double UPPER = Rcpp::as<double>(_upper);
	double LOWER = Rcpp::as<double>(_lower);
	bool REJECT = false;
	EXPRATE = Rcpp::as<double>(_exprate);
	//printf("exponential prior rate = %f\n",EXPRATE);

	std::vector< double > alphas = Rcpp::as<std::vector<double> >(_alphas);
	std::vector< double > alphau = Rcpp::as<std::vector<double> 	>(_alphau);
	double q = Rcpp::as<double>(_q);

	std::vector< double > z = Rcpp::as<vector <double> >(_z);
	std::vector< double > stdstim = Rcpp::as < vector < double > > (_stim);
	std::vector< double > stdunstim = Rcpp::as < vector < double > > (_unstim);
  //double pXi = Rcpp::as<double>(_pXi);
  NumericVector pXi(_pXi);
	/*
	 * Wrap R variables in Rcpp objects
	 */
	Rcpp::NumericMatrix const stim(_stim);
	Rcpp::NumericMatrix const unstim(_unstim);
	Rcpp::NumericVector const iter(_iter);
	Rcpp::NumericVector const burn(_burn);
	Rcpp::NumericVector const thin(_thin);
	Rcpp::NumericVector const tune(_tune);

	std::string outfile = Rcpp::as<std::string>(_outfile);

	std::string outfilep(outfile.data());
	outfilep.append("P");

	Rprintf("Creating %s\n",outfile.data());

	FILE* file = fopen(outfile.data(),"w");
	FILE* fileP = fopen(outfilep.data(),"w");
	if(file==NULL|fileP==NULL){
		return(wrap("Can't open file!"));
	}
	/*
	 * Parameters
	 */
	const double NITERS=iter[0];
	const double BURNIN=burn[0];
	const double THINNING=thin[0];
	const double TUNING=tune[0];
	double realitcounter=0;

	/*
	 * Assert that dimensions match
	 */
	if(alphas.size()!=stim.ncol()){
     ::Rf_error( "dimensions don't match");
	}
	if(stim.nrow()!=unstim.nrow()){
     ::Rf_error( "dimensions don't match");
	}
	if(stim.ncol()!=unstim.ncol()){
     ::Rf_error( "dimensions don't match");
	}
	if(alphas.size()!=alphau.size()){
     ::Rf_error( "dimensions don't match");
	}
	/*
	 * Dimensions of the problem
	 */
	const int k = stim.ncol();
	const int P = stim.nrow();

	/*
	 * Output variables
	 */
	std::vector<double> ps(P,0),pu(P,0);
	std::vector <double> llnull(P,0);
	std::vector <double> llresp(P,0);
	std::vector <double> llnullNew(P,0);
	std::vector <double> llrespNew(P,0);

	std::vector <double> stdsum_data_alphas(P*k,0);
	std::vector <double> stdsum_data_alphau(P*k,0);

	arma::vec asi, aui;
	/*
	 * Armadillo objects will store the simulations from the tuning phase
	 * so we can easily compute variances and so forth.
	 */
	arma::mat Ms(int(TUNING),alphas.size());
#ifdef DEBUG2
	Rprintf("init Ms\n");
#endif
	arma::mat Mu(int(TUNING),alphau.size());
#ifdef DEBUG2
	Rprintf("init Mu\n");
#endif

	/*
	 * Precompute and preallocate a few things we'll need
	 */
	std::vector <double> sum_stim_unstim(P*k,0);
	std::transform(stdstim.begin(),stdstim.end(),stdunstim.begin(),sum_stim_unstim.begin(),plus<double>());

	std::vector<double> newalphas(alphas.size(),0);
	newalphas.resize(alphas.size());
	std::vector<double> newalphau(alphau.size(),0);
	newalphau.resize(alphau.size());

	NumericVector sigmas(alphas.size(),10.0);
	NumericVector sigmau(alphau.size(),10.0);

	arma::vec rateS(alphas.size());
#ifdef DEBUG2
	Rprintf("init rateS\n");
#endif
	arma::vec rateU(alphau.size());
#ifdef DEBUG2
	Rprintf("init rateU\n");
#endif
	rateS.fill(RATE);
	rateU.fill(RATE);
	NumericVector accepts(alphas.size(),0.0);
	NumericVector acceptu(alphas.size(),0.0);
	std::vector<double> cll(P,0.0);
	std::vector<double> p(P,0.0);
	std::vector<double> cz(P,0.0);
	std::vector<double> prr(NITERS-BURNIN,0.0);

	double prior=0,newprior=0;
	double oldll=0,newll=0;

	/*
	 * Construct the header string
	 *
	 */
	std::stringstream headers(stringstream::in|stringstream::out);
	std::stringstream headersP(stringstream::in|stringstream::out);

	//write the z's and p's to the second file
	for(int i=0;i<P;i++){
		headersP<<"z."<<i<<"\t";
	}
	for(int i=0;i<P-1;i++){
		headersP<<"ps."<<i<<"\t"<<"pu."<<i<<"\t";
	}
	headersP<<"ps."<<P-1<<"\t"<<"pu."<<P-1<<std::endl;

	for(int i=0;i<alphas.size();i++){
		headers<<"alphas."<<i<<"\t";
	}
	for(int i=0;i<alphau.size();i++){
		headers<<"alphau."<<i<<"\t";
	}
	headers<<"q"<<std::endl;
	//counters
	int iteration=0,j=0;
	/*
	 * Run the MCMC algorithm
	 */

	/*
	 * Initialize the normalizing constants
	 */

	for(iteration = 0; iteration < NITERS; iteration++){
		//::Rprintf("%d ",iteration);
		for(j=0;j<k;j++){
			/*
			 * prior for the current alphas_j
			 */

			prior=::Rf_dexp(alphas[j],1.0/EXPRATE,true);
			std::copy(alphas.begin(),alphas.end(),newalphas.begin());

			//current null marginal log likelihood
			loglikenull(sum_stim_unstim,alphau,llnull,stdsum_data_alphau,P,k);

			//If alternative is greater compute the ratio of normalizing constants for the alternative marginal log likelihood
			if(FILTER&&k==2&&!FAST){
				normalizingConstant(stdstim,stdunstim,alphas,alphau,llresp,P,k);
			}else{
				//otherwise the two sided marginal log likelihood
				loglikeresp(stdstim,alphas,stdunstim,alphau,llresp,stdsum_data_alphas,stdsum_data_alphau,P,k);
			}

			//compute z1*lnull+z2*lresp+prior
			completeLL(z,llnull,llresp,cll,filter,P,k);

			oldll=std::accumulate(cll.begin(),cll.end(),0.0)+prior;
			if(isfinite(oldll)!=1){
         ::Rf_error( "oldll != 1");
			}

			//simulate alphas_j
			//try integral values for alpha_s beta_s
			if(FILTER&&k==2&&!FAST){
				newalphas[j]=ceil(alphaProposal(alphas,sigmas[j]*rateS[j],j));
			}else{
				newalphas[j]=alphaProposal(alphas,sigmas[j]*rateS[j],j);
			}
			if(newalphas[j]>0){
//				if(FILTER&&k==2&&!FAST){
//					newprior=dgeom(newalphas[j],EXPRATE);
//				}else{
					newprior=::Rf_dexp(newalphas[j],1.0/EXPRATE,true);
//				}

				//don't need to recompute the null marginal log likelihood since it doesn't depend on alphas_j
				std::copy(llnull.begin(),llnull.end(),llnullNew.begin());
				if(FILTER&&k==2&&!FAST){
					//compute one sided marginal log likelihood
					normalizingConstant(stdstim,stdunstim,newalphas,alphau,llrespNew,P,k);
				}else{
					//two sided
					loglikeresp(stdstim,newalphas,stdunstim,alphau,llrespNew,stdsum_data_alphas,stdsum_data_alphau,P,k);
				}
				//compute z1*lnull+z2*lresp+prior
				completeLL(z,llnullNew,llrespNew,cll,filter,P,k);
				newll=std::accumulate(cll.begin(),cll.end(),0.0)+newprior;
			}else{
				REJECT=true;
				newll=nan("0");
			}

			//Rprintf("newll - oldll = %f isfinite()=%d\n",newll-oldll,isfinite(newll-oldll));

			if(!REJECT&&newalphas[j]>0&&(::log(Rf_runif(0.0,1.0)) <= (newll-oldll) )&&(!ISNAN(newll-oldll)&&(!ISNAN(newll))&&isfinite(::exp(newll-oldll)))){
#ifdef NDEBUG
				Rprintf("ACCEPTED alphas_%d %f prob: %f newll %f oldll %f\n",j,newalphas[j],::exp(newll-oldll), newll, oldll);
#endif
				accepts[j]=accepts[j]+1;//increment acceptance count
				alphas[j]=newalphas[j]; //new alphas_j is accepted
				oldll=newll-newprior; //save the new complete data log likelihood (minus the prior for alphas_j) so we don't recompute it for the next step
				std::copy(llnullNew.begin(),llnullNew.end(),llnull.begin()); //ditto for the null and alternative marginal log likelihood
				std::copy(llrespNew.begin(),llrespNew.end(),llresp.begin());
			}else{
				oldll=oldll-prior; //reject so just subtract the alpha-specific prior
#ifdef NDEBUG
				Rprintf("REJECTED alphas_%d %f, deltall: %f newll %f oldll %f\n",j,newalphas[j],(newll-oldll),newll, oldll);
				REJECT=false;
#endif
			}
			if(isfinite(oldll)!=1){
         ::Rf_error( "oldll != 1");
			}

			/*
			 * Simulate alphau_j
			 */
			//prior for the current alphau_j
//			if(FILTER&&k==2&&!FAST){
//				prior=dgeom(alphau[j],EXPRATE);
//			}else{
				prior=Rf_dexp(alphau[j],1.0/EXPRATE,true);
//			}
			oldll=oldll+prior;

			//recompute to see if we still have problems with alpha u beta u estimates
//			loglikenull(stdsum_stim_unstim,stdalphau,stdllnullRes,stdsum_data_alphau,P,k); //new null marginal likelihood.
//			if(FILTER&&k==2&&!FAST){
//				normalizingConstant(stdstim,stdunstim,stdalphas,stdalphau,stdllrespRes,P,k); //new responder marginal LL - one sided
//			}else{
//				//two sided
//				loglikeresp(stdstim,stdalphas,stdunstim,stdalphau,stdllrespRes,stdsum_data_alpha,stdsum_data_alphau,P,k);
//			}
//			completeLL(z,stdllnullRes,stdllrespRes,cll,filter,P,k);
//			oldll=std::accumulate(cll.begin(),cll.end(),0.0)+prior;

			if(isfinite(oldll)!=1){
         ::Rf_error( "dimensions don't match");
			}
			//copy the alphau vector to the proposal vector.
			std::copy(alphau.begin(),alphau.end(),newalphau.begin());//copy the current alpha vector to the new alpha vector prior to drawing a sample

			//simulate alphau)j
			if(FILTER&&k==2&&!FAST){
				newalphau[j]=ceil(alphaProposal(alphau,sigmau[j]*rateU[j],j));
			}else{
				newalphau[j]=alphaProposal(alphau,sigmau[j]*rateU[j],j);
			}
			if(newalphau[j]>0){

//				if(FILTER&&k==2&&!FAST){
//					newprior=dgeom(newalphau[j],EXPRATE);
//				}else{
					newprior=Rf_dexp(newalphau[j],1.0/EXPRATE,true);
//				}

				//compute z1*lnull+z2*lresp+prior
				loglikenull(sum_stim_unstim,newalphau,llnullNew,stdsum_data_alphau,P,k); //new null marginal likelihood.
				if(FILTER&&k==2&&!FAST){
					normalizingConstant(stdstim,stdunstim,alphas,newalphau,llrespNew,P,k); //new responder marginal LL - one sided
				}else{
					//two sided
					loglikeresp(stdstim,alphas,stdunstim,newalphau,llrespNew,stdsum_data_alphas,stdsum_data_alphau,P,k);
				}
				//compute z1*lnull+z2*lresp+prior
				completeLL(z,llnullNew,llrespNew,cll,filter,P,k);
				newll=std::accumulate(cll.begin(),cll.end(),0.0)+newprior;
			}else{
				REJECT=true;
				newll=nan("0");
			}

			//	printf("newll - oldll = %f isfinite()=%d\n",newll-oldll,isfinite(newll-oldll));
			if(!REJECT&&newalphau[j]>0&&(log(Rf_runif(0.0,1.0)) <= (newll-oldll) )&&(!ISNAN(newll-oldll)&&(!ISNAN(newll))&&isfinite(::exp(newll-oldll)))){
				//increment acceptance count for alphauj
#ifdef NDEBUG
				Rprintf("ACCEPTED alphau_%d %f, prob ratio %f newll %f oldll %f\n",j,newalphau[j],::exp(newll-oldll),newll, oldll);
#endif
				acceptu[j]=acceptu[j]+1;
				alphau[j]=newalphau[j];//new alphau_j is accepted
				oldll=newll-newprior; //complete data log likelihood (minus the prior)
				//marginal null and alternative log likelihoods for the accepted parameter are saved so we don't have to recompute them
				std::copy(llnullNew.begin(),llnullNew.end(),llnull.begin());
				std::copy(llrespNew.begin(),llrespNew.end(),llresp.begin());
			}else{
				oldll=oldll-prior;
				REJECT=false;
#ifdef NDEBUG
				Rprintf("REJECTED alphau_%d %f, deltall: %f newll %f oldll %f\n",j,newalphau[j],(newll-oldll),newll, oldll);
#endif
			}
			//simulate q (w)
			q=simQ(z,P,k,pXi);
			//simulate z
			simZ(q,llnull,llresp,z,p,filter,P,k); //overwrites the current z. A running average is stored in cz

		}

		/*
		 * If we haven't fixed the step sizes yet..
		 */
		if(!fixed){
			/*
			 * Tuning phase
			 */
			//Fill in the Ms and Mu matrices
			asi = conv_to<arma::vec>::from(alphas);
#ifdef DEBUG2
			Rprintf("conv alphas to asi\n");
#endif
			aui = conv_to<arma::vec>::from(alphau);
#ifdef DEBUG2
			Rprintf("conv alphau to aui\n");
#endif
//print some dimensions
#ifdef DEBUG2
			Rprintf("Ms size is %d rows by %d columns and asi size is %d rows by %d columns\n",Ms.n_rows,Ms.n_cols,asi.n_rows,asi.n_cols);
#endif
			Ms.row(iteration%(int)TUNING) = trans(asi);
#ifdef DEBUG2
			Rprintf("assign asi to Ms.row\n");
#endif
			Mu.row(iteration%(int)TUNING) = trans(aui);
#ifdef DEBUG2
			Rprintf("assign aui to Mu.row\n");
#endif
			//Tuning
			if(((iteration+1) % (int)TUNING)==0){
				ntune=ntune+1;
				//Compute the covariances
				arma::mat covarianceS = arma::cov(Ms);
#ifdef DEBUG2
				Rprintf("compute cov Ms\n");
#endif
				arma::mat covarianceU = arma::cov(Mu);
#ifdef DEBUG2
				Rprintf("compute cov Mu\n");
#endif
				arma::vec dS = arma::sqrt(covarianceS.diag());
#ifdef DEBUG2
				Rprintf("sqrt diag S\n");
#endif
				arma::vec dU = arma::sqrt(covarianceU.diag());
#ifdef DEBUG2
				Rprintf("sqrt diag U\n");
#endif
				//Weight and assign
				//Tweak the acceptance rates
				accepts=accepts/TUNING;
				acceptu=acceptu/TUNING;

//				printf("sigmas: ");
//				for(j=0;j<sigmas.length();j++){
//					printf("%f %f ",sigmas[j],sigmau[j]);
//				}
//				printf("\n Acceptance rates:");
//				for(j = 0; j < accepts.length(); j++){
//					printf("%f %f ",accepts[j],acceptu[j]);
//				}
//				printf("\n");
				Rprintf("Tuning: %d\t",ntune);
				if((ntune<=12&&(Rcpp::any(accepts > UPPER).is_true() || Rcpp::any(acceptu > UPPER).is_true() || Rcpp::any(accepts < LOWER).is_true() || Rcpp::any(acceptu < LOWER).is_true()))){
					for(j=0;j<accepts.length();j++){
						//stimulated
						if((accepts[j]/DEFAULT_RATE) > 1.1 || (accepts[j]/DEFAULT_RATE )<0.8){
							rateS[j]=accepts[j]/DEFAULT_RATE;
						}
						//unstimulated
						if((acceptu[j]/DEFAULT_RATE) > 1.1 || (acceptu[j]/DEFAULT_RATE) < 0.8){
							rateU[j]=acceptu[j]/DEFAULT_RATE;
						}
					}
					for(j=0;j<sigmas.length();j++){
						sigmas[j] = dS(j);
						sigmau[j] = dU(j);
					}

					for(j=0;j<k;j++){
						if(rateS[j]==0){
							R_CheckUserInterrupt();
							rateS[j]=1;
							accepts[j]=0;
							iteration=0;
						}
						if(ISNAN(sigmas[j])||sigmas[j]==0){
							R_CheckUserInterrupt();
							sigmas[j]=1;
							accepts[j]=0;
							iteration=0;
						}
						if(rateU[j]==0){
							R_CheckUserInterrupt();
							rateU[j]=1;
							iteration=0;
							acceptu[j]=0;
						}if(ISNAN(sigmau[j])||sigmau[j]==0){
							R_CheckUserInterrupt();
							sigmau[j]=1;
							iteration=0;
							acceptu[j]=0;
						}
					}

				}else{
					Rprintf("Fixed step size\n");
					Rprintf("sigmas: ");
					for(int j=0;j<sigmas.length();j++){
						Rprintf("%f %f ",sigmas[j],sigmau[j]);
					}
					Rprintf("\n Acceptance rates:");
					for(int j = 0; j < accepts.length(); j++){
						Rprintf("%f %f ",accepts[j],acceptu[j]);
					}
					Rprintf("\n");
					fixed=true;
					iteration = 0;
					//write out the headers for the two data files
					fprintf(file,"%s",headers.str().data());
					fprintf(fileP,"%s",headersP.str().data());
				}
				//reset the acceptance counts
				accepts.fill(0);
				acceptu.fill(0);
			}
		}
		/*
		 * Running average of z1's after the burn-in
		 */

		if((iteration+1)%10000==0){
			R_CheckUserInterrupt();
			if(iteration==0){
				std::copy(p.begin(),p.end(),cz.begin());
			}
			Rprintf("--- Done %i iterations ---\n",(int)iteration+1);
			//			printf("\n Acceptance rates:");
			//			for(int j = 0; j < accepts.length(); j++){
			//				printf("%f %f",accepts[j],acceptu[j]);
			//			}
			//			printf("\n");
		}

		if(iteration>=BURNIN&&iteration%(int)THINNING==0&&fixed){
			realitcounter++;
			for(int j=0;j<p.size();j++){
				double f = realitcounter/(realitcounter+1.0);
				double foo = p[j]/realitcounter;
				cz[j]=(cz[j]+foo)*f;
			}
			//write chain to file
			//write out the z's
			//when the model is two dimensional..
			if(k==2){
				//and the proportions sampled from each model
				sampleP(sum_stim_unstim,stdstim,stdunstim,alphas,alphau,z,ps,pu,P,k);
				for(int obs=0;obs<P;obs++){
					fprintf(fileP,"%f\t", z[obs]);
				  // prr[iteration-BURNIN]+=(1-z[obs]);
				}
				for(int obs=0;obs<P-1;obs++){
					fprintf(fileP,"%f\t%f\t",ps[obs],pu[obs]);
				}
				fprintf(fileP,"%f\t%f\n",ps[P-1],pu[P-1]);
			}
			for(int obs=0;obs<alphas.size();obs++){
				fprintf(file,"%f\t", alphas[obs]);
			}
			for(int obs=0;obs<alphau.size();obs++){
				fprintf(file,"%f\t", alphau[obs]);
			}
			fprintf(file,"%f\n",q);
			// std::cout<<"PRR: "<<prr[iteration-BURNIN]/P<<std::endl;
		}
#ifdef NDEBUG
		Rprintf("alphas: %f %f alphau: %f %f\n",alphas[0],alphas[1],alphau[0],alphau[1]);
#endif
	}
	if(!fixed){
		Rprintf("Failed to set step size. Run a longer chain.\n");
	}

	/*
	 * Close the file and return some stuff to R.
	 */
	fflush(file);fflush(fileP);
	fclose(file);fclose(fileP);
	ntune=0;
	return Rcpp::List::create(
			Rcpp::Named("z") = cz,
			Rcpp::Named("stepsizeS") = sigmas,
			Rcpp::Named("stepsizeU") = sigmau);
	    // Rcpp::Named("prr") = prr);
	END_RCPP
}

/*
 * Null component log likelihood
 * data is the data, alpha is the parameters, output is the result, sum_dat_alphau is data+alpha
 */
void loglikenull(const std::vector<double> &data,const std::vector<double>  &alpha,std::vector<double> &output, std::vector<double> &sum_dat_alphau,int P, int k){
	int i=0,j=0;
	double da=0,a=0;
	a=lkbeta(alpha);
	for(i=0;i<P;i++){
		for(j=0;j<k;j++){
			sum_dat_alphau[j*P+i]=data[j*P+i]+alpha[j];
		}
		da=lkbeta(sum_dat_alphau,i,k,P);
		output[i]=da-a;
	}

}
/*
 * Responder component log-likelihood
 */
void loglikeresp(const std::vector<double>  &stim, const std::vector<double>  &alphas,const  std::vector<double>  &unstim, const std::vector<double>  &alphau,std::vector<double> &output, std::vector<double> &sum_dat_alphas,std::vector<double> &sum_dat_alphau,int P, int k){
	int i=0,j=0;
	double da,db,a,b;
	b=lkbeta(alphau);
	a=lkbeta(alphas);
	for(i=0;i<P;i++){
		for(j=0;j<k;j++){
			sum_dat_alphas[j*P+i]=stim[j*P+i]+alphas[j];
			sum_dat_alphau[j*P+i]=unstim[j*P+i]+alphau[j];
		}
		da=lkbeta(sum_dat_alphas,i,k,P);
		db=lkbeta(sum_dat_alphau,i,k,P);
		output[i]=da+db-a-b;
	}
}

/*
 * K-dimensional Beta function
 */
inline double lkbeta(const std::vector<double>& alpha,int I,int k,int P){
	double sum_alpha=0;
	double sum_log_gamma_alpha=0;
	double log_gamma_sum_alpha=0;
	for(int j = 0;j<k;j++){
		sum_alpha=sum_alpha+alpha[I+j*P];
		sum_log_gamma_alpha = sum_log_gamma_alpha+lgamma(alpha[j*P+I]);
	}
	log_gamma_sum_alpha = lgamma(sum_alpha);
	return sum_log_gamma_alpha-log_gamma_sum_alpha;
}

inline double lkbeta(const std::vector<double> &alpha){
	double sum_alpha = std::accumulate(alpha.begin(),alpha.end(),0.0);
	double log_gamma_sum_alpha = lgamma(sum_alpha);
	double sum_log_gamma_alpha=0;
	for(int i=0;i<alpha.size();i++){
		sum_log_gamma_alpha=sum_log_gamma_alpha+lgamma(alpha[i]);
	}
	return sum_log_gamma_alpha-log_gamma_sum_alpha;
}

/*
 * log-gamma function for use with std::transform
 */
double op_lgamma(double i){
	return lgamma(i);
}

/*
 * Draw a proposal for the ith component of an alpha vector
 */
double alphaProposal(const std::vector<double> &alpha, double sigma, int i){
	double na;
	na = ::Rf_rnorm(alpha[i],sigma);
	return na;
}
double alphaDiscreteProposal(const std::vector<double> &alpha, double d, int i){
	double na;
	d=round(std::abs(d));
	if(d<1){
    ::Rf_error( "d is < 1");
	}
	na = ::Rf_runif(-d,d);
	na=alpha[i]+na;
	return na;
}

/*
 * Compute the complete data log-likelihood
 * If FILTER is true, we check each index against the value of filter, and set the posterior probability to zero for FILTER_j = true
 */
void completeLL(std::vector<double> &z,std::vector<double> &lnull, std::vector<double> &lresp,std::vector<double> &cll,std::vector<bool> &filter,int P, int k){
	int i;
	for(i=0;i< P;i++){
		if(FAST&filter[i]){
			z[i+P]=0.0;z[i]=1.0;
		}
		cll[i] = z[i]*lnull[i]+z[i+P]*(lresp[i]);
	}
}
void simZ(double &q,std::vector<double> &lnull, std::vector<double> &lresp,std::vector<double>& z,std::vector<double> &p,std::vector<bool> &filter,int P, int k){
	int i;
	double lq = ::log(q);
	double mlq = ::log(1.0-q);
	for(i=0;i < lnull.size(); i++){
		lnull[i]=lnull[i]+lq;
		lresp[i]=lresp[i]+mlq;
		double mx=std::max(lnull[i],lresp[i]);
		//printf("null:%f\talternative: %f\n",lnull[i],lresp[i]);
		if(FAST&filter[i]){
			p[i]=1;
		}else{
			p[i] = ::exp(lnull[i]-::log(::exp(lnull[i]-mx)+::exp(lresp[i]-mx))-mx);
			z[i] = ::Rf_rbinom(1.0,p[i]);
			z[i+P] = 1.0-z[i];
		}
	}
}
//inline double simQ(std::vector<double> &z, int P,int k,double pXi){
inline double simQ(std::vector<double> &z, int P,int k, NumericVector pXi){
	std::vector<double> ab(2,0);
	double q;
	for(int j=0;j<2;j++){
		for(int i=0;i<P;i++){
			ab[j]=ab[j]+z[j*P+i];
		}
	}
	q = 1.0-::Rf_rbeta(ab[1]+pXi[0],ab[0]+pXi[1]);
	return q;
}

void normalizingConstant(std::vector<double> &stim,std::vector<double> &unstim,std::vector<double> &alphas,std::vector<double> &alphau,std::vector<double> &llresp, int P,int k){
	if(k!=2){
     ::Rf_error( "k!=2");
	}
	double numerator=0,denominator=0,nummc,denommc;
	double C=1,CC=1;
	//If any alphas are <= 0 fill with nan;
	std::vector<double> u(2,0), s(2,0);
	int i=0,j=0;
	for(i=0;i<P;i++){
		for(j=0;j<2;j++){
			s[j]=stim[i+j*P]+alphas[j];
			u[j]=unstim[i+j*P]+alphau[j];
		}
		//alphas[1] is alpha, alphas[0] is beta
		//data+hyperparameters
		//Rprintf("s1 %f, s0 %f, u1 %f u0 %f\n",s[1],s[0],u[1],u[0]);
		//Rprintf("alphas %f, betas %f, alphau %f betau %f\n",alphas[1],alphas[0],alphau[1],alphau[0]);

		numerator=normconstIBeta((double)s[0],(double)s[1],(double)u[0],(double)u[1]);
		//hyperparameters only
		denominator=normconstIBeta((double)alphas[0],(double)alphas[1],(double)alphau[0],(double)alphau[1]);
		//					nummc = normconstMC((double)s[1],(double)s[0],(double)u[1],(double)u[0]);
		//					denommc = normconstMC((double)alphas[1],(double)alphas[0],(double)alphau[1],(double)alphau[0]);
		//	Rprintf("%f/%f\n",nummc,denommc);
		//	Rprintf("%f  %f  %f\n",log(nummc),log(denommc),log(nummc)-log(denommc));

		//Rprintf("numerator: %f, denominator %f\n",exp(numerator), exp(denominator));
		CC=numerator-denominator;
		//printf("alphas %f betas %f alphau %f betau %f\n",alphas[1], alphas[0], alphau[1],alphau[0]);

		//		C=log(nummc)-log(denommc);
		//printf("%d.\t%f\t%f\n",i,nummc,denommc);
		//	printf("C: %f CC: %f  diff: %f\n",C,CC, C-CC);
		//double K=lgamma((double)s[1])+lgamma((double)s[0])-lgamma(s[1]+s[0])+lgamma((double)u[1])+lgamma((double)u[0])-lgamma(u[1]+u[0])-lgamma((double)alphas[1])-lgamma((double)alphas[0])+lgamma(alphas[1]+alphas[0])-lgamma((double)alphau[1])-lgamma((double)alphau[0])+lgamma(alphau[1]+alphau[0]);
		double K = ::Rf_lbeta((double) s[1],(double) s[0])+::Rf_lbeta((double) u[1], (double) u[0])-::Rf_lbeta((double) alphas[1],(double)alphas[0])-::Rf_lbeta((double)alphau[1],(double)alphau[0]);
		if(ISNAN(CC)){
			//			printf("s0: %f s1: %f u0: %f u1: %f as0: %f as1: %f au0: %f au1: %f \n",s[0],s[1],u[0],u[1],alphas[0],alphas[1],alphau[0],alphau[1]);
			//			printf("numerator: %f  denominator %f  C: %f\n",numerator,denominator,numerator-denominator);
			//			printf("log(1-exp(C))=%f\n",log(1-exp(numerator-denominator)));
			nummc = (normconstMC((double)s[1],(double)s[0],(double)u[1],(double)u[0]));
			denommc = (normconstMC((double)alphas[1],(double)alphas[0],(double)alphau[1],(double)alphau[0]));
			C=log(nummc)-log(denommc);
			CC=C;
		}
		//		printf("mc: %f acpprox: %f difference %f\n",C+K,K+CC,C-CC);
		//Rprintf("C:%f\n",exp(CC));
		//Rprintf("ll:%f\n\n",K+CC);

		llresp[i]=K+CC;
		//printf("%d.\t%f\n",i,llresp[i]);
	}
}

double normconstMC(double as, double bs, double au, double bu){
	double res;
	NumericVector r = rbeta(1000,au,bu);
	r=pbeta(r,as,bs,false,false);
	res = std::accumulate(r.begin(),r.end(),0.0)/r.length();
	return res;
}

//estimate_logZus_int<-function(alpha.u,beta.u,alpha.s,beta.s)
//{
//  if(round(beta.u)!=beta.u) # Test if it's an integer
//  {
//    # Compute for integer values around the true value
//    betaU<-beta.u
//    beta.u<-floor(betaU)
//    j<-alpha.u:(alpha.u+beta.u-1)
//    K<- -lbeta(alpha.s,beta.s)+lfactorial(alpha.u+beta.u-1)+lbeta(j+alpha.s,alpha.u+beta.u-1-j+beta.s)-lfactorial(j)-lfactorial(alpha.u+beta.u-1-j)
//    I1<-sum(exp(K))
//
//    beta.u<-ceiling(betaU)
//    j<-alpha.u:(alpha.u+beta.u-1)
//    K<- -lbeta(alpha.s,beta.s)+lfactorial(alpha.u+beta.u-1)+lbeta(j+alpha.s,alpha.u+beta.u-1-j+beta.s)-lfactorial(j)-lfactorial(alpha.u+beta.u-1-j)
//    I2<-sum(exp(K))
//
//    # Interpolation
//    I<-(ceiling(betaU)-betaU)*I1+(betaU-floor(betaU))*I2
//  }
//  else
//  {
//  j<-alpha.u:(alpha.u+beta.u-1)
//  K<- -lbeta(alpha.s,beta.s)+lfactorial(alpha.u+beta.u-1)+lbeta(j+alpha.s,alpha.u+beta.u-1-j+beta.s)-lfactorial(j)-lfactorial(alpha.u+beta.u-1-j)
//  I<-sum(exp(K))
//  }
//  return(I)
//}

double normconstIBeta(double au, double bu, double as, double bs){
	double alphau = round(au);
	double betaU = round(bu);
	double alphas = as;
	double betas = bs;
	double mx;
	std::vector<double> upper((int)betaU,0.0);
	double sum=0;
	double K=-Rf_lbeta(alphas,betas)+lgamma(alphau+betaU);
	//printf("summation length: %d\n",betaU);
	for(int j=alphau;j<=alphau+betaU-1;j++){
		upper[j-alphau]=Rf_lbeta(j+alphas,alphau+betaU-1-j+betas)-lgamma(j+1)-lgamma(alphau+betaU-j)+K;
	}
	std::vector<double>::iterator where=std::max_element(upper.begin(),upper.end());
	mx = *where;
	for(int i=0;i<upper.size();i++){
		sum=sum+::exp(upper[i]-mx);
	}
	sum=log(sum)+mx;
	return sum;
}
//double normconstIBeta(double as, double bs, double au, double bu){
//	double alphas = as;
//	double betas = bs;
//	double alphau = (double)ceil(au);
//	double betau = (double)ceil(bu);
//	//moved the test for negative proposal outside to the main loop
//	//	if(alphas<=0||betas<=0||alphau<=0||betau<=0){
//	//		return 0.0/0.0; //if any parameters are negative return nan.
//	//	}
//	double sum=0,mx=0;
//	double upper = (double) (alphau+betau);
//	std::vector<double> res((int)betau,0.0);
//	//	printf("as=%f bs=%f au=%f bu=%f\n",as,bs,au,bu);
//	//	printf("INTS: as=%f bs=%f au=%f bu=%f\n",alphas,betas,alphau,betau);
//	//	printf("upper: %d, alphau: %d size: %d\n",upper, alphau,res.size());
//	double K = -::Rf_lbeta(alphas,betas)+Rf_lgammafn(alphau+betau)-Rf_lgammafn(alphas+betas+alphau+betau-1);
//#ifdef FOO
//	printf("upper=%f\n",upper);
//	printf("K=%f\n",K);
//	printf("-::Rf_lbeta(alphas,betas)=%f\n",-::Rf_lbeta(alphas,betas));
//	printf("Rf_lgammafn(alphau+betau)=%f\n",Rf_lgammafn(alphau+betau));
//	printf("-Rf_lgammafn(alphas+betas+alphau-1)=%f\n",-Rf_lgammafn(alphas+betas+alphau-1));
//#endif
//	for(int j = (int)alphau;j<=((int)upper-1);j++){
//#ifdef FOO
//		printf("j=%d\n",j);
//		printf("Rf_lgammafn(alphas+j)=%f\n",Rf_lgammafn(alphas+j));
//		printf("Rf_lgammafn(alphau+betau+betas-1)=%f\n",Rf_lgammafn(alphau+betau+betas-j-1));
//		printf("-Rf_lgammafn(j+1)=%f\n",-Rf_lgammafn(j+1));
//		printf("-Rf_lgammafn(alphau+betau-j)=%f\n",-Rf_lgammafn(alphau+betau-j));
//		printf("sm = %f\n",K+Rf_lgammafn(alphas+j)+Rf_lgammafn(alphau+betau+betas-j-1)-Rf_lgammafn(j+1)-Rf_lgammafn(alphau+betau-j));
//#endif
//		res[j-(int)alphau]=K+Rf_lgammafn(alphas+j)+Rf_lgammafn(alphau+betau+betas-j-1)-Rf_lgammafn(j+1)-Rf_lgammafn(alphau+betau-j);
//	}
//
//	//todo normalized sum of exponentials
//	std::vector<double>::iterator where=std::max_element(res.begin(),res.end());
//	mx = *where;
//	for(int i=0;i<res.size();i++){
//		sum=sum+::exp(res[i]-mx);
//	}
//	sum=log(sum)+mx;
//	//printf("%f \n",sum);
//	return(sum);
//}

//samples P's for the 2-d case only.
void sampleP(std::vector<double>& sumdata,std::vector<double>& stim,std::vector<double>& unstim,std::vector<double>& alphas,std::vector<double>& alphau,std::vector<double>& z, std::vector<double> &ps, std::vector<double> &pu, int P,int k){
	for(int i=0;i<P;i++){
		if(z[i+P]==0){
			//sample from the null model
			ps[i]=Rf_rbeta(sumdata[i+1*P]+alphas[1]+alphau[1],sumdata[i+0*P]+alphas[0]+alphau[0]);
			pu[i]=ps[i];
		}else{
			//otherwise sample from the responder model
			ps[i]=Rf_rbeta(stim[i+1*P]+alphas[1],stim[i+0*P]+alphas[0]);
			pu[i]=Rf_rbeta(unstim[i+1*P]+alphau[1],unstim[i+0*P]+alphau[0]);
		}
	}
}

double nc(double as, double bs, double au,double bu,double B){
	double K,mx,sm=0;
	std::vector<double> s(B+1,0);
	K=::Rf_lbeta(au+as,bu+bs)-::log(au);
	s[0]=K;
	for(int i=0;i<(s.size()-1);i++){
		s[i+1]=(Rf_lbeta(au+1,i+1)+Rf_lbeta(au+as+i+1,bu+bs)-Rf_lbeta(au+bu,i+1)-log(au));
	}
	std::vector<double>::iterator where=std::max_element(s.begin(),s.end());
	mx=*where;
	for(int i=0;i<s.size();i++){
		s[i]=::exp(s[i]-mx);
		sm=sm+s[i];
	}
	sm=log(sm)+mx;
	return(sm);
}

double dgeom(int k,double p){
	if(k<1){
   ::Rf_error( "k<1");
	}
	if(p<0||p>1){
   ::Rf_error( "p is not between 0 and 1");
	}
	double olp=log(1-p);
	double lp=log(p);
	double res=olp*(k-1)+lp;
	return res;
}