Raw File
#include <RcppArmadillo.h>
#include <vector>
#include <map>
#include "c_optim.h"

namespace rstpm2 {

  using namespace Rcpp;
  using namespace arma;

  // typedefs

  typedef bool constraintfn(int, double *, void *);

  // Hadamard element-wise multiplication for the _columns_ of a matrix with a vector

  mat rmult(mat m, vec v) {
    mat out(m);
    out.each_col() %= v;
    return out;
  }
  mat lmult(vec v, mat m) {
    return rmult(m,v);
  }

  // element-wise multiplication and division for NumericVector and arma::vec

  NumericVector ew_mult(NumericVector nv, vec v) {
    return as<NumericVector>(wrap(as<vec>(wrap(nv)) % v));
  }

  NumericVector ew_div(NumericVector nv, vec v) {
    return as<NumericVector>(wrap(as<vec>(wrap(nv)) / v));
  }

  void Rprint(NumericMatrix m) {
    for (int i=0; i<m.nrow(); ++i) {
      for (int j=0; j<m.ncol(); ++j) 
	Rprintf("%f ", m(i,j));
      Rprintf("\n");
    }
  }

  void Rprint(NumericVector v) {
    for (int i=0; i<v.size(); ++i) 
      Rprintf("%f ", v(i));
    Rprintf("\n");
  }

  void Rprint(vec v) {
    for (size_t i=0; i<v.size(); ++i) 
      Rprintf("%f ", v(i));
    Rprintf("\n");
  }
  void Rprint(rowvec v) {
    for (size_t i=0; i<v.size(); ++i) 
      Rprintf("%f ", v(i));
    Rprintf("\n");
  }

  void Rprint(mat m) {
    for (size_t i=0; i<m.n_rows; ++i) {
      for (size_t j=0; j<m.n_cols; ++j) 
	Rprintf("%f ", m(i,j));
      Rprintf("\n");
    }
  }

  vec pnorm01(vec x) {
    vec out(x.size());
    for (size_t i=0; i<x.size(); ++i)
      out(i) = R::pnorm(x(i),0.0,1.0,1,0);
    return out;
    //return as<vec>(wrap(pnorm(as<NumericVector>(wrap<vec>(x)),0.0,1.0)));
  }

  vec qnorm01(vec x) {
    vec out(x.size());
    for (size_t i=0; i<x.size(); ++i)
      out(i) = R::qnorm(x(i),0.0,1.0,1,0);
    return out;
  }

  vec dnorm01(vec x) {
    vec out(x.size());
    for (size_t i=0; i<x.size(); ++i)
      out(i) = R::dnorm(x(i),0.0,1.0,0);
    return out;
  }

  vec logit(vec p) {
    return log(p/(1-p));
  }

  vec expit(vec x) {
    return 1/(1+exp(-x));
  }

  RcppExport SEXP tapplySum(SEXP s_y, SEXP s_group) {
    NumericVector y(s_y);
    NumericVector group(s_group);
    NumericVector::iterator iy, igroup;
    std::map<double,double> out;
    for (iy = y.begin(), igroup = group.begin(); iy != y.end(); ++iy, ++igroup) { 
	out[*igroup] += *iy;
    }
    return wrap(out);
  }

  // Q: do we need parscale, trace, reltol and criterion in these structs?

  class stpm2 {
  public:
    stpm2(SEXP sexp) {
      List list = as<List>(sexp);
      init = as<NumericVector>(list["init"]);
      X = as<mat>(list["X"]); 
      XD = as<mat>(list["XD"]); 
      bhazard = as<vec>(list["bhazard"]);
      wt = as<vec>(list["wt"]);
      event = as<vec>(list["event"]);
      time = as<vec>(list["time"]);
      delayed = as<int>(list["delayed"]);
      X0.set_size(1,1); X0.fill(0.0);
      wt0.set_size(1); wt0.fill(0.0);
      if (delayed == 1) {
	X0 = as<mat>(list["X0"]); // optional
	XD0 = as<mat>(list["XD0"]); // optional
	wt0 = as<vec>(list["wt0"]); // optional
      }
      parscale = as<vec>(list["parscale"]);
      reltol = as<double>(list["reltol"]);
      kappa = as<double>(list["kappa"]);
      trace = as<int>(list["trace"]);
    }
    // defaults are for the PH model
    virtual vec link(vec S) { return log(-log(S)); }
    virtual vec ilink(vec x) { return exp(-exp(x)); }
    virtual vec h(vec eta, vec etaD) { return etaD % exp(eta); }
    virtual vec H(vec eta, vec etaD) { return exp(eta); }
    virtual mat gradH(vec eta, vec etaD, mat X, mat XD) { return rmult(X,exp(eta)); }
    virtual mat gradh(vec eta, vec etaD, mat X, mat XD) { 
      return rmult(XD, exp(eta)) + rmult(X, etaD % exp(eta));
    }
    virtual double negll(NumericVector beta);
    virtual void grad_negll(NumericVector beta);
    NumericVector init;
    mat X, XD, X0, XD0; 
    vec bhazard,wt,wt0,event,time,parscale;
    double reltol, kappa;
    int delayed, trace;
  };

  double stpm2::negll(NumericVector beta) {
    int n = init.size();
    vec vbeta(&beta[0],n);
    vbeta = vbeta % parscale;
    vec eta = X * vbeta;
    vec etaD = XD * vbeta;
    vec h = this->h(eta,etaD) + bhazard;
    vec H = this->H(eta,etaD) + bhazard;
    double constraint = kappa/2.0 * sum(h % h % (h<0)); // sum(h^2 | h<0)
    vec eps = h*0.0 + 1.0e-16; 
    h = max(h,eps);
    double ll = sum(wt % event % log(h)) - sum(wt % H) - constraint;
    if (delayed == 1) {
      vec eta0 = X0 * vbeta;
      vec etaD0 = XD0 * vbeta;
      mat H0 = this->H(eta0,etaD0);
      ll += sum(wt0 % H0);
    }
    return -ll;  
  }

  void stpm2::grad_negll(NumericVector beta) {
    int n = beta.size();
    vec vbeta = as<vec>(wrap(beta));
    vbeta = vbeta % parscale;
    vec eta = X * vbeta;
    vec etaD = XD * vbeta;
    vec h = this->h(eta,etaD) + bhazard;
    // vec H = exp(eta);
    mat gradH = this->gradH(eta,etaD,X,XD);
    mat gradh = this->gradh(eta,etaD,X,XD);
    mat Xgrad = -gradH + rmult(gradh, event / h);
    mat Xconstraint = - kappa*rmult(gradh,h);
    vec eps = h*0.0 + 1.0e-16; // hack
    //Xgrad.rows(h<=eps) = Xconstraint.rows(h<=eps);
    Xgrad = rmult(Xgrad,wt);
    rowvec vgr = sum(Xgrad,0);
    if (delayed == 1) {
      vec eta0 = X0 * vbeta;
      vec etaD0 = XD0 * vbeta;
      mat gradH0 = this->gradH(eta0, etaD0, X0, XD0); 
      vgr += sum(rmult(gradH0, wt0),0);
    }
    for (int i = 0; i<n; ++i) {
      // gr[i] = -vgr[i]*parscale[i];
    }
  }


  class stpm2PO : public stpm2 {
  public:
    stpm2PO(SEXP sexp) : stpm2(sexp) { }
    vec link(vec S) { return -logit(S); }
    vec ilink(vec x) { return expit(-x); }
    vec h(vec eta, vec etaD) { return etaD % exp(eta) % expit(-eta); }
    vec H(vec eta, vec etaD) { return log(1+exp(eta)); }
    mat gradH(vec eta, vec etaD, mat X, mat XD) { 
      return rmult(X,exp(eta) % expit(-eta));
    }
    mat gradh(vec eta, vec etaD, mat X, mat XD) { 
      return rmult(X, etaD % exp(eta) % expit(-eta)) - 
	rmult(X, exp(2*eta) % etaD % expit(-eta) % expit(-eta)) +
	rmult(XD, exp(eta) % expit(-eta));
    }
  };

  class stpm2Probit : public stpm2 {
  public:
    stpm2Probit(SEXP sexp) : stpm2(sexp) { }
    vec link(vec S) { return -qnorm01(S); }
    vec ilink(vec eta) { return pnorm01(-eta); }
    vec H(vec eta, vec etaD) { return -log(pnorm01(-eta)); }
    vec h(vec eta, vec etaD) { return etaD % dnorm01(eta) / pnorm01(-eta); }
    mat gradH(vec eta, vec etaD, mat X, mat XD) { 
      return rmult(X, dnorm01(eta) / pnorm01(-eta));
    }
    mat gradh(vec eta, vec etaD, mat X, mat XD) { 
      return rmult(X, -eta % dnorm01(eta) % etaD / pnorm01(-eta)) +
	rmult(X, dnorm01(eta) % dnorm01(eta) / pnorm01(-eta) / pnorm01(-eta) % etaD) +
	rmult(XD,dnorm01(eta) / pnorm01(-eta));
    }
  };
  
  class stpm2AH : public stpm2 {
  public:
    stpm2AH(SEXP sexp) : stpm2(sexp) { }
    vec link(vec S) { return -log(S); }
    vec ilink(vec x) { return exp(-x); }
    vec h(vec eta, vec etaD) { return etaD; }
    vec H(vec eta, vec etaD) { return eta; }
    mat gradh(vec eta, vec etaD, mat X, mat XD) { return XD; }
    mat gradH(vec eta, vec etaD, mat X, mat XD) { return X;  }
  };

  struct SmoothLogH {
    int first_para, last_para;
    mat S;
  };

  struct SmoothHaz {
    mat X0, X1, X2, X3;
    vec w;
    double lambda;
  };

  template<class Smooth>
  std::vector<Smooth> read_smoothers(List lsmooth) {}

  template<>
  std::vector<SmoothLogH> read_smoothers(List lsmooth) {
    std::vector<SmoothLogH> smooth;
    for(int i=0; i<lsmooth.size(); ++i) {
      List lsmoothi = as<List>(lsmooth[i]);
      List lsmoothiS = as<List>(lsmoothi["S"]);
      SmoothLogH smoothi =  {
	as<int>(lsmoothi["first.para"]) - 1, 
	as<int>(lsmoothi["last.para"]) - 1, 
	as<mat>(lsmoothiS[0])
      };
      smooth.push_back(smoothi);
    }
    return smooth;
  }

  template<>
  std::vector<SmoothHaz> read_smoothers(List lsmooth) {
    std::vector<SmoothHaz> smooth;
    for(int i=0; i<lsmooth.size(); ++i) {
      List lsmoothi = as<List>(lsmooth[i]);
      SmoothHaz smoothi =  {
	as<mat>(lsmoothi["X0"]), 
	as<mat>(lsmoothi["X1"]), 
	as<mat>(lsmoothi["X2"]), 
	as<mat>(lsmoothi["X3"]), 
	as<vec>(lsmoothi["w"]), 
	as<double>(lsmoothi["lambda"])
      };
      smooth.push_back(smoothi);
    }
    return smooth;
  }

  template<class Smooth, class Stpm2 = stpm2>
  class pstpm2 : public Stpm2 {
  public:
    pstpm2(SEXP sexp) : Stpm2(sexp) {
      List list = as<List>(sexp);
      List lsmooth = as<List>(list["smooth"]);
      sp = as<NumericVector>(list["sp"]);
      reltol_search = as<double>(list["reltol_search"]);
      // reltol = as<double>(list["reltol"]);
      alpha = as<double>(list["alpha"]);
      criterion = as<int>(list["criterion"]);
      smooth = read_smoothers<Smooth>(lsmooth);
    }
    NumericVector sp;
    double alpha, reltol_search; 
    int criterion;
    std::vector<Smooth> smooth;
  };

  /** 
      Extension of stpm2 and pstpm2 to include shared frailties with a cluster variable
  **/
  template<class Stpm2>
  class stpm2Shared : public Stpm2 {
  public:
    stpm2Shared(SEXP sexp) : Stpm2(sexp) {
      List list = as<List>(sexp);
      IntegerVector cluster = as<IntegerVector>(list["cluster"]);
      // wragged array indexed by a map of vectors
      for (int i=0; i<cluster.size(); ++i) {
	clusters[cluster[i]].push_back(i);
      }
    }
    std::map<int,std::vector<int> > clusters;
  };


  /**
     Extension to the BFGS class

     optim() and calc_hessian() assume that data->parscale is an array/vector/NumericVector
     optimWithConstraint() further assumes that data->kappa is a double with an initial value
   */
  template<class Data>
  class BFGS2 : public BFGS {
  public:
    void optim(optimfn fn, optimgr gr, NumericVector init, void * ex,
	       bool apply_parscale = true) {
      Data * data = (Data *) ex;
      n = init.size();
      if (apply_parscale) for (int i = 0; i<n; ++i) init[i] /= data->parscale[i];
      BFGS::optim(fn,gr,init,ex);
      if (apply_parscale) for (int i = 0; i<n; ++i) coef[i] *= data->parscale[i];
      hessian = calc_hessian(gr, ex);
    }
    void optimWithConstraint(optimfn fn, optimgr gr, NumericVector init, void * ex, constraintfn constraint,
			     bool apply_parscale = true) {
      Data * data = (Data *) ex;
      n = init.size();
      if (apply_parscale) for (int i = 0; i<n; ++i) init[i] /= data->parscale[i];
      bool satisfied;
      do {
	BFGS::optim(fn,gr,init,ex);
	satisfied = constraint(n,&coef[0],ex);
	if (!satisfied) data->kappa *= 2.0;   
      } while ((!satisfied)&& data->kappa < 1.0e3);      
      if (apply_parscale) for (int i = 0; i<n; ++i) coef[i] *= data->parscale[i];
      hessian = calc_hessian(gr, ex);
   // Rprintf("kappa=%f\n",data->kappa);
    }
    NumericMatrix calc_hessian(optimgr gr, void * ex) {
      Data * data = (Data *) ex;
      vec parscale(n);
      for (int i=0; i<n; ++i) {
	parscale[i] = data->parscale[i];
	data->parscale[i] = 1.0;
      }
      NumericMatrix hessian = BFGS::calc_hessian(gr,ex);
      for (int i=0; i<n; ++i) data->parscale[i] = parscale[i];
      return hessian;
    }
  };

  template<class Data>
  double fminfn(int n, double * beta, void *ex) {
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    vbeta = vbeta % data->parscale;
    vec eta = data->X * vbeta;
    vec etaD = data->XD * vbeta;
    vec h = data->h(eta,etaD) + data->bhazard;
    vec H = data->H(eta,etaD);
    double constraint = data->kappa/2.0 * sum(h % h % (h<0)) + 
      data->kappa/2.0 * sum((H/data->time) % (H/data->time) % (H<0));
    vec eps = h*0.0 + 1.0e-16; 
    h = max(h,eps);
    H = max(H,eps);
    double ll = sum(data->wt % data->event % log(h)) - sum(data->wt % H) - constraint;
    if (data->delayed == 1) {
      vec eta0 = data->X0 * vbeta;
      vec etaD0 = data->XD0 * vbeta;
      mat H0 = data->H(eta0,etaD0);
      ll += sum(data->wt0 % H0);
    }
    return -ll;  
  }

  /** 
      Objective function for a Gamma shared frailty
      Assumes that weights == 1.
      The implementation is incomplete, requiring either the use of optimisation without
      gradients or the calculation of the gradients.
  **/
  template<class Data>
  double fminfnShared(int n, double * beta, void *ex) {
    typedef std::vector<int> Index;
    typedef std::map<int,Index> IndexMap;
    Data * data = (Data *) ex;
    vec vbeta(beta,n-1); // theta is the last parameter in beta
    double theta = beta[n-1];
    vbeta = vbeta % data->parscale;
    vec eta = data->X * vbeta;
    vec etaD = data->XD * vbeta;
    vec h = data->h(eta,etaD) + data->bhazard;
    vec H = data->H(eta,etaD) + data->bhazard;
    double constraint = data->kappa/2.0 * sum(h % h % (h<0)); // sum(h^2 | h<0)
    vec eps = h*0.0 + 1.0e-16; 
    h = max(h,eps);
    mat H0;
    //double ll = sum(data->wt % data->event % log(h)) - sum(data->wt % H) - constraint;
    if (data->delayed == 1) {
      vec eta0 = data->X0 * vbeta;
      vec etaD0 = data->XD0 * vbeta;
      H0 = data->H(eta0,etaD0);
      //ll += sum(data->wt0 % H0);
    }
    double ll;
    for (IndexMap::iterator it=data->clusters.begin(); it!=data->clusters.end(); ++it) {
      int mi=0;
      double sumH = 0.0, sumHenter = 0.0;
      for (Index::iterator j=it->second.begin(); j!=it->second.end(); ++j) {
	if (data->event(*j)==1) {
	  mi++;
	  ll += log(h(*j));
	}
	sumH += H(*j);
	if (data->delayed == 1)
	  sumHenter += H0(*j);
      }
      ll -= (1.0/theta+mi)*log(1.0+theta*sumH);
      if (data->delayed == 1)
	ll += 1.0/theta*log(1.0+theta*sumHenter);
      if (mi>0) {
	int k=1;
	for (Index::iterator j=it->second.begin(); j!=it->second.end(); ++j) {
	  if (data->event(*j)==1) {
	    ll += log(1.0+theta*(mi-k));
	    k++;
	  }
	}
      }
    }
    ll -= constraint;
    return -ll;  
  }

  /** 
      Utility function for calculating a gamma frailty log-likelihood within R code 
   **/
  RcppExport SEXP llgammafrailty(SEXP _theta, SEXP _h, SEXP _H, SEXP _d,
				    SEXP _cluster) {
    double theta = as<double>(_theta);
    NumericVector h = as<NumericVector>(_h);
    NumericVector H = as<NumericVector>(_H);
    IntegerVector d = as<IntegerVector>(_d);
    IntegerVector cluster = as<IntegerVector>(_cluster);
    double ll = 0.0;
    // wragged array indexed by a map of vectors
    typedef std::vector<int> Index;
    typedef std::map<int,Index> IndexMap;
    IndexMap clusters;
    for (int i=0; i<cluster.size(); ++i) {
      clusters[cluster[i]].push_back(i);
    }
    for (IndexMap::iterator it=clusters.begin(); it!=clusters.end(); ++it) {
      int mi=0;
      double sumH = 0.0;
      for (Index::iterator j=it->second.begin(); j!=it->second.end(); ++j) {
	if (d[*j]==1) {
	  mi++;
	  ll += log(h[*j]);
	}
	sumH += H[*j];
	// sumHenter += Henter[*j];
      }
      ll -= (1.0/theta+mi)*log(1.0+theta*sumH);
      // ll += 1.0/theta*log(1.0+theta*sumHenter);
      if (mi>0) {
	int k=1;
	for (Index::iterator j=it->second.begin(); j!=it->second.end(); ++j) {
	  if (d[*j]==1) {
	    ll += log(1.0+theta*(mi-k));
	    k++;
	  }
	}
      }
    }
    return wrap(ll);
  }

  /** 
      Utility function for calculating a gamma frailty log-likelihood within R code 
   **/
  RcppExport SEXP llgammafrailtydelayed(SEXP _theta, SEXP _h, SEXP _H, SEXP _H0, SEXP _d,
				    SEXP _cluster) {
    double theta = as<double>(_theta);
    NumericVector h = as<NumericVector>(_h);
    NumericVector H = as<NumericVector>(_H);
    NumericVector H0 = as<NumericVector>(_H0); // assumes that _H0 is zero for data not left truncated
    IntegerVector d = as<IntegerVector>(_d);
    IntegerVector cluster = as<IntegerVector>(_cluster);
    double ll = 0.0;
    // wragged array indexed by a map of vectors
    typedef std::vector<int> Index;
    typedef std::map<int,Index> IndexMap;
    IndexMap clusters;
    for (int i=0; i<cluster.size(); ++i) {
      clusters[cluster[i]].push_back(i);
    }
    for (IndexMap::iterator it=clusters.begin(); it!=clusters.end(); ++it) {
      int mi=0;
      double sumH = 0.0, sumHenter = 0.0;
      for (Index::iterator j=it->second.begin(); j!=it->second.end(); ++j) {
	if (d[*j]==1) {
	  mi++;
	  ll += log(h[*j]);
	}
	sumH += H[*j];
	sumHenter += H0[*j];
      }
      ll -= (1.0/theta+mi)*log(1.0+theta*sumH);
      ll += 1.0/theta*log(1.0+theta*sumHenter);
      if (mi>0) {
	int k=1;
	for (Index::iterator j=it->second.begin(); j!=it->second.end(); ++j) {
	  if (d[*j]==1) {
	    ll += log(1.0+theta*(mi-k));
	    k++;
	  }
	}
      }
    }
    return wrap(ll);
  }


  struct CureModel {
    int n0, n1, n2;
    mat Xshape, Xscale, Xcure;
    vec time, status;
  };

  double fminfn_cureModel(int n, double * beta, void *ex) {
    double ll = 0.0;
    CureModel * data = (CureModel *) ex;
    vec vbeta(beta,n);
    vec shape = exp(data->Xshape * vbeta(span(0,data->n0-1)));
    vec scale = exp(data->Xscale * vbeta(span(data->n0,data->n1-1)));
    vec cure = 1.0/(1.0+exp(-data->Xcure * vbeta(span(data->n1,data->n2-1))));
    for (size_t i=0; i < data->time.size(); ++i) {
      ll += data->status(i)==1.0 ?
	log(1.0-cure(i)) + R::dweibull(data->time(i),shape(i),scale(i),1) :
	log(cure(i)+(1.0-cure(i)) * R::pweibull(data->time(i),shape(i),scale(i),0,0));
    }
    R_CheckUserInterrupt();  /* be polite -- did the user hit ctrl-C? */
    return -ll;
  }

RcppExport SEXP fitCureModel(SEXP stime, SEXP sstatus, SEXP sXshape,
			  SEXP sXscale, SEXP sXcure, SEXP sbeta) {
    mat Xshape = as<mat>(sXshape);
    mat Xscale = as<mat>(sXscale);
    mat Xcure = as<mat>(sXcure);
    vec time = as<vec>(stime);
    vec status = as<vec>(sstatus);
    NumericVector init = as<NumericVector>(sbeta);
    int n0=Xshape.n_cols;
    int n1=n0+Xscale.n_cols;
    int n2=n1+Xcure.n_cols;
    CureModel data = {n0,n1,n2,Xshape,Xscale,Xcure,time,status};
    
    NelderMead nm;
    nm.reltol = 1.0e-8;
    nm.maxit = 1000;
    nm.optim(& fminfn_cureModel, init, (void *) &data);

    for (int i = 0; i<nm.coef.size(); ++i)
      init[i] = nm.coef[i]; // clone
    
    return List::create(_("Fmin")=nm.Fmin, 
			_("coef")=wrap(init),
			_("fail")=nm.fail,
			_("hessian")=wrap(nm.hessian));
  }


  template<class Data>
  bool fminfn_constraint(int n, double * beta, void *ex) {
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    vbeta = vbeta % data->parscale;
    vec eta = data->X * vbeta;
    vec etaD = data->XD * vbeta;
    vec h = data->h(eta, etaD) + data->bhazard;
    vec H = data->H(eta, etaD);
    return all((h>0) % (H>0));
  }

  template<class Data>
  void fminfn_nlm(int n, double * beta, double * f, void *ex) {
    *f = fminfn<Data>(n, beta, ex);
  };


  // log H penalty - using penalty matrices from mgcv
  template<class Stpm2>
  double pfminfn_SmoothLogH(int n, double * beta, void *ex) {
    typedef SmoothLogH Smooth;
    typedef pstpm2<Smooth,Stpm2> Data;
    double ll = -fminfn<Data>(n,beta,ex);
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    vbeta = vbeta % data->parscale;
    for (size_t i=0; i < data->smooth.size(); ++i) {
      Smooth smoothi = data->smooth[i];
      ll -= (data->sp)[i]/2 * 
	dot(vbeta.subvec(smoothi.first_para,smoothi.last_para),
	    smoothi.S * vbeta.subvec(smoothi.first_para,smoothi.last_para));
    }
    return -ll;  
  }

  // hazard penalty
  template<class Stpm2>
  double pfminfn_SmoothHaz(int n, double * beta, void *ex) {
    typedef SmoothHaz Smooth;
    typedef pstpm2<Smooth,Stpm2> Data;
    double ll = -fminfn<Data>(n,beta,ex);
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    vbeta = vbeta % data->parscale;
    for (size_t i=0; i < data->smooth.size(); ++i) {
      Smooth obj = data->smooth[i];
      vec s0 = obj.X0 * vbeta;
      vec s1 = obj.X1 * vbeta;
      vec s2 = obj.X2 * vbeta;
      vec s3 = obj.X3 * vbeta;
      vec h2 = exp(s0) % (s3 + 3*s1%s2 + s1%s1%s1);
      ll -= (data->sp)[i]/2 * obj.lambda * sum(obj.w % h2 % h2);
    }
    return -ll;  
  };

  template<class Data>
  void grfn(int n, double * beta, double * gr, void *ex) {
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    // if (data->trace) Rprint(vbeta);
    vbeta = vbeta % data->parscale;
    vec eta = data->X * vbeta;
    vec etaD = data->XD * vbeta;
    vec h = data->h(eta,etaD) + data->bhazard;
    vec H = data->H(eta,etaD);
    vec one = ones(h.size());
    vec eps = h*0.0 + 1.0e-16; 
    mat gradH = data->gradH(eta,etaD,data->X,data->XD); 
    mat gradh = data->gradh(eta,etaD,data->X,data->XD); 
    mat Xgrad = -rmult(gradH, one % (H>eps)) + rmult(gradh, data->event / h % (h>eps));
    mat Xconstraint = data->kappa * rmult(gradh,h%(h<eps)) + 
      data->kappa * rmult(gradH,H / data->time / data->time % (H<eps));
    rowvec dconstraint = sum(Xconstraint,0);
    // if (data->trace) Rprint(dconstraint);
    Xgrad = rmult(Xgrad,data->wt);
    rowvec vgr = sum(Xgrad,0);
    if (data->delayed == 1) {
      vec eta0 = data->X0 * vbeta;
      vec etaD0 = data->XD0 * vbeta;
      mat gradH0 = data->gradH(eta0, etaD0, data->X0, data->XD0); 
      vgr += sum(rmult(gradH0, data->wt0),0);
    }
    for (int i = 0; i<n; ++i) {
      gr[i] = -vgr[i]*data->parscale[i] + dconstraint[i];
    }
  }

  template<class Stpm2>
  void pgrfn_SmoothLogH(int n, double * beta, double * gr, void *ex) {
    typedef SmoothLogH Smooth;
    typedef pstpm2<Smooth,Stpm2> Data;
    grfn<Data>(n, beta, gr, ex);
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    vbeta = vbeta % data->parscale;
    vec eta = data->X * vbeta;
    vec etaD = data->XD * vbeta;
    vec h = data->h(eta,etaD) + data->bhazard;
    vec H = data->H(eta,etaD);
    mat gradh = data->gradh(eta,etaD,data->X,data->XD);
    mat gradH = data->gradH(eta,etaD,data->X,data->XD);
    rowvec vgr(n, fill::zeros);
    for (size_t i=0; i < data->smooth.size(); ++i) {
      SmoothLogH smoothi = data->smooth[i];
      vgr.subvec(smoothi.first_para,smoothi.last_para) += 
	(data->sp)[i] * (smoothi.S * vbeta.subvec(smoothi.first_para,smoothi.last_para)).t();
    }
    for (int i = 0; i<n; ++i) gr[i] += vgr[i]*data->parscale[i];
  }

  template<class Stpm2>
  void pgrfn_SmoothHaz(int n, double * beta, double * gr, void *ex) {
    typedef SmoothHaz Smooth;
    typedef pstpm2<Smooth,Stpm2> Data;
    grfn<Data>(n, beta, gr, ex);
    Data * data = (Data *) ex;
    vec vbeta(beta,n);
    vbeta = vbeta % data->parscale;
    rowvec vgr(n, fill::zeros);
    for (size_t i=0; i < data->smooth.size(); ++i) {
      Smooth obj = data->smooth[i];
      vec s0 = obj.X0 * vbeta;
      vec s1 = obj.X1 * vbeta;
      vec s2 = obj.X2 * vbeta;
      vec s3 = obj.X3 * vbeta;
      vec h2 = exp(s0) % (s3 + 3*s1%s2 + s1%s1%s1);
      mat dh2sq_dbeta = 
	2*lmult(h2 % exp(s0),
		obj.X3+3*(rmult(obj.X1,s2)+rmult(obj.X2,s1))+3*lmult(s1%s1,obj.X1))+
	2*lmult(h2 % h2,obj.X0);
      vgr += (data->sp)[i]*obj.lambda*sum(lmult(obj.w, dh2sq_dbeta),0);
    }
    for (int i = 0; i<n; ++i) gr[i] += vgr[i] * data->parscale[i];
  }

  // oh, for partial template specialisation for functions...

  template<class Smooth,class Stpm2>
  double pfminfn(int n, double * beta, void *ex) { return 0.0; }

  template<>
  double pfminfn<SmoothLogH,stpm2>(int n, double * beta, void *ex) {
    return pfminfn_SmoothLogH<stpm2>(n, beta, ex); }
  template<>
  double pfminfn<SmoothLogH,stpm2PO>(int n, double * beta, void *ex) {
    return pfminfn_SmoothLogH<stpm2PO>(n, beta, ex); }
  template<>
  double pfminfn<SmoothLogH,stpm2Probit>(int n, double * beta, void *ex) {
    return pfminfn_SmoothLogH<stpm2Probit>(n, beta, ex); }
    template<>
  double pfminfn<SmoothLogH,stpm2AH>(int n, double * beta, void *ex) {
    return pfminfn_SmoothLogH<stpm2AH>(n, beta, ex); }

  template<>
  double pfminfn<SmoothHaz,stpm2>(int n, double * beta, void *ex) {
    return pfminfn_SmoothHaz<stpm2>(n, beta, ex); }
  template<>
  double pfminfn<SmoothHaz,stpm2PO>(int n, double * beta, void *ex) {
    return pfminfn_SmoothHaz<stpm2PO>(n, beta, ex); }
  template<>
  double pfminfn<SmoothHaz,stpm2Probit>(int n, double * beta, void *ex) {
    return pfminfn_SmoothHaz<stpm2Probit>(n, beta, ex); }

  template<class Smooth, class Stpm2>
  void pgrfn(int n, double * beta, double * gr, void *ex) { }

  template<>
  void pgrfn<SmoothLogH,stpm2>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothLogH<stpm2>(n, beta, gr, ex); }
  template<>
  void pgrfn<SmoothLogH,stpm2PO>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothLogH<stpm2PO>(n, beta, gr, ex); }
  template<>
  void pgrfn<SmoothLogH,stpm2Probit>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothLogH<stpm2Probit>(n, beta, gr, ex);}
    template<>
  void pgrfn<SmoothLogH,stpm2AH>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothLogH<stpm2AH>(n, beta, gr, ex); }

  template<>
  void pgrfn<SmoothHaz,stpm2>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothHaz<stpm2>(n, beta, gr, ex); }
  template<>
  void pgrfn<SmoothHaz,stpm2PO>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothHaz<stpm2PO>(n, beta, gr, ex); }
  template<>
  void pgrfn<SmoothHaz,stpm2Probit>(int n, double * beta, double * gr, void *ex) {
    pgrfn_SmoothHaz<stpm2Probit>(n, beta, gr, ex); }


  template<class Stpm2>
  SEXP optim_stpm2(SEXP args) {

    Stpm2 data(args);

    BFGS2<Stpm2> bfgs;
    bfgs.reltol = data.reltol;
    bfgs.optimWithConstraint(fminfn<Stpm2>, grfn<Stpm2>, data.init, (void *) &data, fminfn_constraint<Stpm2>);

    return List::create(_("fail")=bfgs.fail,
			_("coef")=wrap(bfgs.coef),
			_("hessian")=wrap(bfgs.hessian));
  }

  RcppExport SEXP optim_stpm2_ph(SEXP args) {
    return optim_stpm2<stpm2>(args); }
  RcppExport SEXP optim_stpm2_po(SEXP args) {
    return optim_stpm2<stpm2PO>(args); }
  RcppExport SEXP optim_stpm2_probit(SEXP args) {
    return optim_stpm2<stpm2Probit>(args); }
  RcppExport SEXP optim_stpm2_ah(SEXP args) {
    return optim_stpm2<stpm2AH>(args); }


  RcppExport SEXP optim_stpm2_nlm(SEXP args) {

    stpm2 data(args);

    data.init = ew_div(data.init,data.parscale);
    int n = data.init.size();
    
    Nlm nlm;
    nlm.gradtl = nlm.steptl = data.reltol;
    //nlm.method=2; nlm.stepmx=0.0;
    bool satisfied;
    do {
      nlm.optim(& fminfn_nlm<stpm2>, & grfn<stpm2>, data.init, (void *) &data);
      satisfied = fminfn_constraint<stpm2>(n,&nlm.coef[0],(void *) &data);
      if (!satisfied) data.kappa *= 2.0;
    } while (!satisfied && data.kappa<1.0e5);

    nlm.coef = ew_mult(nlm.coef, data.parscale);

    return List::create(_("itrmcd")=wrap(nlm.itrmcd),
			_("niter")=wrap(nlm.itncnt),
			_("coef")=wrap(nlm.coef),
			_("hessian")=wrap(nlm.hessian));
  }



  template<class Smooth, class Stpm2>
  double pstpm2_step_first(double logsp, void * ex) {
    typedef pstpm2<Smooth,Stpm2> Data;
    Data * data = (Data *) ex;

    data->sp[0] = exp(logsp);

    BFGS2<Data> bfgs;
    bfgs.reltol = data->reltol;

    bfgs.optimWithConstraint(pfminfn<Smooth,Stpm2>, pgrfn<Smooth,Stpm2>, data->init, ex, fminfn_constraint<Data>, false); // do not apply parscale b4/after

    NumericMatrix hessian0 = bfgs.calc_hessian(grfn<Data>, ex);

    if (data->trace > 0)  {
      Rprintf("Debug on trace calculation. Coef:\n");
      Rprint(bfgs.coef);
      Rprintf("Hessian0:\n");
      Rprint(hessian0);
      Rprintf("Hessian:\n");
      Rprint(bfgs.hessian);
    }

    double edf = trace(solve(as<mat>(bfgs.hessian),as<mat>(hessian0)));
    double negll = bfgs.calc_objective(fminfn<Data>,ex);
    double gcv =  negll + data->alpha*edf;
    double bic =  negll + data->alpha*edf*log(sum(data->event));
    data->init = bfgs.coef;
    if (data->trace > 0)
      Rprintf("sp=%f\tedf=%f\tnegll=%f\tgcv=%f\tbic=%f\talpha=%f\n",data->sp[0],edf,negll,gcv,bic,data->alpha);

    return data->criterion==1 ? gcv : bic;
  }    

  template<class Smooth, class Stpm2>
  double pstpm2_step_multivariate(int n, double * logsp, void * ex) {
    typedef pstpm2<Smooth,Stpm2> Data;
    Data * data = (Data *) ex;

    double lsp = -9.0, usp = 9.0;

    for (int i=0; i < data->sp.size(); ++i)
      //data->sp[i] = exp(logsp[i]);
      data->sp[i] = exp(bound(logsp[i],lsp,usp));

    if (data->trace > 0) {
      for (int i = 0; i < data->sp.size(); ++i)
	Rprintf("sp[%i]=%f\t",i,data->sp[i]);
    }

    BFGS2<Data> bfgs; 
    bfgs.reltol = data->reltol_search;
    bfgs.optimWithConstraint(pfminfn<Smooth,Stpm2>, pgrfn<Smooth,Stpm2>, data->init, ex, fminfn_constraint<Data>, false); // do not apply parscale b4/after

    NumericMatrix hessian0 = bfgs.calc_hessian(grfn<Data>, ex);

    double edf = trace(solve(as<mat>(bfgs.hessian),as<mat>(hessian0)));
    double negll = bfgs.calc_objective(fminfn<Data>, ex);
    double gcv =  negll + data->alpha*edf;
    double bic =  2.0*negll + data->alpha*edf*log(sum(data->event));
    data->init = bfgs.coef;

    // simple boundary constraints
    double constraint = 0.0;
    // double kappa = 1.0;
    for (int i=0; i < data->sp.size(); ++i) {
      if (logsp[i] < lsp)
	constraint +=  pow(logsp[i]-lsp,2.0);
      if (logsp[i] > usp)
	constraint +=  pow(logsp[i]-usp,2.0);
    }
    double objective =  data->criterion==1 ? 
      gcv + data->kappa/2.0*constraint : 
      bic + data->kappa/2.0*constraint;

    if (data->trace > 0) {
      Rprintf("edf=%f\tnegll=%f\tgcv=%f\tbic=%f\tobjective=%f\n",edf,negll,gcv,bic,objective);
    }
    return objective;
  }    


  template<class Smooth, class Stpm2>
  void pstpm2_step_multivariate_nlm(int n, double * logsp, double * f, void *ex) {
    *f = pstpm2_step_multivariate<Smooth,Stpm2>(n, logsp, ex);
  };


  template<class Smooth, class Stpm2>
  SEXP optim_pstpm2_first(SEXP args) { 

    typedef pstpm2<Smooth,Stpm2> Data;
    Data data(args);
    int n = data.init.size();

    for (int i=0; i<n; ++i) data.init[i] /= data.parscale[i];
    double opt_sp = exp(Brent_fmin(log(0.001),log(1000.0),&pstpm2_step_first<Smooth,Stpm2>,&data,1.0e-2));
    data.sp[0] = opt_sp;
    for (int i=0; i<n; ++i) data.init[i] *= data.parscale[i];

    BFGS2<Data> bfgs;
    bfgs.coef = data.init;
    bfgs.reltol = data.reltol;
    bfgs.optimWithConstraint(pfminfn<Smooth,Stpm2>, pgrfn<Smooth,Stpm2>, data.init, (void *) &data, fminfn_constraint<Data>);

    NumericMatrix hessian0 = bfgs.calc_hessian(grfn<Data>, (void *) &data);
    double edf = trace(solve(as<mat>(bfgs.hessian),as<mat>(hessian0)));

    return List::create(_("sp")=wrap(opt_sp),
			_("coef")=wrap(bfgs.coef),
			_("hessian")=wrap(bfgs.hessian),
          _("edf")=wrap(edf));

  }

  RcppExport SEXP optim_pstpm2LogH_first_ph(SEXP args) {
    return optim_pstpm2_first<SmoothLogH,stpm2>(args); }
  RcppExport SEXP optim_pstpm2Haz_first_ph(SEXP args) {
    return optim_pstpm2_first<SmoothHaz,stpm2>(args); }
  RcppExport SEXP optim_pstpm2LogH_first_po(SEXP args) {
    return optim_pstpm2_first<SmoothLogH,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2Haz_first_po(SEXP args) {
    return optim_pstpm2_first<SmoothHaz,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2LogH_first_probit(SEXP args) {
    return optim_pstpm2_first<SmoothLogH,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2Haz_first_probit(SEXP args) {
    return optim_pstpm2_first<SmoothHaz,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2LogH_first_ah(SEXP args) {
    return optim_pstpm2_first<SmoothLogH,stpm2AH>(args); }
  
  
  template<class Smooth, class Stpm2>
  SEXP optim_pstpm2_multivariate(SEXP args) {

    typedef pstpm2<Smooth,Stpm2> Data;
    Data data(args);
    int n = data.init.size();
    data.kappa = 10.0;

    NelderMead nm;
    nm.reltol = 1.0e-5;
    nm.maxit = 500;
    nm.hessianp = false;
    for (int i=0; i<n; ++i) data.init[i] /= data.parscale[i];

    NumericVector logsp(data.sp.size());
    for (int i=0; i < data.sp.size(); ++i)
      logsp[i] = log(data.sp[i]);

    bool satisfied;
    do {
      nm.optim(pstpm2_step_multivariate<Smooth,Stpm2>, logsp, (void *) &data);
      satisfied = true;
      for (int i=0; i < data.sp.size(); ++i)
	if (logsp[i]< -7.0 || logsp[i] > 7.0) satisfied = false;
      if (!satisfied) data.kappa *= 2.0;
    } while (!satisfied && data.kappa<1.0e5);

    for (int i=0; i<n; ++i) data.init[i] *= data.parscale[i];
    // for (int i=0; i < data.sp.size(); ++i)
    //   data.sp[i] = exp(logsp[i]);
    for (int i=0; i < nm.coef.size(); ++i)
      data.sp[i] = exp(nm.coef[i]);

    BFGS2<Data> bfgs;
    bfgs.coef = data.init;
    bfgs.reltol = data.reltol;
    data.kappa = 1.0;
    bfgs.optimWithConstraint(pfminfn<Smooth,Stpm2>, pgrfn<Smooth,Stpm2>, data.init, (void *) &data, fminfn_constraint<Data>);

    NumericMatrix hessian0 = bfgs.calc_hessian(grfn<Data>, (void *) &data);
    double edf = trace(solve(as<mat>(bfgs.hessian),as<mat>(hessian0)));

    return List::create(_("sp")=wrap(data.sp),
  			_("coef")=wrap(bfgs.coef),
  			_("hessian")=wrap(bfgs.hessian),
        _("edf")=wrap(edf));

  }

  RcppExport SEXP optim_pstpm2LogH_multivariate_ph(SEXP args) { 
    return optim_pstpm2_multivariate<SmoothLogH,stpm2>(args); }
  RcppExport SEXP optim_pstpm2Haz_multivariate_ph(SEXP args) {
    return optim_pstpm2_multivariate<SmoothHaz,stpm2>(args); }
  RcppExport SEXP optim_pstpm2LogH_multivariate_po(SEXP args) {
    return optim_pstpm2_multivariate<SmoothLogH,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2Haz_multivariate_po(SEXP args) {
    return optim_pstpm2_multivariate<SmoothHaz,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2LogH_multivariate_probit(SEXP args) {
    return optim_pstpm2_multivariate<SmoothLogH,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2Haz_multivariate_probit(SEXP args) {
    return optim_pstpm2_multivariate<SmoothHaz,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2LogH_multivariate_ah(SEXP args) { 
    return optim_pstpm2_multivariate<SmoothLogH,stpm2AH>(args); }

  template<class Smooth, class Stpm2>
  SEXP optim_pstpm2_multivariate_nlm(SEXP args) {

    typedef pstpm2<Smooth,Stpm2> Data;
    Data data(args);
    int n = data.init.size();
    data.kappa = 10.0;

    Nlm nlm;
    nlm.iagflg = 0;
    nlm.gradtl = 1.0e-4;
    nlm.steptl = 1.0e-4;
    nlm.msg = 9 + 4;
    nlm.hessianp = false;
    for (int i=0; i<n; ++i) data.init[i] /= data.parscale[i];

    NumericVector logsp(data.sp.size());
    for (int i=0; i < data.sp.size(); ++i)
      logsp[i] = log(data.sp[i]);

    bool satisfied;
    do {
      nlm.optim(pstpm2_step_multivariate_nlm<Smooth,Stpm2>, (fcn_p) 0, logsp, (void *) &data);
      satisfied = true;
      for (int i=0; i < data.sp.size(); ++i)
	if (logsp[i]< -7.0 || logsp[i] > 7.0) satisfied = false;
      if (!satisfied) data.kappa *= 2.0;
    } while (!satisfied && data.kappa<1.0e5);

    for (int i=0; i<n; ++i) data.init[i] *= data.parscale[i];
    for (int i=0; i < nlm.coef.size(); ++i)
      data.sp[i] = exp(nlm.coef[i]);

    BFGS2<Data> bfgs;
    bfgs.coef = data.init;
    bfgs.reltol = data.reltol;
    data.kappa = 1.0;
    bfgs.optimWithConstraint(pfminfn<Smooth,Stpm2>, pgrfn<Smooth,Stpm2>, data.init, (void *) &data, fminfn_constraint<Data>);

    NumericMatrix hessian0 = bfgs.calc_hessian(grfn<Data>, (void *) &data);
    double edf = trace(solve(as<mat>(bfgs.hessian),as<mat>(hessian0)));

    return List::create(_("sp")=wrap(data.sp),
  			_("coef")=wrap(bfgs.coef),
  			_("hessian")=wrap(bfgs.hessian),
			_("edf")=wrap(edf));
  }

  RcppExport SEXP optim_pstpm2LogH_multivariate_ph_nlm(SEXP args) { 
    return optim_pstpm2_multivariate_nlm<SmoothLogH,stpm2>(args); }
  RcppExport SEXP optim_pstpm2Haz_multivariate_ph_nlm(SEXP args) {
    return optim_pstpm2_multivariate_nlm<SmoothHaz,stpm2>(args); }
  RcppExport SEXP optim_pstpm2LogH_multivariate_po_nlm(SEXP args) {
    return optim_pstpm2_multivariate_nlm<SmoothLogH,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2Haz_multivariate_po_nlm(SEXP args) {
    return optim_pstpm2_multivariate_nlm<SmoothHaz,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2LogH_multivariate_probit_nlm(SEXP args) {
    return optim_pstpm2_multivariate_nlm<SmoothLogH,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2Haz_multivariate_probit_nlm(SEXP args) {
    return optim_pstpm2_multivariate_nlm<SmoothHaz,stpm2Probit>(args); }


  template<class Smooth, class Stpm2>
  SEXP optim_pstpm2_fixedsp(SEXP args) { 

    typedef pstpm2<Smooth,Stpm2> Data;
    Data data(args);
    BFGS2<Data> bfgs;
    bfgs.coef = data.init;
    bfgs.reltol = data.reltol;

    bfgs.optimWithConstraint(pfminfn<Smooth,Stpm2>, pgrfn<Smooth,Stpm2>, data.init, (void *) &data, fminfn_constraint<Data>);

    NumericMatrix hessian0 = bfgs.calc_hessian(grfn<Data>, (void *) &data);
    double edf = trace(solve(as<mat>(bfgs.hessian),as<mat>(hessian0)));

    return List::create(_("sp")=wrap(data.sp),
			_("coef")=wrap(bfgs.coef),
			_("hessian")=wrap(bfgs.hessian),
			_("edf")=wrap(edf));
  }

  RcppExport SEXP optim_pstpm2LogH_fixedsp_ph(SEXP args) {
    return optim_pstpm2_fixedsp<SmoothLogH,stpm2>(args); }
  RcppExport SEXP optim_pstpm2Haz_fixedsp_ph(SEXP args) {
    return optim_pstpm2_fixedsp<SmoothHaz,stpm2>(args); }
  RcppExport SEXP optim_pstpm2LogH_fixedsp_po(SEXP args) {
    return optim_pstpm2_fixedsp<SmoothLogH,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2Haz_fixedsp_po(SEXP args) {
    return optim_pstpm2_fixedsp<SmoothHaz,stpm2PO>(args); }
  RcppExport SEXP optim_pstpm2LogH_fixedsp_probit(SEXP args) { 
    return optim_pstpm2_fixedsp<SmoothLogH,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2Haz_fixedsp_probit(SEXP args) {
    return optim_pstpm2_fixedsp<SmoothHaz,stpm2Probit>(args); }
  RcppExport SEXP optim_pstpm2LogH_fixedsp_ah(SEXP args) {
    return optim_pstpm2_fixedsp<SmoothLogH,stpm2AH>(args); }

  template<class Smooth, class Stpm2>
  SEXP test_pstpm2(SEXP args) { 

    pstpm2<Smooth,Stpm2> data(args);
    int n = data.init.size();

    NumericVector init = ew_div(data.init,data.parscale);

    double pfmin = pfminfn<Smooth,Stpm2>(n,&init[0],(void *) &data);
    NumericVector gr(n);
    pgrfn<Smooth,Stpm2>(n,&init[0], &gr[0], (void *) &data);

    init = ew_mult(init,data.parscale);

    return List::create(_("sp")=wrap(data.sp),
			_("pfmin")=wrap(pfmin),
			_("gr")=wrap(gr)
			);

  }

  RcppExport SEXP test_pstpm2LogH(SEXP args) {
    return test_pstpm2<SmoothLogH,stpm2>(args);
  }

  RcppExport SEXP test_pstpm2Haz(SEXP args) {
    return test_pstpm2<SmoothHaz,stpm2>(args);
  }

  // R CMD INSTALL ~/src/R/microsimulation
  // R -q -e "require(microsimulation); .Call('test_nmmin',1:2,PACKAGE='microsimulation')"

  // .Call("optim_stpm2",init,X,XD,rep(bhazard,nrow(X)),wt,ifelse(event,1,0),package="rstpm2")

} // anonymous namespace
back to top