Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 9a2a3051 authored by hhakim's avatar hhakim
Browse files

Implement the mul. of two Fausts in C++ and bind py. wrapper to this impl.

- Fix by the way FaustCoreCpp::to_string(), avoiding to use directly c_str() on the result of iostringstream::str() like described in the notes here: https://en.cppreference.com/w/cpp/io/basic_ostringstream/str. It actually made strange results, empty strings and utf-8 decoding error.
parent 23e012df
Branches
Tags
No related merge requests found
......@@ -99,6 +99,7 @@ namespace Faust
Transform(const Transform<FPP,Cpu> & A);
Transform(const Transform<FPP, Cpu>* A, const bool transpose_A, const bool conj_A, const Transform<FPP, Cpu>* B, const bool transpose_B, const bool conj_B);
/** \brief
* check the factors validity of the faust, if the list of factors represents a valid matrix
* */
......
......@@ -210,6 +210,56 @@ Faust::Transform<FPP,Cpu>::Transform(const std::vector<Faust::MatGeneric<FPP,Cpu
this->check_factors_validity();
}
template<typename FPP>
Faust::Transform<FPP,Cpu>::Transform(const Transform<FPP, Cpu>* A, const bool transpose_A, const bool conj_A, const Transform<FPP, Cpu>* B, const bool transpose_B, const bool conj_B):
data(std::vector<Faust::MatGeneric<FPP,Cpu>*>()), totalNonZeros(0)
{
data.resize(A->size()+B->size());
int i = transpose_A?A->size()-1:0;
int j = 0;
// verification that mul. is defined between A and B is done afterward by check_factors_validity()
bool copying = A->size()>0;
//TODO: factorize the two loops
while(copying)
{
data[j] = A->data[i]->Clone(false);
if(transpose_A)
{
data[j]->transpose();
i--;
copying = i >= 0;
}
else
{
i++;
copying = i < A->size();
}
if(conj_A) data[j]->conjugate();
totalNonZeros += data[j]->getNonZeros();
j++;
}
i = transpose_B?B->size()-1:0;
copying = B->size()>0;
while(copying)
{
data[j] = B->data[i]->Clone(false);
if(transpose_B)
{
data[j]->transpose();
i--;
copying = i >= 0;
}
else
{
i++;
copying = i < B->size();
}
if(conj_B) data[j]->conjugate();
totalNonZeros += data[j]->getNonZeros();
j++;
}
this->check_factors_validity();
}
template<typename FPP>
void Faust::Transform<FPP,Cpu>::check_factors_validity() const
......@@ -872,7 +922,6 @@ std::string Faust::Transform<FPP,Cpu>::to_string(const bool transpose /* default
str << data[j]->to_string(transpose);
}
}
return str.str();
}
......
......@@ -38,6 +38,7 @@ namespace Faust {
public:
TransformHelper(const std::vector<MatGeneric<FPP,Cpu> *>& facts, const FPP lambda_ = (FPP)1.0, const bool optimizedCopy=true, const bool cloning_fact = true);
TransformHelper();
TransformHelper(TransformHelper<FPP,Cpu>* th_left, TransformHelper<FPP,Cpu>* th_right);
TransformHelper(TransformHelper<FPP,Cpu>* th);
TransformHelper(TransformHelper<FPP,Cpu>* th, bool transpose, bool conjugate);
TransformHelper(TransformHelper<FPP,Cpu>* th, Slice s[2]);
......@@ -46,6 +47,7 @@ namespace Faust {
Vect<FPP,Cpu> multiply(const Vect<FPP,Cpu> x, const bool transpose);
MatDense<FPP,Cpu> multiply(const MatDense<FPP,Cpu> A) const;
MatDense<FPP, Cpu> multiply(const MatDense<FPP,Cpu> A, const bool transpose);
TransformHelper<FPP, Cpu>* multiply(TransformHelper<FPP, Cpu>*);
void push_back(const MatGeneric<FPP,Cpu>* M);
faust_unsigned_int getNbRow() const;
faust_unsigned_int getNbCol() const;
......
......@@ -21,6 +21,14 @@ namespace Faust {
this->transform = make_shared<Transform<FPP,Cpu>>();
}
template<typename FPP>
TransformHelper<FPP,Cpu>::TransformHelper(TransformHelper<FPP,Cpu>* th_left, TransformHelper<FPP,Cpu>* th_right)
: is_transposed(false), is_conjugate(false), is_sliced(false)
{
this->transform = make_shared<Transform<FPP,Cpu>>(th_left->eval_sliced_Transform(), th_left->is_transposed, th_left->is_conjugate,
th_right->eval_sliced_Transform(), th_right->is_transposed, th_right->is_conjugate);
}
template<typename FPP>
TransformHelper<FPP,Cpu>::TransformHelper(TransformHelper<FPP,Cpu>* th, bool transpose, bool conjugate)
{
......@@ -99,6 +107,12 @@ namespace Faust {
return M;
}
template<typename FPP>
TransformHelper<FPP, Cpu>* TransformHelper<FPP,Cpu>::multiply(TransformHelper<FPP, Cpu>* th_right)
{
return new TransformHelper<FPP,Cpu>(this, th_right);
}
template<typename FPP>
void TransformHelper<FPP,Cpu>::push_back(const MatGeneric<FPP,Cpu>* M)
{
......
......@@ -438,7 +438,7 @@ class Faust:
def __mul__(F, A):
"""
Multiplies F by the numpy matrix A.
Multiplies F by the numpy matrix or a Faust A.
This method overloads a Python function/operator.
......@@ -447,13 +447,15 @@ class Faust:
Args:
F: the Faust object.
A: is a 2D numpy matrix (ndarray).
A: is a Faust object or a 2D numpy matrix (ndarray).
<br/> A must be Fortran contiguous (i.e. Column-major order;
`order' argument passed to np.ndararray() must be equal to str
'F').
Returns:
the result of the multiplication as a numpy matrix.
the result of the multiplication as a numpy matrix if A is a
ndarray.
the result of the multiplication as a Faust object if A is a Faust.
Raises:
ValueError
......@@ -467,9 +469,17 @@ class Faust:
>>> A = np.random.rand(F.shape[1], 50)
>>> B = F*A
>>> # is equivalent to B = F.__mul__(A)
>>> G = Faust.rand(5, F.shape[1])
>>> H = F*G
"""
return F.m_faust.multiply(A)
if(isinstance(A, Faust)):
if(F.shape[1] != A.shape[0]): raise ValueError("The dimensions of "
"the two Fausts must "
"agree.")
return Faust(core_obj=F.m_faust.multiply(A.m_faust))
else:
return F.m_faust.multiply(A)
def toarray(F):
"""
......
......@@ -64,6 +64,7 @@ class FaustCoreCpp
unsigned int getNbRow() const;
unsigned int getNbCol() const;
void multiply(FPP* value_y,int nbrow_y,int nbcol_y,FPP* value_x,int nbrow_x,int nbcol_x/*,bool isTranspose*/)const;
FaustCoreCpp<FPP>* mul_faust(FaustCoreCpp<FPP>* right);
unsigned long long nnz()const;
double norm(int ord) const;
double normFro() const;
......
......@@ -69,6 +69,15 @@ void FaustCoreCpp<FPP>::push_back(FPP* data, int* row_ptr, int* id_col, int nnz,
this->transform.push_back(&sparse_mat);
}
template<typename FPP>
FaustCoreCpp<FPP>* FaustCoreCpp<FPP>::mul_faust(FaustCoreCpp<FPP>* right)
{
Faust::TransformHelper<FPP,Cpu>* th = this->transform.multiply(&(right->transform));
FaustCoreCpp<FPP>* core = new FaustCoreCpp<FPP>();
core->transform = th;
return core;
}
template<typename FPP>
void FaustCoreCpp<FPP>::multiply(FPP* value_y,int nbrow_y,int nbcol_y,FPP* value_x,int nbrow_x,int nbcol_x)const
{
......@@ -152,7 +161,10 @@ double FaustCoreCpp<FPP>::get_nb_factors() const
template<typename FPP>
const char* FaustCoreCpp<FPP>::to_string() const
{
return this->transform.to_string().c_str();
std::string str = this->transform.to_string();
char * c_str = (char*) malloc(str.size()+1);
memcpy(c_str, str.c_str(), str.size()+1);
return (const char*) c_str;
}
template<typename FPP>
......
......@@ -67,6 +67,7 @@ cdef extern from "FaustCoreCpp.h" :
FaustCoreCpp[FPP]* transpose()
FaustCoreCpp[FPP]* conjugate()
FaustCoreCpp[FPP]* adjoint()
FaustCoreCpp[FPP]* mul_faust(FaustCoreCpp[FPP]*)
@staticmethod
FaustCoreCpp[FPP]* randFaust(unsigned int t,
unsigned int min_num_factors, unsigned int max_num_factors,
......
......@@ -174,6 +174,19 @@ cdef class FaustCore:
return (nbrow,nbcol)
cdef multiply_faust(self, F):
if(isinstance(F, FaustCore)):
core = FaustCore(core=True)
core2 = FaustCore(core=True)
if(self._isReal):
core.core_faust_dbl = \
self.core_faust_dbl.mul_faust((<FaustCore?>F).core_faust_dbl)
else:
core.core_faust_cplx = \
self.core_faust_cplx.mul_faust((<FaustCore?>F).core_faust_cplx)
core._isReal = self._isReal
return core
raise ValueError("F must be a Faust object")
......@@ -185,6 +198,8 @@ cdef class FaustCore:
# Left-Multiplication by a Faust F
# y=multiply(F,M) is equivalent to y=F*M
def multiply(self,M):
if(isinstance(M, FaustCore)):
return self.multiply_faust(M)
if not isinstance(M, (np.ndarray) ):
raise ValueError('input M must a numpy ndarray')
if(self._isReal):
......@@ -278,7 +293,10 @@ cdef class FaustCore:
else:
c_str = self.core_faust_cplx.to_string()
cdef length = strlen(c_str)
py_str = c_str[:length].decode('UTF-8')
#printf("%s", c_str[:length])
#py_str = str(c_str[:length], 'UTF-8')
py_str = c_str[:length].decode('UTF-8', 'ignore')
free(<void*>c_str)
return py_str
def nnz(self):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment