Skylark (Sketching Library)
0.1
|
00001 00013 #include <vector> 00014 00015 #include <boost/mpi.hpp> 00016 #include <boost/test/minimal.hpp> 00017 00018 //FIXME: ugly 00019 #define SKYLARK_SKETCH_HPP 1 00020 00021 #include "../../utility/distributions.hpp" 00022 #include "../../base/context.hpp" 00023 #include "../../sketch/hash_transform.hpp" 00024 00025 #include "../../base/sparse_matrix.hpp" 00026 00027 typedef FullyDistVec<size_t, double> mpi_vector_t; 00028 typedef SpDCCols<size_t, double> col_t; 00029 typedef SpParMat<size_t, double, col_t> DistMatrixType; 00030 typedef PlusTimesSRing<double, double> PTDD; 00031 typedef skylark::base::sparse_matrix_t<double> LocalMatrixType; 00032 00033 00034 template < typename InputMatrixType, 00035 typename OutputMatrixType = InputMatrixType > 00036 struct Dummy_t : public skylark::sketch::hash_transform_t< 00037 InputMatrixType, OutputMatrixType, 00038 boost::random::uniform_int_distribution, 00039 skylark::utility::rademacher_distribution_t > { 00040 00041 typedef skylark::sketch::hash_transform_t< 00042 InputMatrixType, OutputMatrixType, 00043 boost::random::uniform_int_distribution, 00044 skylark::utility::rademacher_distribution_t > 00045 hash_t; 00046 00047 Dummy_t(int N, int S, skylark::base::context_t& context) 00048 : skylark::sketch::hash_transform_t<InputMatrixType, OutputMatrixType, 00049 boost::random::uniform_int_distribution, 00050 skylark::utility::rademacher_distribution_t>(N, S, context) 00051 {} 00052 00053 std::vector<size_t> getRowIdx() { return hash_t::row_idx; } 00054 std::vector<double> getRowValues() { return hash_t::row_value; } 00055 }; 00056 00057 00058 template<typename sketch_t> 00059 void compute_sketch_matrix(sketch_t sketch, const DistMatrixType &A, 00060 DistMatrixType &result) { 00061 00062 std::vector<size_t> row_idx = sketch.getRowIdx(); 00063 std::vector<double> row_val = sketch.getRowValues(); 00064 00065 // PI generated by random number gen 00066 size_t sketch_size = row_val.size(); 00067 mpi_vector_t cols(sketch_size); 00068 mpi_vector_t rows(sketch_size); 00069 mpi_vector_t vals(sketch_size); 00070 00071 for(size_t i = 0; i < sketch_size; ++i) { 00072 cols.SetElement(i, i); 00073 rows.SetElement(i, row_idx[i]); 00074 vals.SetElement(i, row_val[i]); 00075 } 00076 00077 result = DistMatrixType(result.getnrow(), result.getncol(), 00078 rows, cols, vals); 00079 } 00080 00081 void compare_result(size_t rank, DistMatrixType &expected_A, 00082 elem::DistMatrix<double, elem::STAR, elem::STAR> &result) { 00083 00084 col_t &data = expected_A.seq(); 00085 //FIXME: use comm_grid 00086 const size_t my_row_offset = 00087 static_cast<int>((static_cast<double>(expected_A.getnrow()) / 00088 expected_A.getcommgrid()->GetGridRows())) * 00089 expected_A.getcommgrid()->GetRankInProcCol(rank); 00090 00091 const size_t my_col_offset = 00092 static_cast<int>((static_cast<double>(expected_A.getncol()) / 00093 expected_A.getcommgrid()->GetGridCols())) * 00094 expected_A.getcommgrid()->GetRankInProcRow(rank); 00095 00096 for(typename col_t::SpColIter col = data.begcol(); 00097 col != data.endcol(); col++) { 00098 for(typename col_t::SpColIter::NzIter nz = data.begnz(col); 00099 nz != data.endnz(col); nz++) { 00100 00101 const size_t rowid = nz.rowid() + my_row_offset; 00102 const size_t colid = col.colid() + my_col_offset; 00103 const double value = nz.value(); 00104 00105 if(value != result.GetLocal(rowid, colid)) 00106 BOOST_FAIL("Result of colwise (dist -> dist) application not as expected"); 00107 } 00108 } 00109 00110 } 00111 00112 int test_main(int argc, char *argv[]) { 00113 00115 //[> Parameters <] 00116 00117 //FIXME: use random sizes? 00118 const size_t n = 100; 00119 const size_t m = 50; 00120 const size_t n_s = 60; 00121 const size_t m_s = 30; 00122 00124 //[> Setup test <] 00125 namespace mpi = boost::mpi; 00126 00127 #ifdef SKYLARK_HAVE_OPENMP 00128 int provided; 00129 MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); 00130 #endif 00131 00132 mpi::environment env(argc, argv); 00133 mpi::communicator world; 00134 const size_t rank = world.rank(); 00135 00136 elem::Initialize(argc, argv); 00137 MPI_Comm mpi_world(world); 00138 elem::Grid grid(mpi_world); 00139 00140 skylark::base::context_t context (0); 00141 00142 double count = 1.0; 00143 00144 const size_t matrix_full = n * m; 00145 mpi_vector_t colsf(matrix_full); 00146 mpi_vector_t rowsf(matrix_full); 00147 mpi_vector_t valsf(matrix_full); 00148 00149 for(size_t i = 0; i < matrix_full; ++i) { 00150 colsf.SetElement(i, i % m); 00151 rowsf.SetElement(i, i / m); 00152 valsf.SetElement(i, count); 00153 count++; 00154 } 00155 00156 DistMatrixType A(n, m, rowsf, colsf, valsf); 00157 mpi_vector_t zero; 00158 00159 count = 1.0; 00160 elem::Matrix<double> local_A(n, m); 00161 for( size_t j = 0; j < local_A.Height(); j++ ) 00162 for( size_t i = 0; i < local_A.Width(); i++ ) 00163 local_A.Set(j, i, count++); 00164 00165 00167 //[> Column wise application DistSparseMatrix -> DistMatrix[MC/MR] <] 00168 00169 typedef elem::DistMatrix<double> mcmr_target_t; 00170 00171 //[> 1. Create the sketching matrix <] 00172 Dummy_t<DistMatrixType, mcmr_target_t> Sparse(n, n_s, context); 00173 00174 //[> 2. Create space for the sketched matrix <] 00175 mcmr_target_t sketch_A(n_s, m, grid); 00176 elem::Zero(sketch_A); 00177 00178 //[> 3. Apply the transform <] 00179 Sparse.apply(A, sketch_A, skylark::sketch::columnwise_tag()); 00180 00181 //[> 4. Build structure to compare <] 00182 // easier to check if all processors own result 00183 elem::DistMatrix<double, elem::STAR, elem::STAR> result = sketch_A; 00184 00185 DistMatrixType pi_sketch(n_s, n, zero, zero, zero); 00186 compute_sketch_matrix(Sparse, A, pi_sketch); 00187 DistMatrixType expected_A = Mult_AnXBn_Synch<PTDD, double, col_t>( 00188 pi_sketch, A, false, false); 00189 00190 compare_result(rank, expected_A, result); 00191 00193 //[> Column wise application DistSparseMatrix -> DistMatrix[VC/*] <] 00194 00195 typedef elem::DistMatrix<double, elem::VC, elem::STAR> vcs_target_t; 00196 00197 //[> 1. Create the sketching matrix <] 00198 Dummy_t<DistMatrixType, vcs_target_t> SparseVC(n, n_s, context); 00199 00200 //[> 2. Create space for the sketched matrix <] 00201 vcs_target_t sketch_A_vcs(n, n_s, grid); 00202 elem::Zero(sketch_A_vcs); 00203 00204 //[> 3. Apply the transform <] 00205 SparseVC.apply(A, sketch_A_vcs, skylark::sketch::columnwise_tag()); 00206 00207 //[> 4. Build structure to compare <] 00208 // easier to check if all processors own result 00209 result = sketch_A_vcs; 00210 00211 compute_sketch_matrix(SparseVC, A, pi_sketch); 00212 expected_A = Mult_AnXBn_Synch<PTDD, double, col_t>( 00213 pi_sketch, A, false, false); 00214 00215 compare_result(rank, expected_A, result); 00216 00217 #if 0 00218 00219 //[> Column wise application DistSparseMatrix -> DistMatrix[*/*] <] 00220 00221 typedef elem::DistMatrix<double, elem::STAR, elem::STAR> st_target_t; 00222 00223 //[> 1. Create the sketching matrix <] 00224 Dummy_t<DistMatrixType, st_target_t> SparseST(n, n_s, context); 00225 00226 //[> 2. Create space for the sketched matrix <] 00227 st_target_t sketch_A_st(n, n_s, grid); 00228 elem::Zero(sketch_A_st); 00229 00230 //[> 3. Apply the transform <] 00231 SparseST.apply(A, sketch_A_st, skylark::sketch::columnwise_tag()); 00232 00233 //[> 4. Build structure to compare <] 00234 // easier to check if all processors own result 00235 result = sketch_A_st; 00236 00237 compute_sketch_matrix(SparseVC, A, pi_sketch); 00238 expected_A = Mult_AnXBn_Synch<PTDD, double, col_t>( 00239 pi_sketch, A, false, false); 00240 00241 compare_result(rank, expected_A, result); 00242 #endif 00243 00245 //[> Column wise application DistSparseMatrix -> LocalDenseMatrix <] 00246 00247 Dummy_t<DistMatrixType, elem::Matrix<double>> LocalSparse(n, n_s, context); 00248 elem::Matrix<double> local_sketch_A(n, n_s); 00249 elem::Zero(local_sketch_A); 00250 LocalSparse.apply(A, local_sketch_A, skylark::sketch::columnwise_tag()); 00251 00252 elem::Matrix<double> pi_sketch_l(n_s, n); 00253 elem::Zero(pi_sketch_l); 00254 elem::Matrix<double> expected_A_l(n_s, m); 00255 elem::Zero(expected_A_l); 00256 00257 if(rank == 0) { 00258 // PI generated by random number gen 00259 std::vector<size_t> row_idx = LocalSparse.getRowIdx(); 00260 std::vector<double> row_val = LocalSparse.getRowValues(); 00261 00262 int sketch_size = row_val.size(); 00263 typename LocalMatrixType::coords_t coords; 00264 00265 for(int i = 0; i < sketch_size; ++i) 00266 pi_sketch_l.Set(row_idx[i], i, row_val[i]); 00267 00268 elem::Gemm(elem::NORMAL, elem::NORMAL, 1.0, pi_sketch_l, local_A, 00269 0.0, expected_A_l); 00270 00271 for(int col = 0; col < expected_A_l.Width(); col++) { 00272 for(int row = 0; row < expected_A_l.Height(); row++) { 00273 if(local_sketch_A.Get(row, col) != 00274 expected_A_l.Get(row, col)) 00275 BOOST_FAIL("Result of local colwise application not as expected"); 00276 } 00277 } 00278 } 00279 00280 00282 //[> Row wise application DistSparseMatrix -> DistMatrix[MC/MR] <] 00283 00284 //[> 1. Create the sketching matrix <] 00285 Dummy_t<DistMatrixType, mcmr_target_t> Sparse_r(m, m_s, context); 00286 00287 //[> 2. Create space for the sketched matrix <] 00288 mcmr_target_t sketch_A_r(n, m_s, grid); 00289 elem::Zero(sketch_A_r); 00290 00291 //[> 3. Apply the transform <] 00292 Sparse_r.apply(A, sketch_A_r, skylark::sketch::rowwise_tag()); 00293 00294 //[> 4. Build structure to compare <] 00295 // easier to check if all processors own result 00296 result = sketch_A_r; 00297 00298 DistMatrixType pi_sketch_r(m_s, m, zero, zero, zero); 00299 compute_sketch_matrix(Sparse_r, A, pi_sketch_r); 00300 pi_sketch_r.Transpose(); 00301 DistMatrixType expected_AR = Mult_AnXBn_Synch<PTDD, double, col_t>( 00302 A, pi_sketch_r, false, false); 00303 00304 compare_result(rank, expected_AR, result); 00305 00307 //[> Row wise application DistSparseMatrix -> DistMatrix[VC/*] <] 00308 00309 //[> 1. Create the sketching matrix <] 00310 Dummy_t<DistMatrixType, vcs_target_t> Sparse_r_vcs(m, m_s, context); 00311 00312 //[> 2. Create space for the sketched matrix <] 00313 vcs_target_t sketch_A_r_vcs(n, m_s, grid); 00314 elem::Zero(sketch_A_r_vcs); 00315 00316 //[> 3. Apply the transform <] 00317 Sparse_r_vcs.apply(A, sketch_A_r_vcs, skylark::sketch::rowwise_tag()); 00318 00319 //[> 4. Build structure to compare <] 00320 // easier to check if all processors own result 00321 result = sketch_A_r_vcs; 00322 00323 pi_sketch_r.Transpose(); 00324 compute_sketch_matrix(Sparse_r_vcs, A, pi_sketch_r); 00325 pi_sketch_r.Transpose(); 00326 expected_AR = Mult_AnXBn_Synch<PTDD, double, col_t>( 00327 A, pi_sketch_r, false, false); 00328 00329 compare_result(rank, expected_AR, result); 00330 00332 //[> Row wise application DistSparseMatrix -> LocalDenseMatrix <] 00333 00334 Dummy_t<DistMatrixType, elem::Matrix<double>> LocalSparse_r(m, m_s, context); 00335 elem::Matrix<double> local_sketch_A_r(n, m_s); 00336 elem::Zero(local_sketch_A_r); 00337 LocalSparse_r.apply(A, local_sketch_A_r, skylark::sketch::rowwise_tag()); 00338 00339 elem::Matrix<double> local_pi_sketch_r(m_s, m); 00340 elem::Zero(local_pi_sketch_r); 00341 elem::Matrix<double> expected_A_r(n, m_s); 00342 elem::Zero(expected_A_r); 00343 00344 if(rank == 0) { 00345 // PI generated by random number gen 00346 std::vector<size_t> row_idx = LocalSparse_r.getRowIdx(); 00347 std::vector<double> row_val = LocalSparse_r.getRowValues(); 00348 00349 int sketch_size = row_val.size(); 00350 typename LocalMatrixType::coords_t coords; 00351 00352 for(int i = 0; i < sketch_size; ++i) 00353 local_pi_sketch_r.Set(row_idx[i], i, row_val[i]); 00354 00355 elem::Gemm(elem::NORMAL, elem::TRANSPOSE, 1.0, local_A, local_pi_sketch_r, 00356 0.0, expected_A_r); 00357 00358 for(int col = 0; col < expected_A_r.Width(); col++) { 00359 for(int row = 0; row < expected_A_r.Height(); row++) { 00360 if(local_sketch_A_r.Get(row, col) != 00361 expected_A_r.Get(row, col)) 00362 BOOST_FAIL("Result of local rowwise application not as expected"); 00363 } 00364 } 00365 } 00366 00367 return 0; 00368 }