Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,14 @@ As such, I can probably help out with small stuff, but for technical and theoret
You can find the original swig wrapper to re-generate these files on the branch swig_generator at https://github.com/samuelstjean/spams-python/tree/swig_generator

This (unofficial) version includes pre-built wheels for python 3 on windows, mac (with openmp support) and linux and can be installed with ``pip install spams-bin``.

# Improvements from the original version

+ Automatic build system with meson
+ Pytest for testing
+ Newer swig wrappers
+ Fixed internal naming clash for newer openmp namespace and the orthogonal matching pursuit (omp) function
+ Fixed C++20 deprecation issues with templates
+ Fixed undefined behavior with openmp and passing 0 as the number of cores (it now defaults to 1)
+ Fixed a positivity bug with spams.lassoWeighted
+ Probably other stuff
4 changes: 2 additions & 2 deletions spams_wrap/spams.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,10 @@ SpMatrix<T> *_omp(Matrix<T> *X,Matrix<T> *D,Matrix<T> **path,bool return_reg_pat
if(return_reg_path) {
*path = new Matrix<T>(K,scalar_L);
(*path)->setZeros();
omp((Matrix<T> &)(*X),(Matrix<T> &)(*D),(SpMatrix<T> &)(*alpha),pL,pE,pLambda,vecL,vecEps,vecLambda,numThreads,*path);
ompursuit((Matrix<T> &)(*X),(Matrix<T> &)(*D),(SpMatrix<T> &)(*alpha),pL,pE,pLambda,vecL,vecEps,vecLambda,numThreads,*path);
} else {
*path = NULL;
omp((Matrix<T> &)(*X),(Matrix<T> &)(*D),(SpMatrix<T> &)(*alpha),pL,pE,pLambda,vecL,vecEps,vecLambda,numThreads);
ompursuit((Matrix<T> &)(*X),(Matrix<T> &)(*D),(SpMatrix<T> &)(*alpha),pL,pE,pLambda,vecL,vecEps,vecLambda,numThreads);
}
return alpha;
}
Expand Down
4 changes: 2 additions & 2 deletions spams_wrap/spams/decomp/decomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static char nonUnit='n';
/// * optimized for a large number of signals (precompute the Gramm matrix

template <typename T>
void omp(const Matrix<T>& X, const Matrix<T>& D, SpMatrix<T>& spalpha,
void ompursuit(const Matrix<T>& X, const Matrix<T>& D, SpMatrix<T>& spalpha,
const int *L, const T* eps, const T* lambda, const bool vecL = false,
const bool vecEps = false, const bool Lambda=false, const int numThreads=-1,
Matrix<T>* path = NULL);
Expand Down Expand Up @@ -320,7 +320,7 @@ void coreSOMP(const Matrix<T>& X, const Matrix<T>& D, const Matrix<T>& G,
/// * optimized for a big number of signals (precompute the Gramm matrix

template <typename T>
void omp(const Matrix<T>& X, const Matrix<T>& D, SpMatrix<T>& spalpha,
void ompursuit(const Matrix<T>& X, const Matrix<T>& D, SpMatrix<T>& spalpha,
const int* pL, const T* peps, const T* pLambda,
const bool vecL, const bool vecEps,
const bool vecLambda, const int numThreads, Matrix<T>* path) {
Expand Down
89 changes: 44 additions & 45 deletions spams_wrap/spams/dictLearn/dicts.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

/* Software SPAMS v2.1 - Copyright 2009-2011 Julien Mairal
/* Software SPAMS v2.1 - Copyright 2009-2011 Julien Mairal
*
* This file is part of SPAMS.
*
Expand Down Expand Up @@ -70,7 +70,7 @@ void regul_error(char *buffer, int bufsize,const char *message) {
// calculate size
for(unsigned int i = 0;i < NBREGUL;i++)
size += strlen(regul_table[i].name) + 1;
}
}
if (size >= bufsize) {
n1 = bufsize - 1;
strncpy(buffer,"Invalid regularization\n",n1);
Expand All @@ -90,7 +90,7 @@ void regul_error(char *buffer, int bufsize,const char *message) {

template <typename T> struct ParamDictLearn {
public:
ParamDictLearn() :
ParamDictLearn() :
mode(PENALTY),
regul(FISTA::RIDGE),
tol(1.e-4),
Expand Down Expand Up @@ -131,7 +131,7 @@ template <typename T> struct ParamDictLearn {
updateD(true),
updateW(true),
updateTheta(true),
logName(NULL),
logName(NULL),
iter_updateD(1) { };
~ParamDictLearn() { delete[](logName); };
int iter;
Expand All @@ -141,7 +141,7 @@ template <typename T> struct ParamDictLearn {
T tol;
bool ista;
bool fixed_step;
bool posAlpha;
bool posAlpha;
constraint_type_D modeD;
bool posD;
mode_compute modeParam;
Expand Down Expand Up @@ -192,17 +192,17 @@ template <typename T> class Trainer {
const int NUM_THREADS=-1);
/// Constructor with existing structure
Trainer(const Matrix<T>& A, const Matrix<T>& B, const Matrix<T>& D,
const int itercount, const int batchsize,
const int itercount, const int batchsize,
const int NUM_THREADS);

/// train or retrain using the matrix X
/* train with graph or tree */
void train(const Data<T>& X, const ParamDictLearn<T>& param);
void train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
const GraphStruct<T>* graph_st = NULL,
const GraphStruct<T>* graph_st = NULL,
const TreeStruct<T>* tree_st = NULL);
void trainOffline(const Data<T>& X, const ParamDictLearn<T>& param);

/// Accessors
void getA(Matrix<T>& A) const { A.copy(_A);};
void getB(Matrix<T>& B) const { B.copy(_B);};
Expand All @@ -211,14 +211,14 @@ template <typename T> class Trainer {

private:
/// Forbid lazy copies
explicit Trainer<T>(const Trainer<T>& trainer);
explicit Trainer(const Trainer<T>& trainer);
/// Forbid lazy copies
Trainer<T>& operator=(const Trainer<T>& trainer);

/// clean the dictionary
void cleanDict(const Data<T>& X, Matrix<T>& G,
const bool posD = false,
const constraint_type_D modeD = L2, const T gamma1 = 0,
const constraint_type_D modeD = L2, const T gamma1 = 0,
const T gamma2 = 0,
const T maxCorrel =
0.999999);
Expand All @@ -238,7 +238,7 @@ template <typename T> class Trainer {

/// Empty constructor
template <typename T> Trainer<T>::Trainer() : _k(0), _initialDict(false),
_itercount(0), _batchsize(256) {
_itercount(0), _batchsize(256) {
_NUM_THREADS=1;
#ifdef _OPENMP
_NUM_THREADS = MIN(MAX_THREADS,omp_get_num_procs());
Expand All @@ -248,9 +248,9 @@ template <typename T> Trainer<T>::Trainer() : _k(0), _initialDict(false),

/// Constructor with data
template <typename T> Trainer<T>::Trainer(const int k, const
int batchsize, const int NUM_THREADS) : _k(k),
_initialDict(false), _itercount(0),_batchsize(batchsize),
_NUM_THREADS(NUM_THREADS) {
int batchsize, const int NUM_THREADS) : _k(k),
_initialDict(false), _itercount(0),_batchsize(batchsize),
_NUM_THREADS(NUM_THREADS) {
if (_NUM_THREADS == -1) {
_NUM_THREADS=1;
#ifdef _OPENMP
Expand All @@ -260,7 +260,7 @@ template <typename T> Trainer<T>::Trainer(const int k, const
};

/// Constructor with initial dictionary
template <typename T> Trainer<T>::Trainer(const Matrix<T>& D,
template <typename T> Trainer<T>::Trainer(const Matrix<T>& D,
const int batchsize, const int NUM_THREADS) : _k(D.n()),
_initialDict(true),_itercount(0),_batchsize(batchsize),
_NUM_THREADS(NUM_THREADS) {
Expand All @@ -277,7 +277,7 @@ template <typename T> Trainer<T>::Trainer(const Matrix<T>& D,

/// Constructor with existing structure
template <typename T> Trainer<T>::Trainer(const Matrix<T>& A, const Matrix<T>&
B, const Matrix<T>& D, const int itercount, const int batchsize,
B, const Matrix<T>& D, const int itercount, const int batchsize,
const int NUM_THREADS) : _k(D.n()),_initialDict(true),_itercount(itercount),
_batchsize(batchsize),
_NUM_THREADS(NUM_THREADS) {
Expand All @@ -293,7 +293,7 @@ template <typename T> Trainer<T>::Trainer(const Matrix<T>& A, const Matrix<T>&
};

template <typename T>
void Trainer<T>::cleanDict(const Data<T>& X, Matrix<T>& G,
void Trainer<T>::cleanDict(const Data<T>& X, Matrix<T>& G,
const bool posD,
const constraint_type_D modeD, const T gamma1,
const T gamma2,
Expand Down Expand Up @@ -364,9 +364,9 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
cout << "Online Dictionary Learning with exponential decay t0: " << t0 << " rho: " << rho << endl;
}
}
if (param.posD)
if (param.posD)
cout << "Positivity constraints on D activated" << endl;
if (param.posAlpha)
if (param.posAlpha)
cout << "Positivity constraints on alpha activated" << endl;
if (param.modeD != L2) cout << "Sparse dictionaries, mode: " << param.modeD << ", gamma1: " << param.gamma1 << ", gamma2: " << param.gamma2 << endl;
cout << "mode Alpha " << param.mode << endl;
Expand All @@ -385,7 +385,7 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
const int M = X.n();
const int K = _k;
const int n = X.m();
const int L = param.mode == SPARSITY ? static_cast<int>(param.lambda) :
const int L = param.mode == SPARSITY ? static_cast<int>(param.lambda) :
param.mode == PENALTY && param.lambda == 0 && param.lambda2 > 0 && !param.posAlpha ? K : MIN(n,K);
const int batchsize= param.batch ? M : MIN(_batchsize,M);

Expand All @@ -397,7 +397,7 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
flush(cout);
}

if (_D.m() != n || _D.n() != K)
if (_D.m() != n || _D.n() != K)
_initialDict=false;

srandom(0);
Expand Down Expand Up @@ -509,7 +509,7 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
flush(cout);
}
time.stop();
if (param.iter < 0 &&
if (param.iter < 0 &&
time.getElapsed() > T(-param.iter)) break;
if (param.log) {
int seconds=static_cast<int>(floor(log(time.getElapsed())*5));
Expand All @@ -522,10 +522,10 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
}
}
time.start();

Matrix<T> G;
_D.XtX(G);
if (param.clean)
if (param.clean)
this->cleanDict(X,G,param.posD,
param.modeD,param.gamma1,param.gamma2);
G.addDiag(MAX(param.lambda2,1e-10));
Expand Down Expand Up @@ -591,7 +591,7 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
}
}
int count2=0;
for (int k = 0; k<L; ++k)
for (int k = 0; k<L; ++k)
if (ind[k] == -1) {
break;
} else {
Expand Down Expand Up @@ -696,8 +696,8 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
Beven.scal(scal);
Aodd.scal(scal);
Bodd.scal(scal);
if ((_itercount > 0 && i*batchsize < M)
|| (_itercount == 0 && t0 != 0 &&
if ((_itercount > 0 && i*batchsize < M)
|| (_itercount == 0 && t0 != 0 &&
i*batchsize < 10000)) {
Aorig.scal(scal);
Borig.scal(scal);
Expand Down Expand Up @@ -738,7 +738,7 @@ void Trainer<T>::train(const Data<T>& X, const ParamDictLearn<T>& param) {
newd.normalize2();
di.copy(newd);
}
} else if (param.clean &&
} else if (param.clean &&
((_itercount+i)*batchsize) > 10000) {
_D.refCol(k,di);
di.setZeros();
Expand Down Expand Up @@ -786,9 +786,9 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
cout << "Online Dictionary Learning with exponential decay t0: " << t0 << " rho: " << rho << endl;
}
}
if (param.posD)
if (param.posD)
cout << "Positivity constraints on D activated" << endl;
if (param.posAlpha)
if (param.posAlpha)
cout << "Positivity constraints on alpha activated" << endl;
if (param.modeD != L2) cout << "Sparse dictionaries, mode: " << param.modeD << ", gamma1: " << param.gamma1 << ", gamma2: " << param.gamma2 << endl;
cout << "mode Alpha " << param.mode << endl;
Expand All @@ -807,7 +807,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
const int M = X.n();
const int K = _k;
const int n = X.m();
const int L = param.mode == SPARSITY ? static_cast<int>(param.lambda) :
const int L = param.mode == SPARSITY ? static_cast<int>(param.lambda) :
param.mode == PENALTY && param.lambda == 0 && param.lambda2 > 0 && !param.posAlpha ? K : MIN(n,K);
const int batchsize= param.batch ? M : MIN(_batchsize,M);

Expand All @@ -819,7 +819,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
flush(cout);
}

if (_D.m() != n || _D.n() != K)
if (_D.m() != n || _D.n() != K)
_initialDict=false;

srandom(0);
Expand Down Expand Up @@ -958,7 +958,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
flush(cout);
}
time.stop();
if (param.iter < 0 &&
if (param.iter < 0 &&
time.getElapsed() > T(-param.iter)) break;
if (param.log) {
int seconds=static_cast<int>(floor(log(time.getElapsed())*5));
Expand All @@ -971,10 +971,10 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
}
}
time.start();

// !! Matrix<T> G;
_D.XtX(G);
if (param.clean)
if (param.clean)
this->cleanDict(X,G,param.posD,
param.modeD,param.gamma1,param.gamma2);
G.addDiag(MAX(param.lambda2,1e-10));
Expand Down Expand Up @@ -1038,7 +1038,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
losses[numT]->init(Xj);
regularizers[numT]->reset();
// alpha.refCol(j,alphai);
FISTA::FISTA_Generic(*(losses[numT]),*(regularizers[numT]),alpha0i,alphai,optim_infoi,param_fista);
FISTA::FISTA_Generic(*(losses[numT]),*(regularizers[numT]),alpha0i,alphai,optim_infoi,param_fista);
alphai.toSparse(spcoeffj);
} else {
if (param.mode == SPARSITY) {
Expand All @@ -1051,7 +1051,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
}
if(param.mode != FISTAMODE) {
INTM count2=0;
for (int k = 0; k<L; ++k)
for (int k = 0; k<L; ++k)
if (ind[k] == -1) {
break;
} else {
Expand Down Expand Up @@ -1157,8 +1157,8 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
Beven.scal(scal);
Aodd.scal(scal);
Bodd.scal(scal);
if ((_itercount > 0 && i*batchsize < M)
|| (_itercount == 0 && t0 != 0 &&
if ((_itercount > 0 && i*batchsize < M)
|| (_itercount == 0 && t0 != 0 &&
i*batchsize < 10000)) {
Aorig.scal(scal);
Borig.scal(scal);
Expand Down Expand Up @@ -1199,7 +1199,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,
newd.normalize2();
di.copy(newd);
}
} else if (param.clean &&
} else if (param.clean &&
((_itercount+i)*batchsize) > 10000) {
_D.refCol(k,di);
di.setZeros();
Expand Down Expand Up @@ -1234,7 +1234,7 @@ void Trainer<T>::train_fista(const Data<T>& X, const ParamDictLearn<T>& param,


template <typename T>
void writeLog(const Matrix<T>& D, const T time, int iter,
void writeLog(const Matrix<T>& D, const T time, int iter,
char* name) {
std::ofstream f;
f.precision(12);
Expand All @@ -1253,7 +1253,7 @@ void writeLog(const Matrix<T>& D, const T time, int iter,


template <typename T>
void Trainer<T>::trainOffline(const Data<T>& X,
void Trainer<T>::trainOffline(const Data<T>& X,
const ParamDictLearn<T>& param) {

int sparseD = param.modeD == L1L2 ? 2 : 6;
Expand Down Expand Up @@ -1335,7 +1335,7 @@ void Trainer<T>::trainOffline(const Data<T>& X,
for (int i = 0; i<JJ; ++i) {
if (J < 0 && time.getElapsed() > T(-J)) break;
_D.XtX(G);
if (param.clean)
if (param.clean)
this->cleanDict(X,G,param.posD,
param.modeD,param.gamma1,param.gamma2);
int j;
Expand Down Expand Up @@ -1433,7 +1433,7 @@ void Trainer<T>::trainOffline(const Data<T>& X,
}
}
_D.XtX(G);
if (param.clean)
if (param.clean)
this->cleanDict(X,G,param.posD,param.modeD,
param.gamma1,param.gamma2);
time.printElapsed();
Expand All @@ -1447,4 +1447,3 @@ void Trainer<T>::trainOffline(const Data<T>& X,


#endif

Loading
Loading