Thanks to visit codestin.com
Credit goes to code.bioconductor.org

#include <cmath>  // std::pow
#include "GeoDiff.h"
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

#include <roptim.h>
// [[Rcpp::depends(roptim)]]
using namespace Rcpp;
using namespace roptim;

// You can include R code blocks in C++ files processed with sourceCpp
// (useful for testing and development). The R code will be automatically
// run after the compilation.
//





class NBthmDE_unll : public Functor {
public:
  arma::mat X;
  arma::mat Z;
  arma::vec y;
  arma::vec alpha0;
  arma::vec alpha;
  arma::vec x;

  double operator()(const arma::vec &u) override {
    int n = X.n_cols;
    arma::vec beta = x(arma::span(0,n-1));
    double r = x(n);
    double threshold = x(n+1);
    arma::vec tmp = arma::exp2(X*beta+Z*u);
    arma::vec mu = alpha0*threshold+alpha%tmp;

    return(arma::sum(dnbinom_mu_vec(y, r, mu, 1)));
  }
};

// // [[Rcpp::export]]
// double haha(arma::mat X, arma::mat Z, arma::vec y, arma::vec alpha0,
//             arma::vec alpha, arma::vec x, arma::vec u){
//   lik_probe_mh f;
//   f.X=X;
//   f.Z=Z;
//   f.y=y;
//   f.alpha0 = alpha0;
//   f.alpha=alpha;
//   f.x=x;
//
//   return(f(u));
// }

// [[Rcpp::export]]
List condi_u(arma::mat& Tem, int ind, arma::vec& u,
           int temp_size){
  float mu;
  float Sig;

  if(temp_size==1) {
    mu = 0;
    Sig = Tem(0,0);
  } else {
    int cluster_ind = (ind+temp_size-1)/temp_size;
    //Rcout << "cluster_ind:" << cluster_ind << "\n";
    int temp_ind = ind - (cluster_ind-1)*temp_size;
    //Rcout << "temp_ind:" << temp_ind << "\n";
    arma::vec u_temp = u(arma::span(((cluster_ind-1)*temp_size),(cluster_ind*temp_size-1)));
    //Rcout << "u_temp:" << u_temp << "\n";
    arma::vec ind_vec = arma::linspace(0,(temp_size-1), temp_size);
    arma::uvec lef = arma::find(ind_vec!=(temp_ind-1));
    arma::uvec temp_ind_v(1);
    temp_ind_v.fill(temp_ind-1);
    //Rcout << "lef:" << lef << "\n";
    //arma::mat mu = Tem.submat(temp_ind_v, lef)*arma::solve(Tem.submat(lef,lef), u_temp.elem(lef)));
    //arma::mat Sig = Tem.submat(temp_ind_v,temp_ind_v)+Tem.submat(temp_ind_v, lef)*arma::solve(Tem.submat(lef,lef), Tem.submat(lef, temp_ind_v));
    arma::mat mu0 = Tem.submat(temp_ind_v, lef)*arma::solve(Tem.submat(lef,lef), u_temp.elem(lef));
    arma::mat Sig0 = Tem.submat(temp_ind_v,temp_ind_v)+Tem.submat(temp_ind_v, lef)*arma::solve(Tem.submat(lef,lef), Tem.submat(lef, temp_ind_v));
    mu = mu0(0,0);
    Sig = Sig0(0,0);
  }

  //Rcout << "mu:" << mu << "\n";
  //Rcout << "Sig:" << Sig << "\n";
  // arma::rowvec mu2 = mu(lef);
  // arma::vec mu3 = mu2.elem(lef);
  // Rcout << "mu2:" << mu2 << "\n";
  // //
  return List::create(Named("mu") = mu,
                      Named("Sig") = Sig);

}



// [[Rcpp::export]]
arma::mat NBthmDE_mh(arma::mat& Tem, arma::vec& u, arma::mat& X, arma::mat& Z, arma::vec& y, arma::vec& alpha0,
                 arma::vec& alpha, arma::vec& x, int nmh){
  int len_u = u.n_elem;
  int temp_size = Tem.n_rows;
  float v=0;
  arma::vec u_tmp = u;
  NBthmDE_unll f;
  f.X=X;
  f.Z=Z;
  f.y=y;
  f.alpha0 = alpha0;
  f.alpha=alpha;
  f.x=x;

  arma::mat u_mat(nmh, len_u, arma::fill::zeros);

  for(int i=0; i < nmh; i++){
    for (int j=0; j < len_u; j++){
      u_tmp = u;
      List condidis = condi_u(Tem, (j+1) ,u, temp_size);
      float mu = condidis["mu"];
//      Rcout << "mu" << mu << "\n";
      float Sig = condidis["Sig"];
//      Rcout << "Sig" << Sig << "\n";
      u_tmp(j) = R::rnorm(mu, sqrt(Sig));
//      Rcout << "u_tmp(j):" << u_tmp(j) << "\n";

      float ratio = exp(f(u_tmp)-f(u));
      if(ratio>1) {
        u(j) = u_tmp(j);
      } else{
          v=R::runif(0,1);
          if(v<ratio)
            u(j) = u_tmp(j);
        }

    }
    u_mat.row(i) = u.t();
  }


    return(u_mat);

}