ViennaCL - The Vienna Computing Library  1.5.2
viennacl/compressed_compressed_matrix.hpp
Go to the documentation of this file.
00001 #ifndef VIENNACL_COMPRESSED_compressed_compressed_matrix_HPP_
00002 #define VIENNACL_COMPRESSED_compressed_compressed_matrix_HPP_
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2014, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008    Portions of this software are copyright by UChicago Argonne, LLC.
00009 
00010                             -----------------
00011                   ViennaCL - The Vienna Computing Library
00012                             -----------------
00013 
00014    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00015 
00016    (A list of authors and contributors can be found in the PDF manual)
00017 
00018    License:         MIT (X11), see file LICENSE in the base directory
00019 ============================================================================= */
00020 
00025 #include <vector>
00026 #include <list>
00027 #include <map>
00028 #include "viennacl/forwards.h"
00029 #include "viennacl/vector.hpp"
00030 
00031 #include "viennacl/linalg/sparse_matrix_operations.hpp"
00032 
00033 #include "viennacl/tools/tools.hpp"
00034 #include "viennacl/tools/entry_proxy.hpp"
00035 
00036 namespace viennacl
00037 {
00038     namespace detail
00039     {
00040       template <typename CPU_MATRIX, typename SCALARTYPE>
00041       void copy_impl(const CPU_MATRIX & cpu_matrix,
00042                      compressed_compressed_matrix<SCALARTYPE> & gpu_matrix,
00043                      vcl_size_t nonzero_rows,
00044                      vcl_size_t nonzeros)
00045       {
00046         assert( (gpu_matrix.size1() == 0 || viennacl::traits::size1(cpu_matrix) == gpu_matrix.size1()) && bool("Size mismatch") );
00047         assert( (gpu_matrix.size2() == 0 || viennacl::traits::size2(cpu_matrix) == gpu_matrix.size2()) && bool("Size mismatch") );
00048 
00049         viennacl::backend::typesafe_host_array<unsigned int> row_buffer(gpu_matrix.handle1(), nonzero_rows + 1);
00050         viennacl::backend::typesafe_host_array<unsigned int> row_indices(gpu_matrix.handle3(), nonzero_rows);
00051         viennacl::backend::typesafe_host_array<unsigned int> col_buffer(gpu_matrix.handle2(), nonzeros);
00052         std::vector<SCALARTYPE> elements(nonzeros);
00053 
00054         vcl_size_t row_index  = 0;
00055         vcl_size_t data_index = 0;
00056 
00057         for (typename CPU_MATRIX::const_iterator1 row_it = cpu_matrix.begin1();
00058               row_it != cpu_matrix.end1();
00059               ++row_it)
00060         {
00061           bool row_empty = true;
00062 
00063           for (typename CPU_MATRIX::const_iterator2 col_it = row_it.begin();
00064                 col_it != row_it.end();
00065                 ++col_it)
00066           {
00067             SCALARTYPE entry = *col_it;
00068             if (entry != SCALARTYPE(0))
00069             {
00070               if (row_empty)
00071               {
00072                 assert(row_index < nonzero_rows && bool("Provided count of nonzero rows exceeded!"));
00073 
00074                 row_empty = false;
00075                 row_buffer.set(row_index, data_index);
00076                 row_indices.set(row_index, col_it.index1());
00077                 ++row_index;
00078               }
00079 
00080               col_buffer.set(data_index, col_it.index2());
00081               elements[data_index] = entry;
00082               ++data_index;
00083             }
00084           }
00085         }
00086         row_buffer.set(row_index, data_index);
00087 
00088         gpu_matrix.set(row_buffer.get(),
00089                        row_indices.get(),
00090                        col_buffer.get(),
00091                        &elements[0],
00092                        cpu_matrix.size1(),
00093                        cpu_matrix.size2(),
00094                        nonzero_rows,
00095                        nonzeros);
00096       }
00097     }
00098 
00099     //provide copy-operation:
00114     template <typename CPU_MATRIX, typename SCALARTYPE>
00115     void copy(const CPU_MATRIX & cpu_matrix,
00116               compressed_compressed_matrix<SCALARTYPE> & gpu_matrix )
00117     {
00118       //std::cout << "copy for (" << cpu_matrix.size1() << ", " << cpu_matrix.size2() << ", " << cpu_matrix.nnz() << ")" << std::endl;
00119 
00120       if ( cpu_matrix.size1() > 0 && cpu_matrix.size2() > 0 )
00121       {
00122         //determine nonzero rows and total nonzeros:
00123         vcl_size_t num_entries = 0;
00124         vcl_size_t nonzero_rows = 0;
00125         for (typename CPU_MATRIX::const_iterator1 row_it = cpu_matrix.begin1();
00126               row_it != cpu_matrix.end1();
00127               ++row_it)
00128         {
00129           bool row_empty = true;
00130           for (typename CPU_MATRIX::const_iterator2 col_it = row_it.begin();
00131                 col_it != row_it.end();
00132                 ++col_it)
00133           {
00134             if (*col_it != SCALARTYPE(0))
00135             {
00136               ++num_entries;
00137 
00138               if (row_empty)
00139               {
00140                 row_empty = false;
00141                 ++nonzero_rows;
00142               }
00143             }
00144           }
00145         }
00146 
00147         if (num_entries == 0) //we copy an empty matrix
00148           num_entries = 1;
00149 
00150         //set up matrix entries:
00151         detail::copy_impl(cpu_matrix, gpu_matrix, nonzero_rows, num_entries);
00152       }
00153     }
00154 
00155 
00156     //adapted for std::vector< std::map < > > argument:
00162     template <typename SizeType, typename SCALARTYPE>
00163     void copy(const std::vector< std::map<SizeType, SCALARTYPE> > & cpu_matrix,
00164               compressed_compressed_matrix<SCALARTYPE> & gpu_matrix )
00165     {
00166       vcl_size_t nonzero_rows = 0;
00167       vcl_size_t nonzeros = 0;
00168       vcl_size_t max_col = 0;
00169       for (vcl_size_t i=0; i<cpu_matrix.size(); ++i)
00170       {
00171         if (cpu_matrix[i].size() > 0)
00172           ++nonzero_rows;
00173         nonzeros += cpu_matrix[i].size();
00174         if (cpu_matrix[i].size() > 0)
00175           max_col = std::max<vcl_size_t>(max_col, (cpu_matrix[i].rbegin())->first);
00176       }
00177 
00178       viennacl::detail::copy_impl(tools::const_sparse_matrix_adapter<SCALARTYPE, SizeType>(cpu_matrix, cpu_matrix.size(), max_col + 1),
00179                                   gpu_matrix,
00180                                   nonzero_rows,
00181                                   nonzeros);
00182     }
00183 
00184 
00185     //
00186     // gpu to cpu:
00187     //
00197     template <typename CPU_MATRIX, typename SCALARTYPE>
00198     void copy(const compressed_compressed_matrix<SCALARTYPE> & gpu_matrix,
00199               CPU_MATRIX & cpu_matrix )
00200     {
00201       assert( (cpu_matrix.size1() == gpu_matrix.size1()) && bool("Size mismatch") );
00202       assert( (cpu_matrix.size2() == gpu_matrix.size2()) && bool("Size mismatch") );
00203 
00204       if ( gpu_matrix.size1() > 0 && gpu_matrix.size2() > 0 )
00205       {
00206         //get raw data from memory:
00207         viennacl::backend::typesafe_host_array<unsigned int> row_buffer(gpu_matrix.handle1(), gpu_matrix.nnz1() + 1);
00208         viennacl::backend::typesafe_host_array<unsigned int> row_indices(gpu_matrix.handle1(), gpu_matrix.nnz1());
00209         viennacl::backend::typesafe_host_array<unsigned int> col_buffer(gpu_matrix.handle2(), gpu_matrix.nnz());
00210         std::vector<SCALARTYPE> elements(gpu_matrix.nnz());
00211 
00212         //std::cout << "GPU->CPU, nonzeros: " << gpu_matrix.nnz() << std::endl;
00213 
00214         viennacl::backend::memory_read(gpu_matrix.handle1(), 0, row_buffer.raw_size(), row_buffer.get());
00215         viennacl::backend::memory_read(gpu_matrix.handle3(), 0, row_indices.raw_size(), row_indices.get());
00216         viennacl::backend::memory_read(gpu_matrix.handle2(), 0, col_buffer.raw_size(), col_buffer.get());
00217         viennacl::backend::memory_read(gpu_matrix.handle(),  0, sizeof(SCALARTYPE)* gpu_matrix.nnz(), &(elements[0]));
00218 
00219         //fill the cpu_matrix:
00220         vcl_size_t data_index = 0;
00221         for (vcl_size_t i = 1; i < row_buffer.size(); ++i)
00222         {
00223           while (data_index < row_buffer[i])
00224           {
00225             if (col_buffer[data_index] >= gpu_matrix.size2())
00226             {
00227               std::cerr << "ViennaCL encountered invalid data at colbuffer[" << data_index << "]: " << col_buffer[data_index] << std::endl;
00228               return;
00229             }
00230 
00231             if (elements[data_index] != static_cast<SCALARTYPE>(0.0))
00232               cpu_matrix(row_indices[i-1], col_buffer[data_index]) = elements[data_index];
00233             ++data_index;
00234           }
00235         }
00236       }
00237     }
00238 
00239 
00245     template <typename SCALARTYPE>
00246     void copy(const compressed_compressed_matrix<SCALARTYPE> & gpu_matrix,
00247               std::vector< std::map<unsigned int, SCALARTYPE> > & cpu_matrix)
00248     {
00249       tools::sparse_matrix_adapter<SCALARTYPE> temp(cpu_matrix, cpu_matrix.size(), cpu_matrix.size());
00250       copy(gpu_matrix, temp);
00251     }
00252 
00253 
00255 
00262     template<class SCALARTYPE>
00263     class compressed_compressed_matrix
00264     {
00265       public:
00266         typedef viennacl::backend::mem_handle                                                              handle_type;
00267         typedef scalar<typename viennacl::tools::CHECK_SCALAR_TEMPLATE_ARGUMENT<SCALARTYPE>::ResultType>   value_type;
00268         typedef vcl_size_t                                                                                 size_type;
00269 
00271         compressed_compressed_matrix() : rows_(0), cols_(0), nonzero_rows_(0), nonzeros_(0) {}
00272 
00281         explicit compressed_compressed_matrix(vcl_size_t rows, vcl_size_t cols, vcl_size_t nonzero_rows = 0, vcl_size_t nonzeros = 0, viennacl::context ctx = viennacl::context())
00282           : rows_(rows), cols_(cols), nonzero_rows_(nonzero_rows), nonzeros_(nonzeros)
00283         {
00284           row_buffer_.switch_active_handle_id(ctx.memory_type());
00285           row_indices_.switch_active_handle_id(ctx.memory_type());
00286           col_buffer_.switch_active_handle_id(ctx.memory_type());
00287             elements_.switch_active_handle_id(ctx.memory_type());
00288 
00289 #ifdef VIENNACL_WITH_OPENCL
00290           if (ctx.memory_type() == OPENCL_MEMORY)
00291           {
00292             row_buffer_.opencl_handle().context(ctx.opencl_context());
00293             row_indices_.opencl_handle().context(ctx.opencl_context());
00294             col_buffer_.opencl_handle().context(ctx.opencl_context());
00295               elements_.opencl_handle().context(ctx.opencl_context());
00296           }
00297 #endif
00298           if (rows > 0)
00299           {
00300             viennacl::backend::memory_create(row_buffer_, viennacl::backend::typesafe_host_array<unsigned int>().element_size() * (rows + 1), ctx);
00301           }
00302           if (nonzeros > 0)
00303           {
00304             viennacl::backend::memory_create(col_buffer_, viennacl::backend::typesafe_host_array<unsigned int>().element_size() * nonzeros, ctx);
00305             viennacl::backend::memory_create(elements_, sizeof(SCALARTYPE) * nonzeros, ctx);
00306           }
00307         }
00308 
00315         explicit compressed_compressed_matrix(vcl_size_t rows, vcl_size_t cols, viennacl::context ctx)
00316           : rows_(rows), cols_(cols), nonzeros_(0)
00317         {
00318           row_buffer_.switch_active_handle_id(ctx.memory_type());
00319           col_buffer_.switch_active_handle_id(ctx.memory_type());
00320             elements_.switch_active_handle_id(ctx.memory_type());
00321 
00322 #ifdef VIENNACL_WITH_OPENCL
00323           if (ctx.memory_type() == OPENCL_MEMORY)
00324           {
00325             row_buffer_.opencl_handle().context(ctx.opencl_context());
00326             col_buffer_.opencl_handle().context(ctx.opencl_context());
00327               elements_.opencl_handle().context(ctx.opencl_context());
00328           }
00329 #endif
00330           if (rows > 0)
00331           {
00332             viennacl::backend::memory_create(row_buffer_, viennacl::backend::typesafe_host_array<unsigned int>().element_size() * (rows + 1), ctx);
00333           }
00334         }
00335 
00336         explicit compressed_compressed_matrix(viennacl::context ctx) : rows_(0), cols_(0), nonzero_rows_(0), nonzeros_(0)
00337         {
00338           row_buffer_.switch_active_handle_id(ctx.memory_type());
00339           row_indices_.switch_active_handle_id(ctx.memory_type());
00340           col_buffer_.switch_active_handle_id(ctx.memory_type());
00341             elements_.switch_active_handle_id(ctx.memory_type());
00342 
00343 #ifdef VIENNACL_WITH_OPENCL
00344           if (ctx.memory_type() == OPENCL_MEMORY)
00345           {
00346             row_buffer_.opencl_handle().context(ctx.opencl_context());
00347             row_indices_.opencl_handle().context(ctx.opencl_context());
00348             col_buffer_.opencl_handle().context(ctx.opencl_context());
00349               elements_.opencl_handle().context(ctx.opencl_context());
00350           }
00351 #endif
00352         }
00353 
00354 
00355 #ifdef VIENNACL_WITH_OPENCL
00356         explicit compressed_compressed_matrix(cl_mem mem_row_buffer, cl_mem mem_row_indices, cl_mem mem_col_buffer, cl_mem mem_elements,
00357                                               vcl_size_t rows, vcl_size_t cols, vcl_size_t nonzero_rows, vcl_size_t nonzeros) :
00358           rows_(rows), cols_(cols), nonzero_rows_(nonzero_rows), nonzeros_(nonzeros)
00359         {
00360             row_buffer_.switch_active_handle_id(viennacl::OPENCL_MEMORY);
00361             row_buffer_.opencl_handle() = mem_row_buffer;
00362             row_buffer_.opencl_handle().inc();             //prevents that the user-provided memory is deleted once the matrix object is destroyed.
00363             row_buffer_.raw_size(sizeof(cl_uint) * (nonzero_rows + 1));
00364 
00365             row_indices_.switch_active_handle_id(viennacl::OPENCL_MEMORY);
00366             row_indices_.opencl_handle() = mem_row_indices;
00367             row_indices_.opencl_handle().inc();             //prevents that the user-provided memory is deleted once the matrix object is destroyed.
00368             row_indices_.raw_size(sizeof(cl_uint) * nonzero_rows);
00369 
00370             col_buffer_.switch_active_handle_id(viennacl::OPENCL_MEMORY);
00371             col_buffer_.opencl_handle() = mem_col_buffer;
00372             col_buffer_.opencl_handle().inc();             //prevents that the user-provided memory is deleted once the matrix object is destroyed.
00373             col_buffer_.raw_size(sizeof(cl_uint) * nonzeros);
00374 
00375             elements_.switch_active_handle_id(viennacl::OPENCL_MEMORY);
00376             elements_.opencl_handle() = mem_elements;
00377             elements_.opencl_handle().inc();               //prevents that the user-provided memory is deleted once the matrix object is destroyed.
00378             elements_.raw_size(sizeof(SCALARTYPE) * nonzeros);
00379         }
00380 #endif
00381 
00382 
00384         compressed_compressed_matrix & operator=(compressed_compressed_matrix const & other)
00385         {
00386           assert( (rows_ == 0 || rows_ == other.size1()) && bool("Size mismatch") );
00387           assert( (cols_ == 0 || cols_ == other.size2()) && bool("Size mismatch") );
00388 
00389           rows_ = other.size1();
00390           cols_ = other.size2();
00391           nonzero_rows_ = other.nnz1();
00392           nonzeros_ = other.nnz();
00393 
00394           viennacl::backend::typesafe_memory_copy<unsigned int>(other.row_buffer_,  row_buffer_);
00395           viennacl::backend::typesafe_memory_copy<unsigned int>(other.row_indices_, row_indices_);
00396           viennacl::backend::typesafe_memory_copy<unsigned int>(other.col_buffer_,  col_buffer_);
00397           viennacl::backend::typesafe_memory_copy<SCALARTYPE>(other.elements_, elements_);
00398 
00399           return *this;
00400         }
00401 
00402 
00414         void set(const void * row_jumper,
00415                  const void * row_indices,
00416                  const void * col_buffer,
00417                  const SCALARTYPE * elements,
00418                  vcl_size_t rows,
00419                  vcl_size_t cols,
00420                  vcl_size_t nonzero_rows,
00421                  vcl_size_t nonzeros)
00422         {
00423           assert( (rows > 0)         && bool("Error in compressed_compressed_matrix::set(): Number of rows must be larger than zero!"));
00424           assert( (cols > 0)         && bool("Error in compressed_compressed_matrix::set(): Number of columns must be larger than zero!"));
00425           assert( (nonzero_rows > 0) && bool("Error in compressed_compressed_matrix::set(): Number of nonzero rows must be larger than zero!"));
00426           assert( (nonzeros > 0)     && bool("Error in compressed_compressed_matrix::set(): Number of nonzeros must be larger than zero!"));
00427           //std::cout << "Setting memory: " << cols + 1 << ", " << nonzeros << std::endl;
00428 
00429           viennacl::backend::memory_create(row_buffer_,  viennacl::backend::typesafe_host_array<unsigned int>(row_buffer_).element_size() * (rows + 1),  viennacl::traits::context(row_buffer_),  row_jumper);
00430           viennacl::backend::memory_create(row_indices_, viennacl::backend::typesafe_host_array<unsigned int>(row_indices_).element_size() * (rows + 1), viennacl::traits::context(row_indices_), row_indices);
00431           viennacl::backend::memory_create(col_buffer_,  viennacl::backend::typesafe_host_array<unsigned int>(col_buffer_).element_size() * nonzeros,    viennacl::traits::context(col_buffer_),  col_buffer);
00432           viennacl::backend::memory_create(elements_, sizeof(SCALARTYPE) * nonzeros, viennacl::traits::context(elements_), elements);
00433 
00434           nonzeros_ = nonzeros;
00435           nonzero_rows_ = nonzero_rows;
00436           rows_ = rows;
00437           cols_ = cols;
00438         }
00439 
00441         const vcl_size_t & size1() const { return rows_; }
00443         const vcl_size_t & size2() const { return cols_; }
00445         const vcl_size_t & nnz1() const { return nonzero_rows_; }
00447         const vcl_size_t & nnz() const { return nonzeros_; }
00448 
00450         const handle_type & handle1() const { return row_buffer_; }
00452         const handle_type & handle2() const { return col_buffer_; }
00454         const handle_type & handle3() const { return row_indices_; }
00456         const handle_type & handle() const { return elements_; }
00457 
00459         handle_type & handle1() { return row_buffer_; }
00461         handle_type & handle2() { return col_buffer_; }
00463         handle_type & handle3() { return row_indices_; }
00465         handle_type & handle() { return elements_; }
00466 
00467         void switch_memory_context(viennacl::context new_ctx)
00468         {
00469           viennacl::backend::switch_memory_context<unsigned int>(row_buffer_, new_ctx);
00470           viennacl::backend::switch_memory_context<unsigned int>(row_indices_, new_ctx);
00471           viennacl::backend::switch_memory_context<unsigned int>(col_buffer_, new_ctx);
00472           viennacl::backend::switch_memory_context<SCALARTYPE>(elements_, new_ctx);
00473         }
00474 
00475         viennacl::memory_types memory_context() const
00476         {
00477           return row_buffer_.get_active_handle_id();
00478         }
00479 
00480       private:
00481 
00482         vcl_size_t rows_;
00483         vcl_size_t cols_;
00484         vcl_size_t nonzero_rows_;
00485         vcl_size_t nonzeros_;
00486         handle_type row_buffer_;
00487         handle_type row_indices_;
00488         handle_type col_buffer_;
00489         handle_type elements_;
00490     };
00491 
00492 
00493 
00494     //
00495     // Specify available operations:
00496     //
00497 
00500     namespace linalg
00501     {
00502       namespace detail
00503       {
00504         // x = A * y
00505         template <typename T>
00506         struct op_executor<vector_base<T>, op_assign, vector_expression<const compressed_compressed_matrix<T>, const vector_base<T>, op_prod> >
00507         {
00508             static void apply(vector_base<T> & lhs, vector_expression<const compressed_compressed_matrix<T>, const vector_base<T>, op_prod> const & rhs)
00509             {
00510               // check for the special case x = A * x
00511               if (viennacl::traits::handle(lhs) == viennacl::traits::handle(rhs.rhs()))
00512               {
00513                 viennacl::vector<T> temp(lhs);
00514                 viennacl::linalg::prod_impl(rhs.lhs(), rhs.rhs(), temp);
00515                 lhs = temp;
00516               }
00517               else
00518                 viennacl::linalg::prod_impl(rhs.lhs(), rhs.rhs(), lhs);
00519             }
00520         };
00521 
00522         template <typename T>
00523         struct op_executor<vector_base<T>, op_inplace_add, vector_expression<const compressed_compressed_matrix<T>, const vector_base<T>, op_prod> >
00524         {
00525             static void apply(vector_base<T> & lhs, vector_expression<const compressed_compressed_matrix<T>, const vector_base<T>, op_prod> const & rhs)
00526             {
00527               viennacl::vector<T> temp(lhs);
00528               viennacl::linalg::prod_impl(rhs.lhs(), rhs.rhs(), temp);
00529               lhs += temp;
00530             }
00531         };
00532 
00533         template <typename T>
00534         struct op_executor<vector_base<T>, op_inplace_sub, vector_expression<const compressed_compressed_matrix<T>, const vector_base<T>, op_prod> >
00535         {
00536             static void apply(vector_base<T> & lhs, vector_expression<const compressed_compressed_matrix<T>, const vector_base<T>, op_prod> const & rhs)
00537             {
00538               viennacl::vector<T> temp(lhs);
00539               viennacl::linalg::prod_impl(rhs.lhs(), rhs.rhs(), temp);
00540               lhs -= temp;
00541             }
00542         };
00543 
00544 
00545         // x = A * vec_op
00546         template <typename T, typename LHS, typename RHS, typename OP>
00547         struct op_executor<vector_base<T>, op_assign, vector_expression<const compressed_compressed_matrix<T>, const vector_expression<const LHS, const RHS, OP>, op_prod> >
00548         {
00549             static void apply(vector_base<T> & lhs, vector_expression<const compressed_compressed_matrix<T>, const vector_expression<const LHS, const RHS, OP>, op_prod> const & rhs)
00550             {
00551               viennacl::vector<T> temp(rhs.rhs());
00552               viennacl::linalg::prod_impl(rhs.lhs(), temp, lhs);
00553             }
00554         };
00555 
00556         // x = A * vec_op
00557         template <typename T, typename LHS, typename RHS, typename OP>
00558         struct op_executor<vector_base<T>, op_inplace_add, vector_expression<const compressed_compressed_matrix<T>, vector_expression<const LHS, const RHS, OP>, op_prod> >
00559         {
00560             static void apply(vector_base<T> & lhs, vector_expression<const compressed_compressed_matrix<T>, vector_expression<const LHS, const RHS, OP>, op_prod> const & rhs)
00561             {
00562               viennacl::vector<T> temp(rhs.rhs(), viennacl::traits::context(rhs));
00563               viennacl::vector<T> temp_result(lhs);
00564               viennacl::linalg::prod_impl(rhs.lhs(), temp, temp_result);
00565               lhs += temp_result;
00566             }
00567         };
00568 
00569         // x = A * vec_op
00570         template <typename T, typename LHS, typename RHS, typename OP>
00571         struct op_executor<vector_base<T>, op_inplace_sub, vector_expression<const compressed_compressed_matrix<T>, const vector_expression<const LHS, const RHS, OP>, op_prod> >
00572         {
00573             static void apply(vector_base<T> & lhs, vector_expression<const compressed_compressed_matrix<T>, const vector_expression<const LHS, const RHS, OP>, op_prod> const & rhs)
00574             {
00575               viennacl::vector<T> temp(rhs.rhs(), viennacl::traits::context(rhs));
00576               viennacl::vector<T> temp_result(lhs);
00577               viennacl::linalg::prod_impl(rhs.lhs(), temp, temp_result);
00578               lhs -= temp_result;
00579             }
00580         };
00581 
00582       } // namespace detail
00583     } // namespace linalg
00584 
00586 }
00587 
00588 #endif