Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 058917e5 authored by hhakim's avatar hhakim
Browse files

Handle save of a transpose Faust in Faust::Transform::save_mat_file() and...

Handle save of a transpose Faust in Faust::Transform::save_mat_file() and Faust::MatDense::toMatIOVar()/Faust::MatSparse::toMatIOVar().
Allow py and matlab wrappers to access the transpose case by passing a boolean to core lib.

Extends transpose unit test for py wrapper (by testing save of transpose faust).
Minor addition to code doc of nnz().
parent 1c4dd74e
No related branches found
No related tags found
No related merge requests found
Showing
with 82 additions and 35 deletions
......@@ -12,21 +12,23 @@ import math
class TestFaustPy(unittest.TestCase):
MAX_NUM_FACTORS = 64 # for the tested Faust
MAX_DIM_SIZE = 1000
def setUp(self):
""" Initializes the tests objects """
r = random.Random() # initialized from time or system
num_factors = r.randint(1, TestFaustPy.MAX_NUM_FACTORS)
factors = []
d2 = r.randint(1, 1000)
d2 = r.randint(1, TestFaustPy.MAX_DIM_SIZE)
for i in range(0, num_factors):
d1, d2 = d2, r.randint(1, 1000)
d1, d2 = d2, r.randint(1, TestFaustPy.MAX_DIM_SIZE)
factors += [sparse.random(d1, d2, density=0.1, format='csr',
dtype=np.float64).todense()]
self.F = Faust(factors)
self.factors = factors
print("Tests on random Faust with dims=", self.F.get_nb_rows(),
self.F.get_nb_cols())
print("Num. factors:", num_factors)
self.r = r
def testSave(self):
......@@ -161,7 +163,7 @@ class TestFaustPy(unittest.TestCase):
def testMul(self):
print("testMul()")
rmat = np.random.rand(self.F.get_nb_cols(),
self.r.randint(1,1000))
self.r.randint(1,TestFaustPy.MAX_DIM_SIZE))
prod = self.mulFactors()*rmat
test_prod = self.F*rmat
self.assertProdEq(prod, test_prod)
......@@ -177,6 +179,28 @@ class TestFaustPy(unittest.TestCase):
self.assertLessEqual(abs(tF[i,j]-F[j,i])/abs(F[j,i]), 10**-3)
else:
self.assertEqual(tF[i,j],0)
tmp_dir = tempfile.gettempdir()+os.sep
rand_suffix = random.Random().randint(1,1000)
test_file = tmp_dir+"A"+str(rand_suffix)+".mat"
ref_file = tmp_dir+"A"+str(rand_suffix)+"o.mat"
self.F.transpose().save(test_file)
self.F.save(ref_file)
#print("file=",test_file)
tF2 = Faust(test_file)
#print(tF2.get_nb_rows(), tF2.get_nb_cols())
#print(self.F.get_nb_rows(), self.F.get_nb_cols())
self.assertEqual(tF2.get_nb_cols(), tF.shape[1])
self.assertEqual(tF2.get_nb_rows(), tF.shape[0])
tF2 = tF2.todense()
for i in range(0, tF.shape[0]):
for j in range(0, tF.shape[1]):
if(F[j,i] != 0):
self.assertLessEqual(abs(tF2[i,j]-F[j,i])/abs(F[j,i]),
10**-12)
else:
self.assertEqual(tF2[i,j],0)
os.remove(test_file)
os.remove(ref_file)
def testSize(self):
print("testSize()")
......
......@@ -374,7 +374,7 @@ void spgemm(const Faust::MatSparse<FPP,Cpu> & A,const Faust::MatDense<FPP,Cpu> &
//! All the other line contains one coefficient in ColMajor access of the MatDense
void print_file(const char* filename)const;
matvar_t* toMatIOVar() const;
matvar_t* toMatIOVar(bool transpose) const;
void operator=(MatDense<FPP,Cpu> const& A);
......
......@@ -51,7 +51,7 @@
#include <Eigen/SparseCore>
#include "faust_exception.h"
#include "faust_constant.h"
#include <cassert>
#ifdef __GEMM_WITH_OPENBLAS__
#include "faust_cblas_algebra.h"
#endif
......@@ -690,12 +690,25 @@ t_print_file.stop();
}
template<typename FPP>
matvar_t* Faust::MatDense<FPP, Cpu>::toMatIOVar() const
matvar_t* Faust::MatDense<FPP, Cpu>::toMatIOVar(bool transpose) const
{
matvar_t *var = NULL; //TODO: should be nullptr in C++11
size_t dims[2] = {this->getNbRow(), this->getNbCol()};
//we don't copy the data again, we use it directly (row-major order organized)
var = Mat_VarCreate(NULL, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, (FPP*) mat.data(), 0);
size_t dims[2];
if(transpose)
{
dims[0] = this->getNbCol();
dims[1] = this->getNbRow();
Eigen::Matrix<FPP, Eigen::Dynamic, Eigen::Dynamic> mat_copy(mat.transpose().eval());
// mat_copy.transposeInPlace(); //undo the transposition
var = Mat_VarCreate(NULL, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, (FPP*) mat_copy.data() /*mat.transpose().eval().data() // doesn't work so we copy above */, 0);
}
else
{
dims[0] = this->getNbRow();
dims[1] = this->getNbCol();
var = Mat_VarCreate(NULL, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, (FPP*) mat.data(), 0);
}
//we don't copy the data again, we use it directly (col-major order organized)
return var;
}
......
......@@ -250,7 +250,7 @@ namespace Faust
//! M = (*this) * M if opThis='N'
// M = (*this)' * M if opThis='T'
void multiply(Faust::MatDense<FPP,Cpu> & M, char opThis) const;
matvar_t* toMatIOVar() const;
matvar_t* toMatIOVar(bool transpose) const;
//! Destructor
~MatSparse(){/*std::cout<<"destructor MatSparse"<<std::endl;*//*this->mat.resize(0,0);*/}
......
......@@ -563,13 +563,13 @@ void Faust::MatSparse<FPP,Cpu>::init_from_file(const char* filename)
}
template<typename FPP>
matvar_t* Faust::MatSparse<FPP, Cpu>::toMatIOVar() const
matvar_t* Faust::MatSparse<FPP, Cpu>::toMatIOVar(bool transpose) const
{
matvar_t *var = NULL; //TODO: should be nullptr in C++11
Faust::MatDense<FPP,Cpu> dense_factor;
//TODO: shouldn't be processed as dense factor, we lose compression of sparse matrix here
dense_factor = (*this); //data is copied with operator = redef.
var = dense_factor.toMatIOVar();
var = dense_factor.toMatIOVar(transpose);
return var;
}
......
......@@ -134,9 +134,10 @@ namespace Faust
/**
* \brief Writes the FAuST into a Matlab file. The product is written as a cell array with the matrix factors as elements.
* \arg \c filename The filepath to the output file (preferably with a .mat suffix).
* \arg \c transpose The boolean to set to true if you want to save the transpose Faust of this instance or false otherwise.
* \throw std::logic_error if any problem occurs.
*/
void save_mat_file(const char* filename) const;
void save_mat_file(const char* filename, bool transpose) const;
long long int get_total_nnz()const{return totalNonZeros;}
void clear(){data.resize(0);totalNonZeros=0;}
......
......@@ -248,16 +248,18 @@ void Faust::Transform<FPP,Cpu>::print_file(const char* filename) const
}
template<typename FPP>
void Faust::Transform<FPP, Cpu>::save_mat_file(const char* filename) const
void Faust::Transform<FPP, Cpu>::save_mat_file(const char* filename, bool transpose) const
{
// save the FAuST as a matlab cell array (respecting what is done in matlab wrapper)
matvar_t *faust_matvar;
size_t dims[2];
int i, ret;
int i, i2, ret;
mat_t *matfp;
matvar_t **faust_factor_matvars = new matvar_t*[size()];
for(i=0; i < size(); i++){
faust_factor_matvars[i] = data[i]->toMatIOVar();
// revert factors order if we are in transpose case
i2 = transpose?size()-i-1:i;
faust_factor_matvars[i] = data[i2]->toMatIOVar(transpose);
if(faust_factor_matvars[i] == NULL)
handleError("Faust::Transform", "Failed to create i-th factor MatIO variable");
}
......
......@@ -139,9 +139,10 @@ namespace Faust
virtual void Display() const=0;
//! \brief Converts the Matrix to a matio variable, especially useful for writing into a file with libmatio.
// \param transpose : set to true to obtain the matio variable for the transpose Matrix.
// \return The matio variable matvar_t if it succeeded or nullptr otherwise.
// \see Faust::Transform::save_mat_file()
virtual matvar_t* toMatIOVar() const=0;
virtual matvar_t* toMatIOVar(bool transpose) const=0;
//! \brief
//! \warning : declare a virtual destructor is mandatory for an abstract class
......
......@@ -473,9 +473,9 @@ classdef Faust
%
% save(F,filename) saves the Faust F into the .mat file specified by filename.
if(F.isReal)
mexFaustReal('save', F.matrix.objectHandle, filename)
mexFaustReal('save', F.matrix.objectHandle, filename, F.transpose_flag)
else
mexFaustCplx('save', F.matrix.objectHandle, filename)
mexFaustCplx('save', F.matrix.objectHandle, filename, F.transpose_flag)
end
end
......
......@@ -72,21 +72,23 @@
typedef @FAUST_SCALAR@ SCALAR;
void save(Faust::Transform<SCALAR,Cpu>* core_ptr, int nargs, const mxArray *args)
void save(Faust::Transform<SCALAR,Cpu>* core_ptr, int nargs, const mxArray **args)
{
size_t MAX_PATH_SIZE=512;
char filepath[MAX_PATH_SIZE];
// args must be the filepath
if(nargs != 1){
mexErrMsgTxt("The number of arguments for the save function is not valid.");
return;
}
if(mxGetString(args, filepath, sizeof(filepath)) || strlen(filepath) == 0){
// args[0] must be the filepath
// args[1] must be the boolean for tranposing or not at write time
// nargs the number of arguments in args (must be 2)
if(nargs != 2){
mexErrMsgTxt("The number of arguments for the save function is not valid.");
return;
}
if(mxGetString(args[0], filepath, sizeof(filepath)) || strlen(filepath) == 0){
mexErrMsgTxt("The filepath is not valid.");
return;
}
// printf("save: filepath = %s, nargs = %d\n", filepath, nargs);
core_ptr->save_mat_file(filepath);
core_ptr->save_mat_file(filepath, mxGetScalar(args[1]));
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
......@@ -449,7 +451,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
if(!strcmp("save", cmd))
return save(convertMat2Ptr<Faust::Transform<SCALAR,Cpu> >(prhs[1]), nrhs-2, prhs[2]);
return save(convertMat2Ptr<Faust::Transform<SCALAR,Cpu> >(prhs[1]), nrhs-2, &prhs[2]);
// // Call the various class methods
......
......@@ -192,6 +192,10 @@ class Faust:
"""
Gives the number of non-zero elements in the Faust.
The function sums together the number of non-zeros elements of
each factor and returns the result. Note that in fact the sum is
computed at Faust creation time and kept in cache.
Returns:
The number of non-zero elements as an integer.
......@@ -313,4 +317,4 @@ class Faust:
if(format not in ["Matlab"]):
raise ValueError("Only Matlab or Matlab_core format is supported.")
if(format == "Matlab"):
F.m_faust.save_mat_file(filepath)
F.m_faust.save_mat_file(filepath, F.m_transpose_flag)
......@@ -69,7 +69,7 @@ class FaustCoreCpp
unsigned int get_fact_nb_rows(unsigned int& i) const;
unsigned int get_fact_nb_cols(unsigned int& i) const;
void get_fact(unsigned int& i, FPP* fact_ptr) const;
void save_mat_file(const char* filepath) const;
void save_mat_file(const char* filepath, bool transpose_flag) const;
private :
Faust::Transform<FPP,Cpu> transform;
};
......
......@@ -200,8 +200,8 @@ void FaustCoreCpp<FPP>::get_fact(unsigned int& i, FPP* fact_ptr) const
}
template<typename FPP>
void FaustCoreCpp<FPP>::save_mat_file(const char* filepath) const
void FaustCoreCpp<FPP>::save_mat_file(const char* filepath, bool transpose_flag) const
{
// std::cout << "FaustCoreCpp::save_mat_file()" << std::endl;
this->transform.save_mat_file(filepath);
this->transform.save_mat_file(filepath, transpose_flag);
}
......@@ -54,4 +54,4 @@ cdef extern from "FaustCoreCpp.h" :
unsigned int get_fact_nb_rows(unsigned int& i) const;
unsigned int get_fact_nb_cols(unsigned int& i) const;
double get_fact(unsigned int& i, FPP* fact_ptr) const;
void save_mat_file(const char* filepath) const;
void save_mat_file(const char* filepath, bool transpose_flag) const;
......@@ -196,12 +196,12 @@ cdef class FaustCore:
self.m_faust.get_fact(i, &fact_view[0, 0])
return fact
def save_mat_file(self,filepath):
def save_mat_file(self,filepath, transpose_flag):
cdef char * cfilepath = <char*> PyMem_Malloc(sizeof(char) *
(len(filepath)+1))
fparr = bytearray(filepath, "UTF-8");
for i in range(0,len(filepath)):
cfilepath[i] = fparr[i]
cfilepath[i+1] = 0
self.m_faust.save_mat_file(cfilepath)
self.m_faust.save_mat_file(cfilepath, transpose_flag)
PyMem_Free(cfilepath)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment