/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2011 by O. Parcollet * * TRIQS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * TRIQS 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * TRIQS. If not, see . * ******************************************************************************/ #ifndef TRIQS_ARRAYS_QCACHE_H #define TRIQS_ARRAYS_QCACHE_H #include "../matrix.hpp" #include "../vector.hpp" #include namespace triqs { namespace arrays { namespace blas_lapack_tools { /** * Given A, a matrix (or vector/array) it presents via the () operator * - a const & to the matrix if A is a value class (matrix, vector, array, ..) * - a const & to a new value class is A is a an expression * - a const & to a view if A is a view. If the view was not contiguous, it is a view to a * temporary regrouped value class. * * const_qcache is NOT copyable. It should be used in local use only. * [Rational : in simple case, like A =matrix, it allows to keep only a const &, which is quicker * */ template class const_qcache; template struct guarantee_no_copy : boost::mpl::or_< is_amv_value_class, is_vector_view > {}; template struct may_need_copy : boost::mpl::or_< is_matrix_view > {}; // For any data structure for which we can guarantee no copy is need to go to blas/lapack : this is just a ref template class const_qcache< A, ENABLE_IF(guarantee_no_copy) > { A const & x; public: const_qcache(A const & x_):x(x_){} const_qcache(const_qcache const &) = delete; typedef A const & exposed_type; exposed_type operator()() const {return x;} }; // For any expression with matrix concept : we need to copy it into a matrix before using blas/lapack template class const_qcache< A, ENABLE_IF(mpl::and_, mpl::not_ > >) > { typedef matrix X; X x; public: const_qcache(A const & x_):x(x_){} const_qcache(const_qcache const &) = delete; typedef X const & exposed_type; exposed_type operator()() const {return x;} }; // For any expression with vector concept : we need to copy it into a matrix before using blas/lapack template class const_qcache< A, ENABLE_IF(mpl::and_, mpl::not_ > >) > { typedef vector X; X x; public: const_qcache(A const & x_):x(x_){} const_qcache(const_qcache const &) = delete; typedef X const & exposed_type; exposed_type operator()() const {return x;} }; // For any data structure for which we can NOT guarantee no copy is need to go to blas/lapack // decision is to be taken at runtime // first the function to take the decision // should be copy to call blas/lapack ? only if we have a view and if the min_stride // of the matrix is not 1, otherwise we use the LD parameter of blas/lapack template constexpr TYPE_ENABLE_IFC(bool, !is_matrix_view::value) copy_is_needed (T const & A) { return false;} template TYPE_ENABLE_IF(bool, is_matrix_view) copy_is_needed (MatrixView const & A) { auto min_stride = A.indexmap().strides()[A.memory_layout_is_fortran() ? 0 : 1]; return min_stride !=1; } // now the class template class const_qcache< A, ENABLE_IF(may_need_copy)> { const bool need_copy; A keeper; struct internal_data { typename A::non_view_type copy_data; A view; internal_data(const_qcache const & P) : copy_data(P.keeper), view(copy_data) { #ifdef TRIQS_ARRAYS_CACHE_COPY_VERBOSE std::cerr<< " Cache : copy made "<< std::endl; std::cerr<< " -- TRACE = --" << std::endl << triqs::utility::stack_trace() << std::endl; #endif } }; friend struct internal_data; mutable std::unique_ptr _id; internal_data & id() const { assert(need_copy); if (!_id) _id.reset(new internal_data(*this)); return *_id;} protected: void back_update() { if (_id) keeper = _id->copy_data; } // copy data back (for derivative, but but mechanism here). A & view() { return (need_copy ? id().view : keeper);} A const & view() const{ return (need_copy ? id().view : keeper);} public : explicit const_qcache(A const & x): need_copy (blas_lapack_tools::copy_is_needed (x)), keeper(x) {} const_qcache(const_qcache const &) = delete; typedef const A exposed_type; exposed_type operator()() const { return view();} }; /** * reflexive_qcache. * Given A, a value or a view, it presents via the () operator * - a & to the matrix if A is a value class (matrix, vector, array, ..) * - a view if A is a view. If the view given at construction was not contiguous, it is a view to a * temporary regrouped value class. In that case, the data are back copied to the original at construction. * * reflexive_qcache is NOT copyable. It should be used in local use only. * [Rational : in simple case, like A =matrix, it allows to keep only a &, which is quicker * */ template class reflexive_qcache; template class reflexive_qcache )> { A & x; public: reflexive_qcache(A & x_):x(x_){} reflexive_qcache(reflexive_qcache const &) = delete; typedef A & exposed_type; exposed_type operator()() const {return x;} }; template class reflexive_qcache )> : const_qcache { typedef const_qcache B; public : explicit reflexive_qcache(A const & x) : B(x) {} reflexive_qcache(reflexive_qcache const &) = delete; ~reflexive_qcache() { this->back_update();} typedef A exposed_type; exposed_type operator()() { return B::view(); } }; }}}//namespace triqs::arrays::blas_lapack #endif