/* Genome-wide Efficient Mixed Model Association (GEMMA) Copyright (C) 2011 Xiang Zhou This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "gsl/gsl_vector.h" #include "gsl/gsl_matrix.h" #include "gsl/gsl_linalg.h" #include "gsl/gsl_blas.h" #include "gsl/gsl_cdf.h" #include "gsl/gsl_multiroots.h" #include "gsl/gsl_min.h" #include "io.h" #include "lapack.h" #include "gzstream.h" #ifdef FORCE_FLOAT #include "lmm_float.h" #include "vc_float.h" #else #include "lmm.h" #include "vc.h" #endif using namespace std; //in this file, X, Y are already transformed (i.e. UtX and UtY) void VC::CopyFromParam (PARAM &cPar) { file_out=cPar.file_out; // v_sigma2=cPar.v_sigma2; time_UtX=0.0; time_opt=0.0; v_traceG=cPar.v_traceG; return; } void VC::CopyToParam (PARAM &cPar) { cPar.time_UtX=time_UtX; cPar.time_opt=time_opt; cPar.v_sigma2=v_sigma2; cPar.v_se_sigma2=v_se_sigma2; cPar.v_pve=v_pve; cPar.v_se_pve=v_se_pve; cPar.v_traceG=v_traceG; cPar.v_beta=v_beta; cPar.v_se_beta=v_se_beta; return; } void UpdateParam (const gsl_vector *log_sigma2, VC_PARAM *p) { size_t n1=(p->K)->size1, n_vc=log_sigma2->size-1, n_cvt=(p->W)->size2; gsl_matrix *K_temp=gsl_matrix_alloc(n1, n1); gsl_matrix *HiW=gsl_matrix_alloc(n1, n_cvt); gsl_matrix *WtHiW=gsl_matrix_alloc(n_cvt, n_cvt); gsl_matrix *WtHiWi=gsl_matrix_alloc(n_cvt, n_cvt); gsl_matrix *WtHiWiWtHi=gsl_matrix_alloc(n_cvt, n1); double sigma2; //calculate H=\sum_i^{k+1} \sigma_i^2 K_i gsl_matrix_set_zero (p->P); for (size_t i=0; iK, 0, n1*i, n1, n1); gsl_matrix_memcpy (K_temp, &K_sub.matrix); } sigma2=exp(gsl_vector_get (log_sigma2, i) ); gsl_matrix_scale(K_temp, sigma2); gsl_matrix_add (p->P, K_temp); } //calculate H^{-1} int sig; gsl_permutation * pmt1=gsl_permutation_alloc (n1); LUDecomp (p->P, pmt1, &sig); LUInvert (p->P, pmt1, K_temp); gsl_permutation_free(pmt1); gsl_matrix_memcpy (p->P, K_temp); //calculate P=H^{-1}-H^{-1}W(W^TH^{-1}W)^{-1}W^TH^{-1} gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, 1.0, p->P, p->W, 0.0, HiW); gsl_blas_dgemm (CblasTrans, CblasNoTrans, 1.0, p->W, HiW, 0.0, WtHiW); gsl_permutation * pmt2=gsl_permutation_alloc (n_cvt); LUDecomp (WtHiW, pmt2, &sig); LUInvert (WtHiW, pmt2, WtHiWi); gsl_permutation_free(pmt2); gsl_blas_dgemm (CblasNoTrans, CblasTrans, 1.0, WtHiWi, HiW, 0.0, WtHiWiWtHi); gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, -1.0, HiW, WtHiWiWtHi, 1.0, p->P); //calculate Py, KPy, PKPy gsl_blas_dgemv(CblasNoTrans, 1.0, p->P, p->y, 0.0, p->Py); for (size_t i=0; iKPy_mat, i); gsl_vector_view PKPy=gsl_matrix_column (p->PKPy_mat, i); if (i==n_vc) { gsl_vector_memcpy (&KPy.vector, p->Py); } else { gsl_matrix_const_view K_sub=gsl_matrix_const_submatrix (p->K, 0, n1*i, n1, n1); gsl_blas_dgemv(CblasNoTrans, 1.0, &K_sub.matrix, p->Py, 0.0, &KPy.vector); } gsl_blas_dgemv(CblasNoTrans, 1.0, p->P, &KPy.vector, 0.0, &PKPy.vector); } gsl_matrix_free (K_temp); gsl_matrix_free (HiW); gsl_matrix_free (WtHiW); gsl_matrix_free (WtHiWi); gsl_matrix_free (WtHiWiWtHi); return; } //below are functions for AI algorithm int LogRL_dev1 (const gsl_vector *log_sigma2, void *params, gsl_vector *dev1) { VC_PARAM *p=(VC_PARAM *) params; size_t n1=(p->K)->size1, n_vc=log_sigma2->size-1; double tr, d; //update parameters UpdateParam (log_sigma2, p); //calculate dev1=-0.5*trace(PK_i)+0.5*yPKPy for (size_t i=0; iP, l, l); } } else { tr=0; for (size_t l=0; lP, l); gsl_vector_const_view K_col=gsl_matrix_const_column (p->K, n1*i+l); gsl_blas_ddot(&P_row.vector, &K_col.vector, &d); tr+=d; } } gsl_vector_view KPy_i=gsl_matrix_column (p->KPy_mat, i); gsl_blas_ddot(p->Py, &KPy_i.vector, &d); d=(-0.5*tr+0.5*d)*exp(gsl_vector_get(log_sigma2, i)); gsl_vector_set(dev1, i, d); } return GSL_SUCCESS; } int LogRL_dev2 (const gsl_vector *log_sigma2, void *params, gsl_matrix *dev2) { VC_PARAM *p=(VC_PARAM *) params; size_t n_vc=log_sigma2->size-1; double d, sigma2_i, sigma2_j; //update parameters UpdateParam (log_sigma2, p); //calculate dev2=0.5(yPKPKPy) for (size_t i=0; iKPy_mat, i); sigma2_i=exp(gsl_vector_get(log_sigma2, i)); for (size_t j=i; jPKPy_mat, j); gsl_blas_ddot(&KPy_i.vector, &PKPy_j.vector, &d); sigma2_j=exp(gsl_vector_get(log_sigma2, j)); d*=-0.5*sigma2_i*sigma2_j; gsl_matrix_set(dev2, i, j, d); if (j!=i) {gsl_matrix_set(dev2, j, i, d);} } } gsl_matrix_memcpy (p->Hessian, dev2); return GSL_SUCCESS; } int LogRL_dev12 (const gsl_vector *log_sigma2, void *params, gsl_vector *dev1, gsl_matrix *dev2) { VC_PARAM *p=(VC_PARAM *) params; size_t n1=(p->K)->size1, n_vc=log_sigma2->size-1; double tr, d, sigma2_i, sigma2_j; //update parameters UpdateParam (log_sigma2, p); //calculate dev1=-0.5*trace(PK_i)+0.5*yPKPy //calculate dev2=0.5(yPKPKPy) for (size_t i=0; iP, l, l); } } else { tr=0; for (size_t l=0; lP, l); gsl_vector_const_view K_col=gsl_matrix_const_column (p->K, n1*i+l); gsl_blas_ddot(&P_row.vector, &K_col.vector, &d); tr+=d; } } gsl_vector_view KPy_i=gsl_matrix_column (p->KPy_mat, i); gsl_blas_ddot(p->Py, &KPy_i.vector, &d); sigma2_i=exp(gsl_vector_get(log_sigma2, i)); d=(-0.5*tr+0.5*d)*sigma2_i; gsl_vector_set(dev1, i, d); for (size_t j=i; jPKPy_mat, j); gsl_blas_ddot(&KPy_i.vector, &PKPy_j.vector, &d); sigma2_j=exp(gsl_vector_get(log_sigma2, j)); d*=-0.5*sigma2_i*sigma2_j; gsl_matrix_set(dev2, i, j, d); if (j!=i) {gsl_matrix_set(dev2, j, i, d);} } } gsl_matrix_memcpy (p->Hessian, dev2); return GSL_SUCCESS; } void VC::CalcVCreml (const gsl_matrix *K, const gsl_matrix *W, const gsl_vector *y) { size_t n1=K->size1, n2=K->size2; size_t n_vc=n2/n1; gsl_vector *log_sigma2=gsl_vector_alloc (n_vc+1); double d, s; //set up params gsl_matrix *P=gsl_matrix_alloc (n1, n1); gsl_vector *Py=gsl_vector_alloc (n1); gsl_matrix *KPy_mat=gsl_matrix_alloc (n1, n_vc+1); gsl_matrix *PKPy_mat=gsl_matrix_alloc (n1, n_vc+1); gsl_vector *dev1=gsl_vector_alloc (n_vc+1); gsl_matrix *dev2=gsl_matrix_alloc (n_vc+1, n_vc+1); gsl_matrix *Hessian=gsl_matrix_alloc (n_vc+1, n_vc+1); VC_PARAM params={K, W, y, P, Py, KPy_mat, PKPy_mat, Hessian}; //initialize sigma2/log_sigma2 gsl_blas_ddot (y, y, &s); s/=(double)n1; for (size_t i=0; if, 1e-3); } while (status==GSL_CONTINUE && iterf, ¶ms, dev1, dev2); gsl_permutation * pmt=gsl_permutation_alloc (n_vc+1); LUDecomp (dev2, pmt, &sig); LUInvert (dev2, pmt, Hessian); gsl_permutation_free(pmt); //save data v_sigma2.clear(); for (size_t i=0; ix, i)); v_sigma2.push_back(d); } v_se_sigma2.clear(); for (size_t i=0; i