Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • tadah/models
1 result
Show changes
Commits on Source (3)
#ifndef M_EA_H #ifndef M_EA_H
#define M_EA_H #define M_EA_H
#include "../LIBS/Eigen/Dense"
#include "../CORE/config/config.h" #include "../CORE/config/config.h"
#include "../CORE/eigen_types.h" #include "svd.h"
#include "ridge_regression.h"
#include "../CORE/core_types.h"
#include "../CORE/lapack.h"
class EA { class EA {
private: private:
Config &config; const Config &config;
const SVD &svd;
const t_type &T;
int verbose; int verbose;
public: public:
EA(Config &c): EA(const Config &c, const SVD &svd, const t_type &T):
config(c), config(c),
svd(svd),
T(T),
verbose(c.get<int>("VERBOSE")) verbose(c.get<int>("VERBOSE"))
{} {}
int run (const mat &Phi,const vec &T, int run(double &alpha, double &beta) {
const mat &S, const mat &U,const mat &V,
double &alpha, double &beta) {
// Phi = USV^T // Phi = USV^T
size_t N=Phi.rows(); size_t N=svd.shapeA().first;
size_t maxsteps=40; size_t maxsteps=40;
const double EPS2 = 5e-12; const double EPS2 = 5e-12;
int convergence_status = 1; int convergence_status = 1;
...@@ -31,40 +34,41 @@ class EA { ...@@ -31,40 +34,41 @@ class EA {
size_t counter=0; size_t counter=0;
double lambda = alpha/beta; double lambda = alpha/beta;
double *s = svd.getS();
// square of the S matrix contains all eigenvalues // square of the S matrix contains all eigenvalues
// of Phi^T*Phi = (VSU^T)(USV^T) = VS^2V^T = S^2 // of Phi^T*Phi = (VSU^T)(USV^T) = VS^2V^T = S^2
const vec eval = S.array().pow(2); double *eval = new double[svd.sizeS()];
for (size_t i=0; i<svd.sizeS(); ++i)
eval[i] = s[i]*s[i];
if (verbose) printf("%9s %9s %9s %9s %9s %9s\n","del alpha", "del beta", "alpha", "beta", "lambda", "gamma"); if (verbose) printf("%9s %9s %9s %9s %9s %9s\n","del alpha", "del beta", "alpha", "beta", "lambda", "gamma");
// D is a filter factors matrix // D is a filter factors matrix
mat D(S.rows(),S.rows()); double *d = new double[svd.sizeS()];
D.setZero();
int outprec=config.get<int>("OUTPREC"); int outprec=config.get<int>("OUTPREC");
double *t = new double[svd.shapeA().first];
double *x = new double[svd.shapeA().second];
while (test1>EPS2 || test2>EPS2) { while (test1>EPS2 || test2>EPS2) {
for (long int i=0; i<S.rows(); ++i) {
double s = S(i,0);
if (s>std::numeric_limits<double>::min())
D(i,i) = (s)/(s*s+lambda);
else
D(i,i) = 0.0;
}
// regularised least square problem (Tikhonov Regularization): // regularised least square problem (Tikhonov Regularization):
vec m_n = V*D*U.transpose()*T; t_type m_n((size_t)svd.sizeS());
RidgeRegression::solve(svd,T,m_n,lambda);
double gamma = 0.0; double gamma = 0.0;
for (long int j=0; j<S.rows(); j++) { for (size_t j=0; j<svd.sizeS(); j++) {
// exlude eigenvalues which are smaller than ~1e-10 if (beta*eval[j] > std::numeric_limits<double>::min()) {
// for numerical stability b/c matrix is not regularized gamma += (beta*eval[j])/(beta*eval[j]+alpha);
if (beta*eval(j) > std::numeric_limits<double>::min()) {
gamma += (beta*eval(j))/(beta*eval(j)+alpha);
} }
} }
alpha = gamma / m_n.dot(m_n); alpha = gamma / (m_n*m_n);
double temp = (T-Phi*m_n).dot(T-Phi*m_n); t_type Tpred = svd.predict(m_n,t,x);
double temp = (T-Tpred)*(T-Tpred);
//double temp = (T-U*S.asDiagonal()*V.transpose()*m_n).dot(T-U*S.asDiagonal()*V.transpose()*m_n);
beta = (static_cast<double>(N)-gamma)/temp; beta = (static_cast<double>(N)-gamma)/temp;
test1 = fabs(alpha_old-alpha)/alpha; test1 = fabs(alpha_old-alpha)/alpha;
...@@ -82,8 +86,45 @@ class EA { ...@@ -82,8 +86,45 @@ class EA {
} }
if (convergence_status && verbose) std::cout << "Number of steps for convergence: " + to_string(counter,outprec) << std::endl; if (convergence_status && verbose) std::cout << "Number of steps for convergence: " + to_string(counter,outprec) << std::endl;
if (!convergence_status && verbose) std::cout << "Max number of steps reached: " + to_string(counter,outprec) << std::endl; if (!convergence_status && verbose) std::cout << "Max number of steps reached: " + to_string(counter,outprec) << std::endl;
delete [] eval;
delete [] d;
delete[] t;
delete[] x;
return convergence_status; return convergence_status;
};
Matrix get_sigma(double alpha, double beta) {
double *vt = svd.getVT();
double *s = svd.getS();
int n = static_cast<int>(svd.shapeVT().first);
Matrix Sigma((size_t)n,(size_t)n);
Sigma.setZero();
double *sigma = &Sigma.data()[0];
// Build P_inv matrix
for (size_t i=0; i<svd.sizeS(); ++i) {
Sigma(i,i) = 1.0/(beta*s[i]*s[i]+alpha);
}
//Sigma = V*P_inv*V.transpose();
char transa = 'T';
char transb = 'N';
double alpha_ = 1.0;
double beta_ = 0.0;
double *work = new double[n*n];
dgemm_(&transb, &transb, &n, &n, &n, &alpha_, sigma, &n, vt, &n,
&beta_, work, &n);
dgemm_(&transa, &transb, &n, &n, &n, &alpha_, vt, &n, work, &n,
&beta_, sigma, &n);
delete[] work;
return Sigma;
} }
}; };
#endif #endif
......
#ifndef EKM_H #ifndef EKM_H
#define EKM_H #define EKM_H
#include "../LIBS/Eigen/Dense"
#include "../CORE/eigen_types.h"
#include "../CORE/core_types.h" #include "../CORE/core_types.h"
template <typename K> template <typename K>
...@@ -10,17 +8,17 @@ class EKM { ...@@ -10,17 +8,17 @@ class EKM {
private: private:
K kernel; K kernel;
public: public:
Eigen::MatrixXd KK; Matrix KK;
template <typename T> template <typename T>
EKM(T &t): EKM(T &t):
kernel(t) kernel(t)
{} {}
void configure(aeds_type2 &basis) { void configure(Matrix &basis) {
// KK is temp matrix KK = Matrix(basis.cols(), basis.cols());
KK = Eigen::MatrixXd(basis.size(), basis.size());
for (long int i=0; i<KK.rows(); i++) { // Compute lower diagonal part only
for (long int j=0; j<KK.cols(); j++) { for (size_t i=0; i<KK.cols(); i++) {
for (size_t j=i+1; j<KK.cols(); j++) {
double val = kernel(basis.col(i),basis.col(j)); double val = kernel(basis.col(i),basis.col(j));
KK(i,j) = val; KK(i,j) = val;
} }
...@@ -28,21 +26,53 @@ class EKM { ...@@ -28,21 +26,53 @@ class EKM {
// KK is a kernel matrix // KK is a kernel matrix
// we compute cholesky for KK^-1 // we compute cholesky for KK^-1
// then KK = L^-1 inverse(KK);
KK = KK.inverse(); cholesky(KK,'L');
Eigen::LLT<Eigen::MatrixXd> llt(KK);
KK = llt.matrixL(); }
KK.transposeInPlace(); void inverse(Matrix &A) {
double *a = &A.data()[0];
int n = A.rows(); // A is square
int *ipiv = new int[n];
int lwork = n*n;
double *work = new double[lwork];
int info;
dgetrf_(&n,&n,a,&n,ipiv,&info);
dgetri_(&n,a,&n,ipiv,work,&lwork,&info);
delete[] ipiv;
delete[] work;
}
void cholesky(Matrix &A, char uplo) {
// matrix must be either U or L
int n = A.cols(); // A is square
double *a = &A.data()[0];
int info;
dpotrf_(&uplo, &n, a, &n, &info);
} }
void project(phi_type &Phi) { void project(phi_type &Phi) {
for (long int i=0; i<Phi.rows(); ++i) { char transa = 'N';
Phi.row(i)= KK*Phi.row(i).transpose(); char transb = 'N';
} int m = Phi.rows();
int n = Phi.cols();
double *a = &Phi.data()[0];
double *b = &KK.data()[0];
double *c = new double[m*n];
double alpha = 1.0;
double beta = 0.0;
dgemm_(&transa, &transb, &m, &n, &n, &alpha, a, &m, b, &n,
&beta, c, &m);
Phi = Matrix(c,m,n);
delete[] c;
} }
aed_type2 project(aed_type2 &aed, aeds_type2 &basis) { aed_type2 project(aed_type2 &aed, Matrix &basis) {
aed_type2 temp(basis.size()); aed_type2 temp(basis.cols());
for (long int b=0; b<basis.cols(); b++) { for (size_t b=0; b<basis.cols(); b++) {
temp(b) = kernel(aed,basis[b]); temp(b) = kernel(aed,basis[b]);
} }
return KK*temp; return KK*temp;
......
#ifndef OLS_H
#define OLS_H
#include "../CORE/core_types.h"
class OLS {
public:
template <typename M, typename V>
static void solve(M &A, V &B, V &weights) {
// A will be destroyed on exit
// B will contain solution
int m = A.rows(); //IN
int n = A.cols(); //IN
int nrhs = 1; // number of colums in B (targets T) //IN
double *a = &A.data()[0]; //IN
int lda = m;
double *b = &B.data()[0]; // IN/OUT
int ldb = std::max(m,n);
double *s = new double[std::min(m,n)]; // size: rows
double rcond = 1e-8; // 1 use machine precision
int rank;
double *work;
int lwork=-1; // QUERRY
int liwork = std::max(
0,int(std::log2(std::min(m,n)/(25+1))) + 1)
+ 11*std::min(m,n);
int smlsiz = 25;
int nlvl = std::max( 0, int( std::log2( std::min(m,n)/(smlsiz+1) ) )+1 );
int *iwork = new int[3*std::min(m,n)*nlvl + 11*std::min(m,n)];
int info;
double wkopt;
dgelsd_(&m,&n,&nrhs,a,&lda,b,&ldb,s,&rcond,&rank,
&wkopt, &lwork, iwork, &info);
lwork = (int)wkopt;
work = new double[lwork];
dgelsd_(&m,&n,&nrhs,a,&lda,b,&ldb,s,&rcond,&rank,
work, &lwork, iwork, &info);
for (size_t i=0;i<n;++i)
std::cout << B(i)<< " ";
std::cout<< std::endl;
weights = B.copy(A.cols());
delete[] s;
delete[] work;
delete[] iwork;
}
};
#endif
#ifndef RIDGE_REGRESSION_H
#define RIDGE_REGRESSION_H
#include "../CORE/core_types.h"
#include "../CORE/maths.h"
#include "../CORE/lapack.h"
#include "svd.h"
class RidgeRegression {
public:
template <typename V, typename W>
static void solve(const SVD &svd, V /*&*/T, W &weights,
const double lambda) {
double *u = svd.getU();
double *s = svd.getS();
double *vt = svd.getVT();
double *d = new double[svd.sizeS()];
for (size_t i=0; i<svd.sizeS(); ++i) {
double sv = s[i];
if (sv>std::numeric_limits<double>::min())
d[i] = (sv)/(sv*sv+lambda);
else
d[i] = 0.0;
}
int m = svd.shapeA().first;
int n = svd.shapeA().second;
int ldu = svd.shapeU().first;
int ucol = svd.shapeU().second;
int lda = m;
int ldvt = svd.shapeVT().first;
// SOLVE: V D U^T T
//STEP1: U^T T
char trans = 'T';
double alpha_ = 1.0;
double *x = &T.data()[0];
double *y = new double[lda];
int incx = 1;
double beta_ = 0.0;
dgemv_(&trans, &ldu, &ucol, &alpha_, u, &lda, x, &incx,
&beta_, y, &incx);
// STEP2 : D (U^T T)
for (int r=0; r<ldvt; ++r) {
y[r]*=d[r];
}
// STEP3: V (D U^T T)
trans='T';
dgemv_(&trans, &ldvt, &n, &alpha_, vt, &ldvt, y, &incx,
&beta_, x, &incx);
weights = t_type(x, (size_t)ldvt);
delete[] d;
delete[] y;
}
};
#endif
#ifndef SVD_H
#define SVD_H
#include "../CORE/core_types.h"
#include "../CORE/maths.h"
#include "../CORE/lapack.h"
class SVD {
/** Compute Compact SVD
*
* M = USV^T
*/
private:
char jobz = 'S'; // compute the first min(M,N) columns of U
int m;
int n;
int lda;
int ldu;
int ldvt;
int ucol;
int lwork;
int info;
// arrays
double *a = nullptr;
double *s = nullptr;
double *u = nullptr;
double *vt = nullptr;
double *work = nullptr;
int *iwork = nullptr;
bool work_alloc=false;
public:
~SVD()
{
delete[] s;
delete[] u;
delete[] vt;
if (work_alloc)
delete[] iwork;
if (work_alloc && lwork>0)
delete[] work;
}
SVD(const SVD &other)
{
std::cout << "Copy-constructor" << std::endl;
jobz = other.jobz;
m = other.m;
n = other.n;
lda = other.lda;
ldu = other.ldu;
ldvt = other.ldvt;
ucol = other.ucol;
lwork = other.lwork;
info = other.info;
// allocate all
s = new double[sizeS()];
u = new double[sizeU()];
vt = new double[sizeVT()];
// We don't need this arrays
a = nullptr;
work = nullptr;
iwork = nullptr;
work_alloc=false;
std::cout << sizeS() << std::endl;;
std::cout << sizeU() << std::endl;;
std::cout << sizeVT() << std::endl;;
// hard copy
std::memcpy(s, other.s, sizeS()*sizeof(double));
std::memcpy(u, other.u, sizeU()*sizeof(double));
std::memcpy(vt, other.vt, sizeVT()*sizeof(double));
}
//SVD &operator=(const SVD &other)
//{
// //if (this == &other)
// // return *this;
// std::cout << "Copy-assignment" << std::endl;
//}
SVD(Matrix &Phi):
m(Phi.rows()),
n(Phi.cols()),
lda(Phi.rows()),
ldu(Phi.rows()),
ldvt(std::min(m,n)),
ucol(std::min(m,n)),
a(&Phi.data()[0]),
s(new double[sizeS()]),
u(new double[sizeU()]),
vt(new double[sizeVT()]),
iwork(new int[8*std::min(m,n)]),
work_alloc(true)
{
lwork=-1; // QUERRY
double wkopt;
dgesdd_(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt,
&wkopt, &lwork, iwork, &info);
lwork = (int)wkopt;
work = new double[lwork];
dgesdd_(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt,
work, &lwork, iwork, &info);
// Filter out v.small singularvalues from S and its inverse
for (size_t i=0; i<sizeS(); ++i) {
if (s[i]<std::numeric_limits<double>::min()) {
s[i] = 0.0;
}
}
}
int get_info() const{
return info;
}
double *getA() const{
return a;
}
double *getU() const{
return u;
}
double *getVT() const{
return vt;
}
double *getS() const{
return s;
}
size_t sizeA() const {
return m*n;
}
size_t sizeU() const {
return ldu*ucol;
}
size_t sizeVT() const {
return ldvt*n;
}
size_t sizeS() const {
return std::min(m,n);
}
std::pair<size_t,size_t> shapeA() const{
return std::pair<size_t, size_t>(m,n);
}
std::pair<size_t,size_t> shapeU() const{
return std::pair<size_t, size_t>(ldu,ucol);
}
std::pair<size_t,size_t> shapeVT() const{
return std::pair<size_t, size_t>(ldvt,n);
}
std::pair<size_t,size_t> shapeS() const{
return std::pair<size_t, size_t>(std::min(m,n),1);
}
template <typename T>
T predict(const T &w) const {
/* Return U S V^T w */
double *t = new double[shapeA().first];
double *x = new double[shapeA().second];
T res = predict(w,t,x);
delete[] t;
delete[] x;
return res;
}
template <typename T>
T predict(const T &w, double *t, double *x) const {
/* Return U S V^T w */
const double *w_ptr = &w.data()[0];
// 1. V^T w
char trans='N';
int m = static_cast<int>(shapeA().first);
int n = static_cast<int>(shapeA().second);
double alpha_ = 1.0;
double beta_ = 0.0;
int incx=1;
dgemv_(&trans, &n, &n, &alpha_, vt, &n, w_ptr, &incx, &beta_, x, &incx);
// 2. S (V^T w)
for (int i=0; i<n; ++i) {
x[i]*=s[i];
}
// 3. U (S V^T w)
dgemv_(&trans, &m, &n, &alpha_, u, &m, x, &incx, &beta_, t, &incx);
return T(t,m);
}
};
#endif