Mentions légales du service

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

Add functions to pack factors in a Faust (multiply them to obtain a single...

Add functions to pack factors in a Faust (multiply them to obtain a single matrix). TransformHelper::pack_factors() signatures (pack to the left, to the right, by index range or all TranformHelper factors).
parent a54a543f
No related branches found
No related tags found
No related merge requests found
......@@ -156,7 +156,7 @@ endif()
if(NOT NOCPPTESTS)
foreach(TEST_FPP float double)
foreach(FILE faust_mult faust_mult_cplx test_Vect_min test_MatDense_get_row test_MatDense_lower_upper_tri test_MatDense_nonzeros_indices test_Transform_move test_TransformHelper_and_Transform_copy_ctor test_TransformHelper_and_Transform_fac_iterato test_TransformHelper_variadic_template_ctor test_MatDense_min faust_transform_omp_mul faust_pruneout faust_transform_optimize_storage faust_transform_optimize faust_prox_blockdiag)
foreach(FILE faust_mult faust_mult_cplx test_Vect_min test_MatDense_get_row test_MatDense_lower_upper_tri test_MatDense_nonzeros_indices test_Transform_move test_TransformHelper_and_Transform_copy_ctor test_TransformHelper_and_Transform_fac_iterato test_TransformHelper_variadic_template_ctor test_MatDense_min test_TH_pack_factors faust_transform_omp_mul faust_pruneout faust_transform_optimize_storage faust_transform_optimize faust_prox_blockdiag)
set(TEST_BIN_FILE ${FILE}_${TEST_FPP})
set(TEST_FILE_CPP ${TEST_BIN_FILE}.cpp)
message(STATUS ${TEST_FILE_CPP})
......
/****************************************************************************/
/* Description: */
/* unitary test for testing multiplication by faust with real scalar */
/* */
/* For more information on the FAuST Project, please visit the website */
/* of the project : <http://faust.inria.fr> */
/* */
/* License: */
/* Copyright (2020): Hakim HADJ-DJILANI */
/* Nicolas Bellot, Adrien Leman, Thomas Gautrais, */
/* Luc Le Magoarou, Remi Gribonval */
/* INRIA Rennes, FRANCE */
/* http://www.inria.fr/ */
/* */
/* The FAuST Toolbox is distributed under the terms of the GNU Affero */
/* General Public License. */
/* This program is free software: you can redistribute it and/or modify */
/* it under the terms of the GNU Affero General Public License as */
/* published by the Free Software Foundation. */
/* */
/* 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 Affero General Public License for more details. */
/* */
/* You should have received a copy of the GNU Affero General Public */
/* License along with this program. */
/* If not, see <http://www.gnu.org/licenses/>. */
/* */
/* Contacts: */
/* Nicolas Bellot : nicolas.bellot@inria.fr */
/* Adrien Leman : adrien.leman@inria.fr */
/* Thomas Gautrais : thomas.gautrais@inria.fr */
/* Luc Le Magoarou : luc.le-magoarou@inria.fr */
/* Remi Gribonval : remi.gribonval@inria.fr */
/* */
/* References: */
/* [1] Le Magoarou L. and Gribonval R., "Flexible multi-layer sparse */
/* approximations of matrices and applications", Journal of Selected */
/* Topics in Signal Processing, 2016. */
/* <https://hal.archives-ouvertes.fr/hal-01167948v1> */
/****************************************************************************/
#include "faust_MatDense.h"
#include "faust_MatSparse.h"
#include "faust_Transform.h"
#include "faust_TransformHelper.h"
#include <string>
/** unit test for TransformHelper variadic template ctor
* The goal is to test that factors are not duplicated in memory and it works when passing anything among a TransformHelper, Transform objects or a vector of MatGeneric<FPP,Cpu*> (anything that supports begin() and end() ops).
*/
typedef @TEST_FPP@ FPP;
using namespace Faust;
int main(int argc, char* argv[])
{
if (typeid(FPP) == typeid(double))
{
cout<<"floating point precision == double"<<endl;
}
if (typeid(FPP) == typeid(float))
{
cout<<"floating point precision == float"<<endl;
}
int mat_nrows = 10;
int mat_ncols = 10;
int n_mats = 5;
int n_sparse_mats = 2;
vector<MatGeneric<FPP,Cpu>*> facts(n_mats);
for(int i=0;i<n_sparse_mats;i++)
{
Faust::MatSparse<FPP,Cpu>* mat = Faust::MatSparse<FPP,Cpu>::randMat(mat_nrows, mat_ncols, .5);
facts[i] = mat;
}
for(int i=n_sparse_mats;i<n_mats;i++)
{
MatDense<FPP,Cpu>* mat = MatDense<FPP,Cpu>::randMat(mat_nrows, mat_ncols);
facts[i] = mat;
}
TransformHelper<FPP,Cpu> th0(facts, 1.0, false, false, false); // a Faust that uses facts without copy (I want to be sure factors are not altered on the end)
/************** Test packing to the right */
cout << "* testing packing factors on the right (from id 3 included)" << endl;
TransformHelper<FPP,Cpu> th(facts, 1.0, false, true, false); //cloning_fact == true to copy facts and not altering it after
// pre-condition: verify facts is identitical to factors really in th
for(int i=0;i<th.size();i++)
assert((*(th.begin()+i))->norm() == (*(facts.begin()+i))->norm());
assert(th.size() == facts.size());
// pack factors on the right of factor index 2
th.pack_factors(3, PackDir::PACK_RIGHT);
//test it's done properly
//1 number of factors
cout << "th new size (after packing at 3 to the right):" << th.size() << endl;
assert(th.size() == 4 /* n_mats-(n_mats-3)+1*/);
//2 identity of left factors
for(int i=0;i<3;i++)
assert((*(th.begin()+i))->norm() == (*(facts.begin()+i))->norm());
//3 the last factor is equal to the product of previous left factors
MatDense<FPP,Cpu> prod_fac3_fac4 = *dynamic_cast<MatDense<FPP,Cpu>*>(facts[3]);
prod_fac3_fac4 *= *dynamic_cast<MatDense<FPP,Cpu>*>(facts[4]);
Real<FPP> npacked = dynamic_cast<MatDense<FPP,Cpu>*>(*(th.begin()+3))->norm();
assert(npacked == prod_fac3_fac4.norm());
cout << "OK" << endl;
/****************************** Test packing to the left **/
cout << "* testing packing factors on the left (up to id 3 included)" << endl;
TransformHelper<FPP,Cpu> th2(facts, 1.0, false, true, false); //cloning_fact == true to copy facts and not altering it after
// pre-condition: verify facts is identitical to factors really in th
for(int i=0;i<th2.size();i++)
assert((*(th2.begin()+i))->norm() == (*(facts.begin()+i))->norm());
assert(th2.size() == facts.size());
// pack factors on the right of factor index 2
th2.pack_factors(3, PackDir::PACK_LEFT);
//test it's done properly
//1 number of factors
cout << "th2 new size (after packing at 3 to the right):" << th2.size() << endl;
assert(th2.size() == 2);
//2 identity of right factors
for(int i = 0; i < facts.size()-3-1;i++)
assert((*(th2.end()-1-i))->norm() == (*(facts.end()-1-i))->norm());
//3 the last factor is equal to the product of previous left factors
MatDense<FPP,Cpu> prod_fac0to3 = *dynamic_cast<Faust::MatSparse<FPP,Cpu>*>(facts[0]);
for(int i=1;i<4;i++)
if(i < n_sparse_mats)
prod_fac0to3 *= MatDense<FPP,Cpu>(*dynamic_cast<Faust::MatSparse<FPP,Cpu>*>(facts[i]));
else
prod_fac0to3 *= *dynamic_cast<Faust::MatDense<FPP,Cpu>*>(facts[i]);
npacked = dynamic_cast<MatDense<FPP,Cpu>*>(*(th2.begin()))->norm();
assert(Faust::fabs(npacked-prod_fac0to3.norm()) < 1e-6);
cout << "OK" << endl;
/******************** test packing only one factor (must do nothing) */
cout << "* testing packing a single factor (idempotent)" << endl;
TransformHelper<FPP,Cpu> th3(facts, 1.0, false, true, false); //cloning_fact == true to copy facts and not altering it after
th3.pack_factors(0,0);
th3.pack_factors(4,4);
for(int i=0;i<th3.size();i++)
assert((*(th3.begin()+i))->norm() == (*(facts.begin()+i))->norm());
assert(th3.size() == facts.size());
cout << "OK" << endl;
/************************* test packing all */
TransformHelper<FPP,Cpu> th4(facts, 1.0, false, true, false); //cloning_fact == true to copy facts and not altering it after
cout << "* testing packing all factors" << endl;
th4.pack_factors();
assert(th4.size() == 1);
MatDense<FPP,Cpu> prod_fac = *dynamic_cast<Faust::MatSparse<FPP,Cpu>*>(facts[0]);
for(int i=1;i<n_mats;i++)
if(i < n_sparse_mats)
prod_fac *= MatDense<FPP,Cpu>(*dynamic_cast<Faust::MatSparse<FPP,Cpu>*>(facts[i]));
else
prod_fac *= *dynamic_cast<Faust::MatDense<FPP,Cpu>*>(facts[i]);
npacked = dynamic_cast<MatDense<FPP,Cpu>*>(*(th2.begin()))->norm();
assert(Faust::fabs(npacked-prod_fac0to3.norm()) < 1e-6);
cout << "OK" << endl;
/****** sanity check on th0 */
// factors have to be not altered by all previous packing
for(int i=0;i<th0.size();i++)
assert((*(th0.begin()+i))->norm() == (*(facts.begin()+i))->norm());
}
......@@ -66,6 +66,11 @@ namespace Faust {
MIXED
};
enum PackDir {
PACK_LEFT,
PACK_RIGHT
};
template<typename FPP>
class TransformHelper<FPP,Cpu> {
static std::default_random_engine generator;
......@@ -188,6 +193,9 @@ namespace Faust {
transf_iterator<FPP> begin() const;
transf_iterator<FPP> end() const;
void pack_factors(faust_unsigned_int start_id, faust_unsigned_int end_id);
void pack_factors();
void pack_factors(const faust_unsigned_int id, const PackDir dir);
static TransformHelper<FPP,Cpu>* randFaust(RandFaustType t, unsigned int min_num_factors, unsigned int max_num_factors, unsigned int min_dim_size, unsigned int max_dim_size, float density=.1f, bool per_row=true);
static TransformHelper<FPP,Cpu>* hadamardFaust(unsigned int n, const bool norma=true);
......
......@@ -1451,6 +1451,49 @@ namespace Faust {
return this->transform->end();
}
template<typename FPP>
void Faust::TransformHelper<FPP,Cpu>::pack_factors(faust_unsigned_int start_id, faust_unsigned_int end_id)
{
if(start_id < 0 || start_id >= size())
throw out_of_range("start_id is out of range.");
if(end_id < 0 || end_id >= size())
throw out_of_range("end_id is out of range.");
if(end_id == start_id)
//nothing to do
return;
// we have to multiply factors from start_id to end_id into one matrix
// simple way to do, 1) create a overhead-free TransformHelper with these factors
// 2) call get_product() to override the start_id factors with the result on the end
// 3) release through ref_man the factors to pack, from start_id to end_id(that's the dirty part to maybe enhance because normally this is the Transform object's responsibility). The packed factor must be acquired too.
// 4) erase factors from start_id to end_id
// 1)
std::vector<Faust::MatGeneric<FPP,Cpu>*> topack_factors(begin()+start_id, begin()+end_id+1);
Faust::TransformHelper<FPP,Cpu> t(topack_factors, 1.0, false, false, true);
// 2)
Faust::MatDense<FPP,Cpu> * packed_fac = new MatDense<FPP,Cpu>(t.get_product());
// 3)
for(auto f = begin()+start_id; f != begin()+end_id+1; f++)
Transform<FPP,Cpu>::ref_man.release(*f);
// 4)
this->transform->data.erase(this->transform->begin()+start_id, this->transform->begin()+end_id+1);
this->transform->data.insert(begin()+start_id, packed_fac);
Transform<FPP,Cpu>::ref_man.acquire(packed_fac);
}
template <typename FPP> void TransformHelper<FPP,Cpu>::pack_factors(const faust_unsigned_int id, const PackDir dir)
{
if(dir == PACK_RIGHT)
pack_factors(id, size()-1);
else // dir == PACK_LEFT
pack_factors(0, id);
}
template <typename FPP> void TransformHelper<FPP,Cpu>::pack_factors()
{
//pack all factors in one
pack_factors(0, size()-1);
}
template<typename FPP> bool TransformHelper<FPP,Cpu>::seed_init = false;
template<typename FPP> std::default_random_engine TransformHelper<FPP,Cpu>::generator(time(NULL));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment