#ifndef LINREG_GLASSO_ADMM_H
#define LINREG_GLASSO_ADMM_H

#include <RcppArmadillo.h>
#include "ADMMutilsLM.h"
#include "linreg_lasso_ADMM.h"

#define DOUBLE_EPS 2.220446e-16
#define ARMA_64BIT_WORD 1
#define SAFE_LOG(a) (((a) <= 0.0) ? log(DOUBLE_EPS) : log(a))
#define SAFE_ZERO(a) ((a) == 0 ? DOUBLE_EPS : (a))
#define SQRT_DOUBLE_EPS sqrt(DOUBLE_EPS)

using std::pow;
using std::exp;
using std::sqrt;
using std::log;

using namespace Rcpp;
using namespace arma;

/*
    Group-LASSO and sparse Group-LASSO via ADMM: wrap functions
                                                                        */

Rcpp::List admm_glasso(const arma::mat& A,
                       const arma::vec& b,
                       const arma::mat& groups,
                       const arma::vec& group_weights,
                       const arma::vec& var_weights,
                       arma::colvec& u,
                       arma::colvec& z,
                       const double lambda,
                       const bool rho_adaptation,
                       double rho,
                       const double tau,
                       const double mu,
                       const double reltol,
                       const double abstol,
                       const int maxiter,
                       const int ping);

Rcpp::List admm_glasso_cov(const arma::mat& W,
                           const arma::mat& Z,
                           const arma::vec& y,
                           arma::colvec& u,
                           arma::colvec& z,
                           const arma::mat& groups,
                           const arma::vec& group_weights,
                           const arma::vec& var_weights,
                           double lambda,
                           const bool rho_adaptation,
                           double rho,
                           const double tau,
                           const double mu,
                           const double reltol,
                           const double abstol,
                           const int maxiter,
                           const int ping);

Rcpp::List admm_glasso_fast(const arma::mat& A,
                            const arma::vec& b,
                            const arma::mat& groups,
                            const arma::vec& group_weights,
                            const arma::vec& var_weights,
                            const arma::vec lambda,
                            const bool rho_adaptation,
                            double rho,
                            const double tau,
                            const double mu,
                            const double reltol,
                            const double abstol,
                            const int maxiter,
                            const int ping);

Rcpp::List admm_glasso_cov_fast(const arma::mat& W,
                                const arma::mat& Z,
                                const arma::vec& y,
                                const arma::mat& groups,
                                const arma::vec& group_weights,
                                const arma::vec& var_weights,
                                const arma::vec& lambda,
                                const bool rho_adaptation,
                                double rho,
                                const double tau,
                                const double mu,
                                const double reltol,
                                const double abstol,
                                const int maxiter,
                                const int ping);

Rcpp::List admm_spglasso(const arma::mat& A,
                         const arma::vec& b,
                         const arma::mat& groups,
                         const arma::vec& group_weights,
                         const arma::vec& var_weights,
                         const arma::vec& var_weights_L1,
                         arma::colvec& u,
                         arma::colvec& z,
                         const double lambda1,
                         const double lambda2,
                         const bool rho_adaptation,
                         double rho,
                         const double tau,
                         const double mu,
                         const double reltol,
                         const double abstol,
                         const int maxiter,
                         const int ping);

Rcpp::List admm_spglasso_cov(const arma::mat& W,
                             const arma::mat& Z,
                             const arma::vec& y,
                             const arma::mat& groups,
                             const arma::vec& group_weights,
                             const arma::vec& var_weights,
                             const arma::vec& var_weights_L1,
                             arma::colvec& u,
                             arma::colvec& z,
                             const double lambda1,
                             const double lambda2,
                             const bool rho_adaptation,
                             double rho,
                             const double tau,
                             const double mu,
                             const double reltol,
                             const double abstol,
                             const int maxiter,
                             const int ping);

Rcpp::List admm_spglasso_fast(const arma::mat& A,
                              const arma::vec& b,
                              const arma::mat& groups,
                              const arma::vec& group_weights,
                              const arma::vec& var_weights,
                              const arma::vec& var_weights_L1,
                              const arma::vec& lambda,
                              const double alpha,
                              const bool rho_adaptation,
                              double rho,
                              const double tau,
                              const double mu,
                              const double reltol,
                              const double abstol,
                              const int maxiter,
                              const int ping);

Rcpp::List admm_spglasso_cov_fast(const arma::mat& W,
                                  const arma::mat& Z,
                                  const arma::vec& y,
                                  const arma::mat& groups,
                                  const arma::vec& group_weights,
                                  const arma::vec& var_weights,
                                  const arma::vec& var_weights_L1,
                                  const arma::vec& lambda,
                                  const double alpha,
                                  const bool rho_adaptation,
                                  double rho,
                                  const double tau,
                                  const double mu,
                                  const double reltol,
                                  const double abstol,
                                  const int maxiter,
                                  const int ping);

Rcpp::List admm_glasso_cov_large_m(const arma::mat& W,
                                   const arma::mat& Z,
                                   const arma::vec& y,
                                   arma::colvec& u,
                                   arma::colvec& z,
                                   const arma::mat& groups,
                                   const arma::vec& group_weights,
                                   const arma::vec& var_weights,
                                   const double lambda,
                                   const bool rho_adaptation,
                                   double rho,
                                   const double tau,
                                   const double mu,
                                   const double reltol,
                                   const double abstol,
                                   const int maxiter,
                                   const int ping);

Rcpp::List admm_glasso_cov_large_n(const arma::mat& W,
                                   const arma::mat& Z,
                                   const arma::vec& y,
                                   arma::colvec& u,
                                   arma::colvec& z,
                                   const arma::mat& groups,
                                   const arma::vec& group_weights,
                                   const arma::vec& var_weights,
                                   const double lambda,
                                   const bool rho_adaptation,
                                   double rho,
                                   const double tau,
                                   const double mu,
                                   const double reltol,
                                   const double abstol,
                                   const int maxiter,
                                   const int ping);

/*
    Group-LASSO and sparse Group-LASSO via ADMM: main functions
                                                                        */

Rcpp::List admm_glasso_large_m(const arma::mat& A,
                               const arma::vec& b,
                               const arma::mat& groups,
                               const arma::vec& group_weights,
                               const arma::vec& var_weights,
                               arma::colvec& u,
                               arma::colvec& z,
                               const double lambda,
                               const bool rho_adaptation,
                               double rho,
                               const double tau,
                               const double mu,
                               const double reltol,
                               const double abstol,
                               const int maxiter,
                               const int ping);

Rcpp::List admm_glasso_large_n(const arma::mat& A,
                               const arma::vec& b,
                               const arma::mat& groups,
                               const arma::vec& group_weights,
                               const arma::vec& var_weights,
                               arma::colvec& u,
                               arma::colvec& z,
                               const double lambda,
                               const bool rho_adaptation,
                               double rho,
                               const double tau,
                               const double mu,
                               const double reltol,
                               const double abstol,
                               const int maxiter,
                               const int ping);

Rcpp::List admm_spglasso_large_m(const arma::mat& A,
                                 const arma::vec& b,
                                 const arma::mat& groups,
                                 const arma::vec& group_weights,
                                 const arma::vec& var_weights,
                                 const arma::vec& var_weights_L1,
                                 arma::colvec& u,
                                 arma::colvec& z,
                                 const double lambda1,
                                 const double lambda2,
                                 const bool rho_adaptation,
                                 double rho,
                                 const double tau,
                                 const double mu,
                                 const double reltol,
                                 const double abstol,
                                 const int maxiter,
                                 const int ping);

Rcpp::List admm_spglasso_large_n(const arma::mat& A,
                                 const arma::vec& b,
                                 const arma::mat& groups,
                                 const arma::vec& group_weights,
                                 const arma::vec& var_weights,
                                 const arma::vec& var_weights_L1,
                                 arma::colvec& u,
                                 arma::colvec& z,
                                 const double lambda1,
                                 const double lambda2,
                                 const bool rho_adaptation,
                                 double rho,
                                 const double tau,
                                 const double mu,
                                 const double reltol,
                                 const double abstol,
                                 const int maxiter,
                                 const int ping);

Rcpp::List admm_spglasso_cov_large_m(const arma::mat& W,
                                     const arma::mat& Z,
                                     const arma::vec& y,
                                     arma::colvec& u,
                                     arma::colvec& z,
                                     const arma::mat& groups,
                                     const arma::vec& group_weights,
                                     const arma::vec& var_weights,
                                     const arma::vec& var_weights_L1,
                                     const double lambda,
                                     const double alpha,
                                     const bool rho_adaptation,
                                     double rho,
                                     const double tau,
                                     const double mu,
                                     const double reltol,
                                     const double abstol,
                                     const int maxiter,
                                     const int ping);

Rcpp::List admm_spglasso_cov_large_n(const arma::mat& W,
                                     const arma::mat& Z,
                                     const arma::vec& y,
                                     arma::colvec& u,
                                     arma::colvec& z,
                                     const arma::mat& groups,
                                     const arma::vec& group_weights,
                                     const arma::vec& var_weights,
                                     const arma::vec& var_weights_L1,
                                     const double lambda,
                                     const double alpha,
                                     const bool rho_adaptation,
                                     double rho,
                                     const double tau,
                                     const double mu,
                                     const double reltol,
                                     const double abstol,
                                     const int maxiter,
                                     const int ping);


/*
    Group-LASSO and sparse Group-LASSO via ADMM:
                  main functions, fast routines
                                                                */

Rcpp::List admm_glasso_large_m_fast(const arma::mat& A,
                                    const arma::vec& b,
                                    const arma::mat& groups,
                                    const arma::vec& group_weights,
                                    const arma::vec& var_weights,
                                    const arma::vec& lambda,
                                    const bool rho_adaptation,
                                    double rho,
                                    const double tau,
                                    const double mu,
                                    const double reltol,
                                    const double abstol,
                                    const int maxiter,
                                    const int ping);

Rcpp::List admm_glasso_large_n_fast(const arma::mat& A,
                                    const arma::vec& b,
                                    const arma::mat& groups,
                                    const arma::vec& group_weights,
                                    const arma::vec& var_weights,
                                    const arma::vec& lambda,
                                    const bool rho_adaptation,
                                    double rho,
                                    const double tau,
                                    const double mu,
                                    const double reltol,
                                    const double abstol,
                                    const int maxiter,
                                    const int ping);

Rcpp::List admm_glasso_cov_large_m_fast(const arma::mat& W,
                                        const arma::mat& Z,
                                        const arma::vec& y,
                                        const arma::mat& groups,
                                        const arma::vec& group_weights,
                                        const arma::vec& var_weights,
                                        const arma::vec& lambda,
                                        const bool rho_adaptation,
                                        double rho,
                                        const double tau,
                                        const double mu,
                                        const double reltol,
                                        const double abstol,
                                        const int maxiter,
                                        const int ping);

Rcpp::List admm_glasso_cov_large_n_fast(const arma::mat& W,
                                        const arma::mat& Z,
                                        const arma::vec& y,
                                        const arma::mat& groups,
                                        const arma::vec& group_weights,
                                        const arma::vec& var_weights,
                                        const arma::vec& lambda,
                                        const bool rho_adaptation,
                                        double rho,
                                        const double tau,
                                        const double mu,
                                        const double reltol,
                                        const double abstol,
                                        const int maxiter,
                                        const int ping);

Rcpp::List admm_spglasso_large_m_fast(const arma::mat& A,
                                      const arma::vec& b,
                                      const arma::mat& groups,
                                      const arma::vec& group_weights,
                                      const arma::vec& var_weights,
                                      const arma::vec& var_weights_L1,
                                      const arma::vec& lambda,
                                      const double alpha,
                                      const bool rho_adaptation,
                                      double rho,
                                      const double tau,
                                      const double mu,
                                      const double reltol,
                                      const double abstol,
                                      const int maxiter,
                                      const int ping);

Rcpp::List admm_spglasso_large_n_fast(const arma::mat& A,
                                      const arma::vec& b,
                                      const arma::mat& groups,
                                      const arma::vec& group_weights,
                                      const arma::vec& var_weights,
                                      const arma::vec& var_weights_L1,
                                      const arma::vec& lambda,
                                      const double alpha,
                                      const bool rho_adaptation,
                                      double rho,
                                      const double tau,
                                      const double mu,
                                      const double reltol,
                                      const double abstol,
                                      const int maxiter,
                                      const int ping);

Rcpp::List admm_spglasso_cov_large_m_fast(const arma::mat& W,
                                          const arma::mat& Z,
                                          const arma::vec& y,
                                          const arma::mat& groups,
                                          const arma::vec& group_weights,
                                          const arma::vec& var_weights,
                                          const arma::vec& var_weights_L1,
                                          const arma::vec& lambda,
                                          const double alpha,
                                          const bool rho_adaptation,
                                          double rho,
                                          const double tau,
                                          const double mu,
                                          const double reltol,
                                          const double abstol,
                                          const int maxiter,
                                          const int ping);

Rcpp::List admm_spglasso_cov_large_n_fast(const arma::mat& W,
                                          const arma::mat& Z,
                                          const arma::vec& y,
                                          const arma::mat& groups,
                                          const arma::vec& group_weights,
                                          const arma::vec& var_weights,
                                          const arma::vec& var_weights_L1,
                                          const arma::vec& lambda,
                                          const double alpha,
                                          const bool rho_adaptation,
                                          double rho,
                                          const double tau,
                                          const double mu,
                                          const double reltol,
                                          const double abstol,
                                          const int maxiter,
                                          const int ping);

/*
    Group-LASSO and sparse Group-LASSO via ADMM:
                  main functions to compute a single lambda
                                                                */

Rcpp::List admm_glasso_large_m_update_1lambda(const arma::mat& A,
                                              const arma::vec& b,
                                              const arma::mat& groups,
                                              const arma::vec& group_weights,
                                              const arma::vec& var_weights,
                                              const arma::sp_mat& F,
                                              const arma::mat& FTF,
                                              const arma::mat& ATA,
                                              const arma::mat& ATA_CHOL_U,
                                              const arma::vec& ATb,
                                              const double b2,
                                              const int m,
                                              const int n,
                                              const int G,
                                              arma::colvec& u,
                                              arma::colvec& z,
                                              const double lambda,
                                              const bool rho_adaptation,
                                              double rho,
                                              const double tau,
                                              const double mu,
                                              const double reltol,
                                              const double abstol,
                                              const int maxiter,
                                              const int ping);

Rcpp::List admm_glasso_large_n_update_1lambda(const arma::mat& A,
                                              const arma::vec& b,
                                              const arma::mat& groups,
                                              const arma::vec& group_weights,
                                              const arma::vec& var_weights,
                                              const arma::sp_mat& F,
                                              const arma::mat& FTF_INV,
                                              const arma::mat& AFTF_INVA,
                                              const arma::mat& ATA_CHOL_U,
                                              const arma::colvec& ATb,
                                              const double b2,
                                              const int m,
                                              const int n,
                                              const int G,
                                              arma::colvec& u,
                                              arma::colvec& z,
                                              const double lambda,
                                              const bool rho_adaptation,
                                              double rho,
                                              const double tau,
                                              const double mu,
                                              const double reltol,
                                              const double abstol,
                                              const int maxiter,
                                              const int ping);

Rcpp::List admm_glasso_cov_large_m_update_1lambda(const arma::mat& W,
                                                  const arma::mat& Z,
                                                  const arma::vec& y,
                                                  const arma::mat& groups,
                                                  const arma::vec& group_weights,
                                                  const arma::vec& var_weights,
                                                  const int G,
                                                  const arma::sp_mat& F,
                                                  const arma::mat& FTF,
                                                  const arma::mat& WMW,
                                                  const arma::vec& WMy,
                                                  const arma::vec& v_LS,
                                                  const arma::mat& P_ZW,
                                                  const arma::mat& WW_CHOL_U,
                                                  const arma::colvec& Wy,
                                                  const double y2,
                                                  const arma::mat& ZZ_CHOL_U,
                                                  const arma::colvec& Zy,
                                                  const arma::mat& ZW,
                                                  arma::colvec& u,
                                                  arma::colvec& z,
                                                  const double lambda,
                                                  const bool rho_adaptation,
                                                  double rho,
                                                  const double tau,
                                                  const double mu,
                                                  const double reltol,
                                                  const double abstol,
                                                  const int maxiter,
                                                  const int ping);

Rcpp::List admm_glasso_cov_large_n_update_1lambda(const arma::mat& W,
                                                  const arma::mat& Z,
                                                  const arma::vec& y,
                                                  const arma::mat& groups,
                                                  const arma::vec& group_weights,
                                                  const arma::vec& var_weights,
                                                  const int G,
                                                  const arma::sp_mat& F,
                                                  const arma::mat& FF_INV,
                                                  const arma::mat& M_ZZW,
                                                  const arma::mat& M_ZZW2,
                                                  const arma::mat& WMW,
                                                  const arma::vec& WMy,
                                                  const arma::vec& v_LS,
                                                  const arma::mat& P_ZW,
                                                  const arma::mat& WW_CHOL_U,
                                                  const arma::colvec& Wy,
                                                  const double y2,
                                                  const arma::mat& ZZ_CHOL_U,
                                                  const arma::colvec& Zy,
                                                  const arma::mat& ZW,
                                                  arma::colvec& u,
                                                  arma::colvec& z,
                                                  const double lambda,
                                                  const bool rho_adaptation,
                                                  double rho,
                                                  const double tau,
                                                  const double mu,
                                                  const double reltol,
                                                  const double abstol,
                                                  const int maxiter,
                                                  const int ping);

Rcpp::List admm_spglasso_large_m_update_1lambda(const arma::mat& A,
                                                const arma::vec& b,
                                                const arma::mat& groups,
                                                const arma::vec& group_weights,
                                                const arma::vec& var_weights,
                                                const arma::vec& var_weights_L1,
                                                const arma::sp_mat& F,
                                                const arma::mat& FTF,
                                                const arma::mat& ATA,
                                                const arma::mat& ATA_CHOL_U,
                                                const arma::colvec& ATb,
                                                const double b2,
                                                const int m,
                                                const int n,
                                                const int G,
                                                arma::colvec& u,
                                                arma::colvec& z,
                                                const double lambda,
                                                const double alpha,
                                                const bool rho_adaptation,
                                                double rho,
                                                const double tau,
                                                const double mu,
                                                const double reltol,
                                                const double abstol,
                                                const int maxiter,
                                                const int ping);

Rcpp::List admm_spglasso_large_n_update_1lambda(const arma::mat& A,
                                                const arma::vec& b,
                                                const arma::mat& groups,
                                                const arma::vec& group_weights,
                                                const arma::vec& var_weights,
                                                const arma::vec& var_weights_L1,
                                                const arma::sp_mat& F,
                                                const arma::mat& FTF_INV,
                                                const arma::mat& AFTF_INVA,
                                                const arma::mat& ATA_CHOL_U,
                                                const arma::colvec& ATb,
                                                const double b2,
                                                const int m,
                                                const int n,
                                                const int G,
                                                arma::colvec& u,
                                                arma::colvec& z,
                                                const double lambda,
                                                const double alpha,
                                                const bool rho_adaptation,
                                                double rho,
                                                const double tau,
                                                const double mu,
                                                const double reltol,
                                                const double abstol,
                                                const int maxiter,
                                                const int ping);

Rcpp::List admm_spglasso_cov_large_m_update_1lambda(const arma::mat& W,
                                                    const arma::mat& Z,
                                                    const arma::vec& y,
                                                    const arma::mat& groups,
                                                    const arma::vec& group_weights,
                                                    const arma::vec& var_weights,
                                                    const arma::vec& var_weights_L1,
                                                    const int G,
                                                    const arma::sp_mat& F,
                                                    const arma::mat& FTF,
                                                    const arma::mat& WMW,
                                                    const arma::vec& WMy,
                                                    const arma::vec& v_LS,
                                                    const arma::mat& P_ZW,
                                                    const arma::mat& WW_CHOL_U,
                                                    const arma::colvec& Wy,
                                                    const double y2,
                                                    const arma::mat& ZZ_CHOL_U,
                                                    const arma::colvec& Zy,
                                                    const arma::mat& ZW,
                                                    arma::colvec& u,
                                                    arma::colvec& z,
                                                    const double lambda,
                                                    const double alpha,
                                                    const bool rho_adaptation,
                                                    double rho,
                                                    const double tau,
                                                    const double mu,
                                                    const double reltol,
                                                    const double abstol,
                                                    const int maxiter,
                                                    const int ping);

Rcpp::List admm_spglasso_cov_large_n_update_1lambda(const arma::mat& W,
                                                    const arma::mat& Z,
                                                    const arma::vec& y,
                                                    const arma::mat& groups,
                                                    const arma::vec& group_weights,
                                                    const arma::vec& var_weights,
                                                    const arma::vec& var_weights_L1,
                                                    const int G,
                                                    const arma::sp_mat& F,
                                                    const arma::mat& FF_INV,
                                                    const arma::mat& M_ZZW,
                                                    const arma::mat& M_ZZW2,
                                                    const arma::mat& WMW,
                                                    const arma::vec& WMy,
                                                    const arma::vec& v_LS,
                                                    const arma::mat& P_ZW,
                                                    const arma::mat& WW_CHOL_U,
                                                    const arma::colvec& Wy,
                                                    const double y2,
                                                    const arma::mat& ZZ_CHOL_U,
                                                    const arma::colvec& Zy,
                                                    const arma::mat& ZW,
                                                    arma::colvec& u,
                                                    arma::colvec& z,
                                                    const double lambda,
                                                    const double alpha,
                                                    const bool rho_adaptation,
                                                    double rho,
                                                    const double tau,
                                                    const double mu,
                                                    const double reltol,
                                                    const double abstol,
                                                    const int maxiter,
                                                    const int ping);



#endif
