3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 13:53:40 +01:00

arrays: new ref counting and weak views

- improve the mem_block and shared_block.
- the reference counting is now done in the mem_block and shared_block, removing the need of shared_ptr.

- speed tests shows that shared_ptr is very slow (due to thread safety?)
the new version is much better, though not perfect.

- Hence introducing weak views.

- also :
-- clean the guard mechanism for python (to allow returning from python without any python ref left).
-- clean code, add documentation for mem_block
-- remove nan init, which was not working, and corresponding test
-- serialisation of view still unchanged (need to forbid serialization of view ??).

- tests ok, incl. valgrind tests.
This commit is contained in:
Olivier Parcollet 2013-06-25 22:29:14 +02:00
parent 6bf0d0f6b5
commit fc2a620eae
27 changed files with 570 additions and 420 deletions

77
test/speed/array_view.cpp Normal file
View File

@ -0,0 +1,77 @@
//#define TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
#include <triqs/arrays.hpp>
#include <triqs/arrays/matrix_view_proxy.hpp>
using namespace triqs::arrays;
#define TEST(X) std::cout << BOOST_PP_STRINGIZE((X)) << " ---> "<< (X) <<std::endl<<std::endl;
const int nl_interne = 100000;
const int N = 1000;
typedef double VALUE_TYPE;
//typedef int VALUE_TYPE;
inline VALUE_TYPE fnt(size_t i) { return i*(i+2.0)*(i-8.0);}
//inline VALUE_TYPE fnt(size_t i) { return i;} //*(i+2.0)*(i-8);}
//inline VALUE_TYPE fnt(size_t i) { return i*(i+2.0)*(i-8);}
struct with_view {
void operator()() {
array<double,3> A(N,2,2);
A() =0;
for (int u =0; u<nl_interne; ++u)
for (int i =0; i<N-1; ++i) A(i,range(), range()) (0,0) = fnt(i);
}
};
struct with_proxy {
void operator()() {
array<double,3> A(N,2,2);
A() =0;
for (int u =0; u<nl_interne; ++u)
for (int i =0; i<N-1; ++i) matrix_view_proxy<array<double,3>, 0>(A,i) (0,0) = fnt(i);
}
};
struct direct {
void operator()() {
array<double,3> A(N,2,2);
A() =0;
for (int u =0; u<nl_interne; ++u)
for (int i =0; i<N-1; ++i) A(i,0,0) = fnt(i);
}
};
struct direct2 {
void operator()() {
array<double,1> A(N);
A() =0;
for (int u =0; u<nl_interne; ++u)
for (int i =0; i<N-1; ++i) A(i) = fnt(i);
}
};
#include "./speed_tester.hpp"
int main() {
speed_tester<direct> (50);
speed_tester<with_proxy> (50);
speed_tester<with_view> (50);
speed_tester<direct2> (50);
//speed_tester<with_slices> (5000);
return 0;
}

View File

@ -22,9 +22,12 @@
#ifndef COMMON_TEST_ARRAY_H
#define COMMON_TEST_ARRAY_H
#include<triqs/utility/first_include.hpp>
#include<sstream>
#define TEST(X) std::cout << BOOST_PP_STRINGIZE((X)) << " ---> "<< (X) <<std::endl;
#define TEST_ASSERT(X) if(!bool(X)) { std::stringstream fs; fs<< "Failed Assertion line "<< __LINE__<< " of file "<< __FILE__<<" :\n"<<BOOST_PP_STRINGIZE((X)); std::cout << fs.str()<< std::endl ; TRIQS_RUNTIME_ERROR<< fs.str();}
#define AS_STRING(X) AS_STRING2(X)
#define AS_STRING2(X) #X

View File

@ -1,43 +0,0 @@
/*******************************************************************************
*
* 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 <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#include "./common.hpp"
#include "./src/array.hpp"
#include "./src/matrix.hpp"
#include <iostream>
using std::cout; using std::endl;
using namespace triqs::arrays;
int main(int argc, char **argv) {
array<long,2, NanInit > A (2,2);
array<double,2, NanInit > B (2,2);
array<std::complex<double> ,2, NanInit > C (2,2);
std::cerr << A << std::endl ;
std::cerr << B << std::endl ;
std::cerr << C << std::endl ;
return 0;
}

View File

@ -51,16 +51,14 @@ int main(int argc, char **argv) {
triqs::arrays::vector<double> V(3), W(4);;
V() = 3; W()=4;
auto VV = V(tqa::range (0,2));
auto VW = W(tqa::range (0,2));
std::cout << "V = "<< V << " W = " << W<< " V view "<< VV<< " W view "<< VW<< std::endl;
std::cout << "V = "<< V << " W = " << W<< std::endl;
std::swap(V,W);
std::cout << "V = "<< V << " W = " << W<< " V view "<< VV<< " W view "<< VW<< std::endl;
std::cout << "V = "<< V << " W = " << W<< std::endl;
// This does NOT compile, the std::swap specialization is deleted.
auto VV = V(tqa::range (0,2));
auto VW = W(tqa::range (0,2));
//std::swap(VV,VW);
//std::cout << "V = "<< V << " W = " << W<< " V view "<< VV<< " W view "<< VW<< std::endl;
}
std::cout << "With deep_swap"<< std::endl;

View File

@ -3,8 +3,8 @@ V = [3,3,3] W = [4,4,4,4] V view [3,3] W view [4,4]
V = [4,4,4,4] W = [3,3,3] V view [3,3] W view [4,4]
V = [4,4,4,4] W = [3,3,3] V view [4,4] W view [3,3]
With std::swap
V = [3,3,3] W = [4,4,4,4] V view [3,3] W view [4,4]
V = [4,4,4,4] W = [3,3,3] V view [3,3] W view [4,4]
V = [3,3,3] W = [4,4,4,4]
V = [4,4,4,4] W = [3,3,3]
With deep_swap
V = [3,3,3] W = [4,4,4] V view [3,3] W view [4,4]
V = [4,4,4] W = [3,3,3] V view [4,4] W view [3,3]

View File

@ -48,7 +48,7 @@ int main(int argc, char **argv) {
for (int j=0; j<3; ++j)
A(i,j) = 10*i+ j;
array_view<long const ,2 > AA (A);
array_view<long,2 > AA (A);
std::cout<<"A is "<<A<<std::endl;
std::cout<<"another view : "<<AA<<std::endl;

View File

@ -28,22 +28,23 @@
#include "impl/flags.hpp"
namespace triqs { namespace arrays {
template <typename ValueType, int Rank, ull_t Opt=0, ull_t TraversalOrder= 0> class array_view;
template <typename ValueType, int Rank, ull_t Opt=0, ull_t TraversalOrder= 0, bool Borrowed=false > class array_view;
template <typename ValueType, int Rank, ull_t Opt=0, ull_t TraversalOrder= 0> class array;
// ---------------------- array_view --------------------------------
#define IMPL_TYPE indexmap_storage_pair< indexmaps::cuboid::map<Rank,Opt,TraversalOrder>, \
storages::shared_block<ValueType>, Opt, TraversalOrder, Tag::array_view >
storages::shared_block<ValueType, Borrowed>, Opt, TraversalOrder, Tag::array_view >
template <typename ValueType, int Rank, ull_t Opt, ull_t TraversalOrder>
template <typename ValueType, int Rank, ull_t Opt, ull_t TraversalOrder, bool Borrowed>
class array_view : Tag::array_view, TRIQS_MODEL_CONCEPT(MutableCuboidArray), public IMPL_TYPE {
static_assert( Rank>0, " Rank must be >0");
public:
typedef typename IMPL_TYPE::indexmap_type indexmap_type;
typedef typename IMPL_TYPE::storage_type storage_type;
typedef array_view<ValueType,Rank,Opt,TraversalOrder> view_type;
typedef array<ValueType,Rank,Opt,TraversalOrder> non_view_type;
typedef array <ValueType,Rank,Opt,TraversalOrder> non_view_type;
typedef array_view<ValueType,Rank,Opt,TraversalOrder> view_type;
typedef array_view<ValueType,Rank,Opt,TraversalOrder,true> weak_view_type;
typedef void has_view_type_tag;
/// Build from an IndexMap and a storage
@ -80,19 +81,27 @@ namespace triqs { namespace arrays {
// Move assignment not defined : will use the copy = since view must copy data
TRIQS_DEFINE_COMPOUND_OPERATORS(array_view);
// to forbid serialization of views...
//template<class Archive> void serialize(Archive & ar, const unsigned int version) = delete;
};
#undef IMPL_TYPE
//------------------------------- array ---------------------------------------------------
#define IMPL_TYPE indexmap_storage_pair< indexmaps::cuboid::map<Rank,Opt,TraversalOrder>, \
storages::shared_block<ValueType>, Opt, TraversalOrder, Tag::array_view >
template <typename ValueType, int Rank, ull_t Opt, ull_t TraversalOrder>
class array: Tag::array, TRIQS_MODEL_CONCEPT(MutableCuboidArray), public IMPL_TYPE {
public:
typedef typename IMPL_TYPE::value_type value_type;
typedef typename IMPL_TYPE::storage_type storage_type;
typedef typename IMPL_TYPE::indexmap_type indexmap_type;
typedef array_view<ValueType,Rank,Opt,TraversalOrder> view_type;
typedef array<ValueType,Rank,Opt,TraversalOrder> non_view_type;
typedef void has_view_type_tag;
typedef array <ValueType,Rank,Opt,TraversalOrder> non_view_type;
typedef array_view<ValueType,Rank,Opt,TraversalOrder> view_type;
typedef array_view<ValueType,Rank,Opt,TraversalOrder,true> weak_view_type;
typedef void has_view_type_tag;
/// Empty array.
explicit array(memory_layout<Rank> ml = memory_layout<Rank>(IMPL_TYPE::indexmap_type::traversal_order)) :IMPL_TYPE(ml){}
@ -190,7 +199,8 @@ namespace triqs { namespace arrays {
//----------------------------------------------------------------------------------
// how to build the view type ....
template < class V, int R, ull_t Opt, ull_t TraversalOrder > struct ViewFactory< V, R, Opt, TraversalOrder,Tag::array_view > { typedef array_view<V,R,Opt,TraversalOrder> type; };
template < class V, int R, ull_t Opt, ull_t TraversalOrder, bool Borrowed >
struct ISPViewType< V, R, Opt, TraversalOrder,Tag::array_view, Borrowed> { typedef array_view<V,R,Opt,TraversalOrder, Borrowed> type; };
}}//namespace triqs::arrays

View File

@ -79,10 +79,10 @@ namespace triqs { namespace arrays { namespace blas_lapack_tools {
// 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 <typename T> constexpr bool copy_is_needed (T const & A) { return false;}
template <typename T> constexpr TYPE_ENABLE_IFC(bool, !is_matrix_view<T>::value) copy_is_needed (T const & A) { return false;}
template <typename T, ull_t Opt, ull_t To>
bool copy_is_needed (matrix_view<T,Opt,To> const & A) {
template <typename MatrixView>
TYPE_ENABLE_IF(bool, is_matrix_view<MatrixView>) copy_is_needed (MatrixView const & A) {
auto min_stride = A.indexmap().strides()[A.memory_layout_is_fortran() ? 0 : 1];
return min_stride !=1;
}

View File

@ -65,8 +65,8 @@ namespace triqs { namespace arrays {
}
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
internal_data & id() const { if (!_id) _id= boost::make_shared<internal_data>(*this,ml); return *_id;}
mutable std::shared_ptr<internal_data> _id;
internal_data & id() const { if (!_id) _id= std::make_shared<internal_data>(*this,ml); return *_id;}
//exposed_view_type & view2 () { if (need_copy) return id().view; else return keeper;}
//exposed_view_type const & view2 () const { if (need_copy) return id().view; else return keeper;}

View File

@ -33,8 +33,6 @@
#include <sstream>
#include <boost/utility/enable_if.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
@ -57,12 +55,17 @@ namespace boost { namespace serialization { class access;}}
#define TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
#define TRIQS_ARRAYS_CHECK_IM_STORAGE_COMPAT
#define TRIQS_ARRAYS_ENFORCE_INIT_NAN_INF
#else
#define TRIQS_ARRAYS_DEBUG_CHECK(Cond,Error)
#endif
// In particular, gcc 4.6, 4.7 do not have "rvalue for *this", which forbid the implementation
// of weak references. In that we, we will revert to strong view instead.
#ifdef TRIQS_COMPILER_IS_OBSOLETE
#define TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED
#endif
namespace triqs {
typedef unsigned long long ull_t;

View File

@ -37,7 +37,7 @@ namespace triqs { namespace arrays {
constexpr ull_t BoundCheck = 1ull << 0;
constexpr ull_t TraversalOrderC = 1ull << 1;
constexpr ull_t TraversalOrderFortran = 1ull << 2;
constexpr ull_t NanInit = 1ull << 3;
//constexpr ull_t NanInit = 1ull << 3;
constexpr ull_t DefaultInit = 1ull << 4;
#define BOUND_CHECK triqs::arrays::BoundCheck
@ -48,12 +48,12 @@ namespace triqs { namespace arrays {
// NB : flags MUST be insensitive to slicing ...
// i.e. when I slice, the flags does not change.
namespace flags {
namespace flags {
#ifndef TRIQS_WORKAROUND_INTEL_COMPILER_BUGS
constexpr ull_t get(ull_t f, ull_t a) { return ((f & (1ull<<a)) >> a);}
constexpr ull_t get2(ull_t f, ull_t a) { return (f & (((1ull<<a) + (1ull<< (a+1ull))) >> a) );}
constexpr ull_t get2(ull_t f, ull_t a) { return ((f & ((1ull<<a) + (1ull<< (a+1ull)))) >> a);}
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
constexpr bool bound_check (ull_t f) { return true;}
@ -71,14 +71,14 @@ namespace triqs { namespace arrays {
template<ull_t F> struct init_tag1;
template<> struct init_tag1<0> { typedef Tag::no_init type;};
template<> struct init_tag1<1> { typedef Tag::nan_inf_init type;};
//template<> struct init_tag1<1> { typedef Tag::nan_inf_init type;};
template<> struct init_tag1<2> { typedef Tag::default_init type;};
// for the init_tag, we pass the *whole* option flag.
template<ull_t F> struct init_tag : init_tag1 < init_mode(F)> {};
template<ull_t F, ull_t To> struct assert_make_sense {
static constexpr bool bc = bound_check(F);;
static constexpr bool bc = bound_check(F);
static constexpr bool is_c = traversal_order_c(F);
static constexpr bool is_f = traversal_order_fortran(F);
static constexpr bool inm = check_init_mode(F);
@ -90,8 +90,8 @@ namespace triqs { namespace arrays {
#else
#define TRIQS_FLAGS_GET(f,a) ((f & (1ull<<a)) >> a)
#define TRIQS_FLAGS_GET2(f,a) (f & (((1ull<<a) + (1ull<< (a+1ull))) >> a))
#define TRIQS_FLAGS_GET2(f,a) ((f & ((1ull<<a) + (1ull<< (a+1ull)))) >> a)
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
template< ull_t F> struct bound_check_trait { static constexpr bool value = true;};
#else
@ -105,7 +105,7 @@ namespace triqs { namespace arrays {
template<ull_t F> struct init_tag1;
template<> struct init_tag1<0> { typedef Tag::no_init type;};
template<> struct init_tag1<1> { typedef Tag::nan_inf_init type;};
//template<> struct init_tag1<1> { typedef Tag::nan_inf_init type;};
template<> struct init_tag1<2> { typedef Tag::default_init type;};
template<ull_t F> struct init_tag : init_tag1 < init_mode_tr<F>::value > {};

View File

@ -40,7 +40,7 @@ namespace triqs { namespace arrays {
template <bool Const, typename IndexMapIterator, typename StorageType > class iterator_adapter;
template < class V, int R, ull_t OptionFlags, ull_t TraversalOrder, class ViewTag > struct ViewFactory;
template < class V, int R, ull_t OptionFlags, ull_t TraversalOrder, class ViewTag, bool Borrowed > struct ISPViewType;
template <typename IndexMapType, typename StorageType, ull_t OptionFlags, ull_t TraversalOrder, typename ViewTag >
class indexmap_storage_pair : Tag::indexmap_storage_pair, TRIQS_MODEL_CONCEPT(MutableArray) {
@ -48,7 +48,7 @@ namespace triqs { namespace arrays {
public :
typedef typename StorageType::value_type value_type;
static_assert(std::is_constructible<value_type>::value, "array/array_view and const operate only on values");
//static_assert(!std::is_const<value_type>::value, "no const type");
static_assert(!std::is_const<value_type>::value, "no const type");
typedef StorageType storage_type;
typedef IndexMapType indexmap_type;
static constexpr unsigned int rank = IndexMapType::domain_type::rank;
@ -63,6 +63,7 @@ namespace triqs { namespace arrays {
indexmap_storage_pair (const indexmap_type & IM, const storage_type & ST):
indexmap_(IM),storage_(ST){
//std::cerr << " construct ISP "<< storage_type::is_weak<< std::endl;
#ifdef TRIQS_ARRAYS_CHECK_IM_STORAGE_COMPAT
if (ST.size() != IM.domain().number_of_elements())
TRIQS_RUNTIME_ERROR<<"index_storage_pair construction : storage and indices are not compatible";
@ -71,12 +72,21 @@ namespace triqs { namespace arrays {
indexmap_storage_pair (indexmap_type && IM, storage_type && ST):
indexmap_(std::move(IM)),storage_(std::move(ST)){
//std::cerr << " construct ISP && IM, && ST "<< storage_type::is_weak<< std::endl;
#ifdef TRIQS_ARRAYS_CHECK_IM_STORAGE_COMPAT
if (ST.size() != IM.domain().number_of_elements())
TRIQS_RUNTIME_ERROR<<"index_storage_pair construction : storage and indices are not compatible";
#endif
}
indexmap_storage_pair (indexmap_type const & IM, storage_type && ST):
indexmap_(IM),storage_(std::move(ST)){
//std::cerr << " construct ISP && ST "<< storage_type::is_weak<< std::endl;
#ifdef TRIQS_ARRAYS_CHECK_IM_STORAGE_COMPAT
if (ST.size() != IM.domain().number_of_elements())
TRIQS_RUNTIME_ERROR<<"index_storage_pair construction : storage and indices are not compatible";
#endif
}
/// The storage is allocated from the size of IM.
indexmap_storage_pair (const indexmap_type & IM): indexmap_(IM),storage_(){
@ -107,7 +117,7 @@ namespace triqs { namespace arrays {
<<"\nfrom the python object \n"<< numpy_interface::object_to_string(X)
<<"\nThe error was :\n "<<s.what();
}
//std::cout << " Leave IPS ref count = "<< X->ob_refcnt << std::endl;
//std::cerr << " Leave IPS ref count = "<< X->ob_refcnt << std::endl;
}
#endif
// ------------------------------- swap --------------------------------------------
@ -172,6 +182,9 @@ namespace triqs { namespace arrays {
// ------------------------------- operator () --------------------------------------------
typedef typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag,false >::type view_type;
typedef typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag,true >::type weak_view_type;
// Evaluation and slices
template<typename... Args>
typename std::enable_if<
@ -185,32 +198,82 @@ namespace triqs { namespace arrays {
, value_type const &>::type
operator()(Args const & ... args) const { return storage_[indexmap_(args...)]; }
template<bool is_const, typename ... Args> struct result_of_call_as_view {
template<bool is_const, bool ForceBorrowed, typename ... Args> struct result_of_call_as_view {
typedef typename indexmaps::slicer<indexmap_type,Args...>::r_type IM2;
typedef typename std::conditional<is_const, typename std::add_const<value_type>::type, value_type>::type V2;
//typedef typename std::conditional<is_const, typename std::add_const<value_type>::type, value_type>::type V2;
typedef value_type V2;
static_assert(IM2::domain_type::rank !=0, "Internal error");
typedef typename ViewFactory<V2,IM2::domain_type::rank, OptionFlags, IM2::traversal_order_in_template, ViewTag >::type type;
typedef typename ISPViewType<V2,IM2::domain_type::rank, OptionFlags, IM2::traversal_order_in_template, ViewTag, ForceBorrowed || StorageType::is_weak >::type type;
};
// change here only for debug
//#define TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED
#ifndef TRIQS_ARRAYS_SLICE_DEFAUT_IS_SHARED
template<typename... Args> // non const version
typename boost::lazy_enable_if_c<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0)
, result_of_call_as_view<false,Args...>
, result_of_call_as_view<false,true,Args...>
>::type // enable_if
operator()(Args const & ... args) {
return typename result_of_call_as_view<false,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), storage()); }
operator()(Args const & ... args) & {
return typename result_of_call_as_view<false,true,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), storage()); }
template<typename... Args> // const version
typename boost::lazy_enable_if_c<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0)
, result_of_call_as_view<true,Args...>
, result_of_call_as_view<true,true,Args...>
>::type // enable_if
operator()(Args const & ... args) const & {
return typename result_of_call_as_view<true,true,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), storage()); }
template<typename... Args> // rvalue version : same value of weak as this
typename boost::lazy_enable_if_c<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0)
, result_of_call_as_view<true,false,Args...>
>::type // enable_if
operator()(Args const & ... args) && {
//std::cerr << "slicing a temporary"<< this->storage().is_weak<< result_of_call_as_view<true,true,Args...>::type::storage_type::is_weak << std::endl;
return typename result_of_call_as_view<true,false,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), std::move(storage()));
}
/// Equivalent to make_view
//typename ISPViewType<typename std::add_const<value_type>::type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag >::type
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, true >::type
operator()() const & { return *this; }
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, true >::type
operator()() & { return *this; }
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, StorageType::is_weak >::type
operator()() && { return *this; }
#else
template<typename... Args> // non const version
typename boost::lazy_enable_if_c<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0)
, result_of_call_as_view<false,false,Args...>
>::type // enable_if
operator()(Args const & ... args) {
return typename result_of_call_as_view<false,false,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), storage()); }
template<typename... Args> // const version
typename boost::lazy_enable_if_c<
(!clef::is_any_lazy<Args...>::value) && (indexmaps::slicer<indexmap_type,Args...>::r_type::domain_type::rank!=0)
, result_of_call_as_view<true,false,Args...>
>::type // enable_if
operator()(Args const & ... args) const {
return typename result_of_call_as_view<true,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), storage()); }
return typename result_of_call_as_view<true,false,Args...>::type ( indexmaps::slicer<indexmap_type,Args...>::invoke(indexmap_,args...), storage()); }
typedef typename ViewFactory<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag >::type view_type;
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression
/// Equivalent to make_view
//typename ISPViewType<typename std::add_const<value_type>::type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag >::type
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, false >::type
operator()() const { return *this; }
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, false >::type
operator()() { return *this; }
#endif
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression
// NB : this is ok because indexmap_storage_pair has a shallow copy constructor ...
// so A(i_) if A is an array will NOT copy the data....
template< typename... Args>
@ -223,12 +286,6 @@ namespace triqs { namespace arrays {
template<typename Fnt> friend void triqs_clef_auto_assign (indexmap_storage_pair & x, Fnt f) { assign_foreach(x,f);}
/// Equivalent to make_view
typename ViewFactory<typename std::add_const<value_type>::type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag >::type
operator()() const { return *this; }
typename ViewFactory<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag >::type
operator()() { return *this; }
// ------------------------------- Iterators --------------------------------------------
typedef iterator_adapter<true,typename IndexMapType::iterator, StorageType> const_iterator;
typedef iterator_adapter<false,typename IndexMapType::iterator, StorageType> iterator;

View File

@ -35,6 +35,7 @@ namespace triqs { namespace arrays {
r(0) = A(1)* B(2) - B(1) * A(2);
r(1) = - A(0)* B(2) + B(0) * A(2);
r(2) = A(0)*B(1) - B(0) * A(1);
std::cout << "in cross product "<< A << B << r << std::endl;
return r;
}

View File

@ -133,8 +133,8 @@ namespace triqs { namespace arrays {
internal_data(inverse_lazy_impl const & P):M(P.a){det_and_inverse_worker<M_view_type> worker(M); worker.inverse();}
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= boost::make_shared<internal_data>(*this);}
mutable std::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= std::make_shared<internal_data>(*this);}
};
// The general case
@ -179,8 +179,8 @@ namespace triqs { namespace arrays {
internal_data(determinant_lazy const & P):M(P.a){det_and_inverse_worker<A_type> worker(M); det = worker.det();}
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= boost::make_shared<internal_data>(*this);}
mutable std::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= std::make_shared<internal_data>(*this);}
};
}} // namespace triqs::arrays

View File

@ -80,7 +80,7 @@ namespace triqs { namespace arrays { namespace linalg {
protected:
eigenelements_worker_base ( matrix_view <T,Opt> the_matrix) : eigenelements_worker_base <T,Opt,false> (the_matrix) {this->compz='V'; }
public:
matrix<T,Opt> vectors() const {
typename matrix_view<T,Opt>::non_view_type vectors() const {
if (!this->has_run) TRIQS_RUNTIME_ERROR<<"eigenelements_worker has not been invoked !";
return this->mat;
}
@ -152,8 +152,10 @@ namespace triqs { namespace arrays { namespace linalg {
* if true : a copy is made, M is preserved, but of course it is slower...
*/
template<typename MatrixViewType >
std::pair<array<double,1>, typename MatrixViewType::non_view_type> eigenelements( MatrixViewType M, bool take_copy =false) {
eigenelements_worker<MatrixViewType, true> W(take_copy ? make_clone(M)() : M()); W.invoke(); return std::make_pair(W.values(),W.vectors());
std::pair<array<double,1>, typename MatrixViewType::non_view_type> eigenelements( MatrixViewType const & M, bool take_copy =false) {
eigenelements_worker<typename MatrixViewType::view_type, true> W(take_copy ? MatrixViewType(make_clone(M)) : M);
W.invoke();
return std::make_pair(W.values(),W.vectors());
}
//--------------------------------
@ -167,8 +169,8 @@ namespace triqs { namespace arrays { namespace linalg {
* if true : a copy is made, M is preserved, but of course it is slower...
*/
template<typename MatrixViewType >
triqs::arrays::vector_view <double> eigenvalues( MatrixViewType M, bool take_copy = false) {
eigenelements_worker<MatrixViewType,false> W(take_copy ? make_clone(M)() : M()); W.invoke(); return W.values();
triqs::arrays::vector_view <double> eigenvalues( MatrixViewType const & M, bool take_copy = false) {
eigenelements_worker<MatrixViewType,false> W(take_copy ? MatrixViewType(make_clone(M)) : M); W.invoke(); return W.values();
}
}}} // namespace triqs::arrays::linalg

View File

@ -111,7 +111,7 @@ namespace triqs { namespace arrays {
// an implementation class to gather the common part to matrix and expression....
template<typename A> struct inverse_lazy_impl : TRIQS_MODEL_CONCEPT(ImmutableMatrix) {
typedef typename boost::remove_const<typename A::value_type>::type value_type;
typedef typename std::remove_const<typename A::value_type>::type value_type;
typedef typename A::domain_type domain_type;
typedef typename domain_type::index_value_type index_value_type;
typedef typename const_view_type_if_exists_else_type<A>::type A_type;
@ -133,8 +133,8 @@ namespace triqs { namespace arrays {
internal_data(inverse_lazy_impl const & P):M(P.a){det_and_inverse_worker<M_view_type> worker(M); worker.inverse();}
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= boost::make_shared<internal_data>(*this);}
mutable std::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= std::make_shared<internal_data>(*this);}
};
// The general case
@ -179,8 +179,8 @@ namespace triqs { namespace arrays {
internal_data(determinant_lazy const & P):M(P.a){det_and_inverse_worker<A_type> worker(M); det = worker.det();}
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= boost::make_shared<internal_data>(*this);}
mutable std::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= std::make_shared<internal_data>(*this);}
};
}} // namespace triqs::arrays

View File

@ -58,8 +58,8 @@ namespace triqs { namespace arrays {
internal_data(mat_vec_mul_lazy const & P): R(P.M.dim0()) { blas::gemv(1,P.M,P.V,0,R); }
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= boost::make_shared<internal_data>(*this);}
mutable std::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= std::make_shared<internal_data>(*this);}
public:
mat_vec_mul_lazy( MT const & M_, VT const & V_):M(M_),V(V_){

View File

@ -52,8 +52,8 @@ namespace triqs { namespace arrays {
internal_data(matmul_lazy const & P): R( P.a.dim0(), P.b.dim1()) { blas::gemm(1.0,P.a, P.b, 0.0, R); }
};
friend struct internal_data;
mutable boost::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= boost::make_shared<internal_data>(*this);}
mutable std::shared_ptr<internal_data> _id;
void activate() const { if (!_id) _id= std::make_shared<internal_data>(*this);}
public:
matmul_lazy( A const & a_, B const & b_):a(a_),b(b_){
@ -83,7 +83,7 @@ namespace triqs { namespace arrays {
private:
template<typename LHS> void assign_comp_impl (LHS & lhs, double S) const {
static_assert((is_matrix_or_view<LHS>::value), "LHS is not a matrix");
static_assert((is_matrix_or_view<LHS>::value), "LHS is not a matrix");
if (lhs.dim0() != dim0())
TRIQS_RUNTIME_ERROR<< "Matmul : +=/-= operator : first dimension mismatch in A*B "<< lhs.dim0()<<" vs "<< dim0();
if (lhs.dim1() != dim1())

View File

@ -27,7 +27,7 @@
#include "vector.hpp"
namespace triqs { namespace arrays {
template <typename ValueType, ull_t Opt=0, ull_t TraversalOrder= 0> class matrix_view;
template <typename ValueType, ull_t Opt=0, ull_t TraversalOrder= 0, bool Borrowed = false> class matrix_view;
template <typename ValueType, ull_t Opt=0, ull_t TraversalOrder= 0> class matrix;
// ---------------------- matrix --------------------------------
@ -46,13 +46,14 @@ namespace triqs { namespace arrays {
bool memory_layout_is_fortran() const { return this->indexmap().strides()[0] < this->indexmap().strides()[1]; }
#define IMPL_TYPE indexmap_storage_pair < indexmaps::cuboid::map<2,Opt,TraversalOrder>, \
storages::shared_block<ValueType>, Opt, TraversalOrder, Tag::matrix_view >
storages::shared_block<ValueType,Borrowed>, Opt, TraversalOrder, Tag::matrix_view >
template <typename ValueType, ull_t Opt, ull_t TraversalOrder >
template <typename ValueType, ull_t Opt, ull_t TraversalOrder, bool Borrowed>
class matrix_view : Tag::matrix_view, TRIQS_MODEL_CONCEPT(MutableMatrix), public IMPL_TYPE {
public :
typedef matrix_view<ValueType,Opt,TraversalOrder> view_type;
typedef matrix<ValueType,Opt,TraversalOrder> non_view_type;
typedef matrix <ValueType,Opt,TraversalOrder> non_view_type;
typedef matrix_view<ValueType,Opt,TraversalOrder> view_type;
typedef matrix_view<ValueType,Opt,TraversalOrder,true> weak_view_type;
typedef void has_view_type_tag;
typedef typename IMPL_TYPE::indexmap_type indexmap_type;
@ -96,11 +97,15 @@ namespace triqs { namespace arrays {
//---------------------------------------------------------------------
// this traits is used by indexmap_storage_pair, when slicing to find the correct view type.
template < class V, int R, ull_t OptionFlags, ull_t To > struct ViewFactory< V, R, OptionFlags, To, Tag::matrix_view> {
typedef typename std::conditional <R == 1, vector_view<V,OptionFlags >, matrix_view<V,OptionFlags, To > >::type type;
template < class V, int R, ull_t OptionFlags, ull_t To, bool Borrowed >
struct ISPViewType< V, R, OptionFlags, To, Tag::matrix_view, Borrowed> {
typedef typename std::conditional <R == 1, vector_view<V,OptionFlags,Borrowed >, matrix_view<V,OptionFlags, To, Borrowed > >::type type;
};
#undef IMPL_TYPE
// ---------------------- matrix --------------------------------
#define IMPL_TYPE indexmap_storage_pair < indexmaps::cuboid::map<2,Opt,TraversalOrder>, \
storages::shared_block<ValueType>, Opt, TraversalOrder, Tag::matrix_view >
template <typename ValueType, ull_t Opt, ull_t TraversalOrder >
class matrix: Tag::matrix, TRIQS_MODEL_CONCEPT(MutableMatrix), public IMPL_TYPE {
@ -108,8 +113,9 @@ namespace triqs { namespace arrays {
typedef typename IMPL_TYPE::value_type value_type;
typedef typename IMPL_TYPE::storage_type storage_type;
typedef typename IMPL_TYPE::indexmap_type indexmap_type;
typedef matrix_view<ValueType,Opt,TraversalOrder> view_type;
typedef matrix<ValueType,Opt,TraversalOrder> non_view_type;
typedef matrix <ValueType,Opt,TraversalOrder> non_view_type;
typedef matrix_view<ValueType,Opt,TraversalOrder> view_type;
typedef matrix_view<ValueType,Opt,TraversalOrder,true> weak_view_type;
typedef void has_view_type_tag;
/// Empty matrix.

View File

@ -52,12 +52,12 @@ namespace triqs { namespace arrays { namespace numpy_interface {
}
if (!PyArray_Check(res)) TRIQS_RUNTIME_ERROR<<" array_view_from_numpy : internal error : the python object is not a numpy";
PyArrayObject * arr = (PyArrayObject *)(res);
//PyArray_SetBaseObject(arr, A.storage().new_ref_to_guard());
//PyArray_SetBaseObject(arr, A.storage().new_python_ref());
#ifdef TRIQS_NUMPY_VERSION_LT_17
arr->base = A.storage().new_ref_to_guard();
arr->base = A.storage().new_python_ref();
assert( arr->flags == (arr->flags & ~NPY_OWNDATA));
#else
int r = PyArray_SetBaseObject(arr,A.storage().new_ref_to_guard());
int r = PyArray_SetBaseObject(arr,A.storage().new_python_ref());
if (r!=0) TRIQS_RUNTIME_ERROR << "Internal Error setting the guard in numpy !!!!";
assert( PyArray_FLAGS(arr) == (PyArray_FLAGS(arr) & ~NPY_ARRAY_OWNDATA));
#endif

View File

@ -1,68 +0,0 @@
/*******************************************************************************
*
* 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 <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#ifndef TRIQS_ARRAYS_BASIC_BLOCK_H
#define TRIQS_ARRAYS_BASIC_BLOCK_H
#include <boost/noncopyable.hpp>
// A minimal basic block : replace by a vector<> or is it quicker ?
namespace triqs { namespace arrays { namespace storages { namespace details {
template<typename ValueType >
struct basic_block : boost::noncopyable {
typedef typename boost::remove_const<ValueType>::type non_const_value_type;
size_t size_;
non_const_value_type * restrict p;
basic_block():size_(0),p(NULL){}
basic_block (size_t s):size_(s),p(new non_const_value_type[s]) { }
~basic_block(){if (p) {delete[] p; } }
void operator=(const basic_block & X) {
assert(size_==X.size_);assert(p); assert(X.p);
memcpy (p,X.p,size_ * sizeof(ValueType));
}
non_const_value_type & operator[](size_t i) {return p[i];}
size_t size() const {return size_;}
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
ar << boost::serialization::make_nvp("size",size_);
for (size_t i=0; i<size_; ++i) ar << boost::serialization::make_nvp("data",p[i]);
}
template<class Archive>
void load(Archive & ar, const unsigned int version) {
ar >> size_;
assert (p==NULL);
p = new non_const_value_type[size_];
for (size_t i=0; i<size_; ++i) ar >> p[i];
}
BOOST_SERIALIZATION_SPLIT_MEMBER();
};
}}}}//namespace triqs::arrays ...
#endif

View File

@ -1,4 +1,3 @@
/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
@ -19,137 +18,263 @@
* TRIQS. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#ifndef TRIQS_MEM_BLOCK_H
#ifndef TRIQS_MEM_BLOCK_H
#define TRIQS_MEM_BLOCK_H
#include "../../utility/exceptions.hpp"
#include <Python.h>
#include <numpy/arrayobject.h>
#include "./memcopy.hpp"
#include <triqs/utility/macros.hpp>
//#define TRIQS_ARRAYS_DEBUG_TRACE_MEM
#ifdef TRIQS_ARRAYS_DEBUG_TRACE_MEM
#include <iostream>
#define TRACE_MEM_DEBUG(X) std::cerr<< X << std::endl;
#define TRACE_MEM_DEBUG(X) std::cerr<< X << std::endl;
#else
#define TRACE_MEM_DEBUG(X)
#define TRACE_MEM_DEBUG(X)
#endif
namespace triqs { namespace arrays { namespace storages { namespace details {
template<typename ValueType> class mem_block {
// if no python, same code but remove python parts...
#ifndef TRIQS_WITH_PYTHON_SUPPORT
typedef void PyObject;
#define Py_DECREF(P)
#endif
typedef typename boost::remove_const<ValueType>::type non_const_value_type;
size_t size_;
non_const_value_type * restrict p;
PyObject * py_obj;
static void import_numpy_array() { if (_import_array()!=0) TRIQS_RUNTIME_ERROR <<"Internal Error in importing numpy";}
namespace triqs { namespace arrays { namespace storages { //namespace details {
public :
template<typename ValueType> struct mem_block; // forward
mem_block():size_(0),p(NULL),py_obj(NULL){}
// debug only, to check also weak refs. This will slow down a bit critical loops..
// I am not sure this is really useful ...
//#define TRIQS_ARRAYS_CHECK_WEAK_REFS
mem_block (size_t s):size_(s),py_obj(NULL){
//p = new non_const_value_type[s]; // check speed penalty for try ??
try { p = new non_const_value_type[s];}
catch (std::bad_alloc& ba) { TRIQS_RUNTIME_ERROR<< "Memory allocation error : bad_alloc : "<< ba.what();}
}
// the ref counting functions : weak means : no use of the reference counting system
template<bool Weak, typename ValueType> ENABLE_IFC(Weak) inc_ref(mem_block<ValueType> * const m) {
#ifdef TRIQS_ARRAYS_CHECK_WEAK_REFS
m->weak_ref_count++;
#endif
}
template<bool Weak, typename ValueType> DISABLE_IFC(Weak) inc_ref(mem_block<ValueType> * const m) { m->ref_count++;}
mem_block (PyObject * obj, bool borrowed ) {
TRACE_MEM_DEBUG(" construct memblock from pyobject"<<obj<< " # ref ="<<obj->ob_refcnt<<" borrowed = "<< borrowed);
assert(obj); import_numpy_array();
if (borrowed) Py_INCREF(obj);
if (!PyArray_Check(obj)) TRIQS_RUNTIME_ERROR<<"Internal error : mem_block construct from pyo : obj is not an array";
PyArrayObject * arr = (PyArrayObject *)(obj);
size_ = PyArray_SIZE(arr);
this->p = (non_const_value_type*)PyArray_DATA(arr);
py_obj = obj;
}
// force inline on gcc ?
//template<typename ValueType> void dec_ref(mem_block<ValueType> * const m) __attribute__((always_inline));
~mem_block(){ // delete memory manually iif py_obj is not set. Otherwise the python interpreter will do that for us.
TRACE_MEM_DEBUG("deleting mem block p ="<<p<< " py_obj = "<< py_obj << " ref of py obj if exists"<<(py_obj ? py_obj->ob_refcnt: -1));
if (py_obj==NULL) { if (p) { delete[] p;} }
else Py_DECREF(py_obj);
}
template<bool Weak, typename ValueType> ENABLE_IFC(Weak) dec_ref(mem_block<ValueType> * const m) {
#ifdef TRIQS_ARRAYS_CHECK_WEAK_REFS
m->weak_ref_count--;
#endif
}
void operator=(const mem_block & X) {
//assert( py_obj==NULL);
assert(size_==X.size_);assert(p); assert(X.p);
storages::memcopy (p, X.p, size_);
}
template<bool Weak, typename ValueType> DISABLE_IFC(Weak) dec_ref(mem_block<ValueType> * const m) {
m->ref_count--; if (m->ref_count ==0) {
#ifdef TRIQS_ARRAYS_CHECK_WEAK_REFS
std::cout << " detroying "<< m->weak_ref_count <<std::endl;
if (m->weak_ref_count !=0) TRIQS_RUNTIME_ERROR << "Deleting an memory block of an array with still "<< m->weak_ref_count<< " weak references";
#endif
delete m;
}
}
mem_block ( mem_block const & X): size_(X.size()), py_obj(NULL) {
//p = new non_const_value_type[s]; // check speed penalty for try ??
try { p = new non_const_value_type[X.size()];}
catch (std::bad_alloc& ba) { TRIQS_RUNTIME_ERROR<< "Memory allocation error : bad_alloc : "<< ba.what();}
if ((X.py_obj==NULL) || (PyCObject_Check(X.py_obj))) { (*this) = X; }
else {
// else make a new copy of the numpy ...
import_numpy_array();
//assert(PyArray_Check(X.py_obj));
if (!is_scalar_or_pod<ValueType>::value) TRIQS_RUNTIME_ERROR << "Internal Error : memcpy on non-scalar";
/**
* This is a block of memory (pointer p and size size_).
* INTERNAL USE only, by shared_block only
*
* The memory can be :
*
* - allocated (and deleted in C++)
* - owned by a numpy python object (py_numpy)
*
* The block contains its own reference system, to avoid the use of shared_ptr in shared_block
* (which was very slow in critical codes).
*
* In addition, the python guard system can return to python an array allocated in C++.
*
* The memory block has 4 possible states (and only 4) :
*
* * State 0) : p ==nullptr && py_numpy == nullptr && py_guard == nullptr
* Default state. Also obtained when the object has been moved from
*
* * State 1) : p !=nullptr && py_numpy == nullptr && py_guard == nullptr
* Memory block allocated and used in C++.
*
* * State 2) : p !=nullptr && py_numpy != nullptr && py_guard == nullptr
* Memory block was allocated by python, and is used in C++.
* The block keeps a python ref (owned!) in py_numpy which is released at destruction
*
* * State 3) : p !=nullptr && py_numpy == nullptr && py_guard != nullptr
* Memory block allocated by C++, but passed to python.
* The guard is an owned reference to a python object, which itself owns a c++ reference to the mem_block
* When the python is done with this object, it releases this reference and the mem_block
* can be destroyed (when nobody else uses it).
* This guarantees that :
* * as long as python does not clean the guard (which is then later attached to a numpy array, cf numpy interface)
* the block will not be deleted.
* * when python is done with this numpy, hence the guard, the c++ reference is dec_refed and
* the usage can continue normally in c++ (without *any* python ref contrary to a previous design).
*
* * Invariants :
* * py_numpy == nullptr || py_guard == nullptr :
* * ref_count >=1.
*/
template<typename ValueType> struct mem_block {
size_t size_; // size of the block
ValueType * restrict p; // the memory block. Owned by this, except when py_numpy is not null
size_t ref_count; // number of refs. : >=1
size_t weak_ref_count; // number of refs. : >=1
PyObject * py_numpy; // if not null, an owned reference to a numpy which is the data of this block
PyObject * py_guard; // if not null, a BORROWED reference to the guard. If null, the guard does not exist
static_assert(!std::is_const<ValueType>::value, "internal error");
#ifdef TRIQS_WITH_PYTHON_SUPPORT
static void import_numpy_array() { if (_import_array()!=0) TRIQS_RUNTIME_ERROR <<"Internal Error in importing numpy";}
#endif
//Construct to state 0
mem_block():size_(0),p(nullptr),py_numpy(nullptr), py_guard(nullptr), ref_count(1), weak_ref_count(0){}
// construct to state 1 with a given size.
mem_block (size_t s):size_(s),py_numpy(nullptr), py_guard(nullptr){
try { p = new ValueType[s];}
catch (std::bad_alloc& ba) { TRIQS_RUNTIME_ERROR<< "Memory allocation error : bad_alloc : "<< ba.what();}
ref_count=1;
weak_ref_count =0;
}
#ifdef TRIQS_WITH_PYTHON_SUPPORT
// construct to state 2. python_object_is_borrowed : whether the python ref is borrowed
mem_block (PyObject * obj, bool python_object_is_borrowed) {
TRACE_MEM_DEBUG(" construct memblock from pyobject"<<obj<< " # ref ="<<obj->ob_refcnt<<" python_object_is_borrowed = "<< python_object_is_borrowed);
assert(obj); import_numpy_array();
if (python_object_is_borrowed) Py_INCREF(obj);
if (!PyArray_Check(obj)) TRIQS_RUNTIME_ERROR<<"Internal error : mem_block construct from pyo : obj is not an array";
PyArrayObject * arr = (PyArrayObject *)(obj);
size_ = PyArray_SIZE(arr);
p = (ValueType*)PyArray_DATA(arr);
py_numpy = obj;
py_guard = nullptr;
ref_count=1;
weak_ref_count =0;
}
#endif
// destructor : release memory only in state 1. This should NEVER be called in state 3 (first need to get back to 1).
~mem_block(){ // delete memory manually iif py_obj is not set. Otherwise the python interpreter will do that for us.
TRACE_MEM_DEBUG("deleting mem block p ="<<p<< " py_obj = "<< py_obj << " ref of py obj if exists"<<(py_obj ? py_obj->ob_refcnt: -1));
assert(ref_count<=1); assert(py_guard==nullptr);// state 3 forbidden
if (py_numpy) Py_DECREF(py_numpy); // state 1
else { if (p) delete[] p; } // state 2 or state 0
}
// can not be copied or moved.
mem_block & operator=(mem_block const & X) = delete;
mem_block & operator=(mem_block && X) = delete;
mem_block(mem_block && X) noexcept {
size_ = X.size_; p = X.p; ref_count = X.ref_count; weak_ref_count = X.weak_ref_count; py_numpy=X.py_numpy; py_guard = X.py_guard;
X.p =nullptr; X.py_numpy= nullptr; X.py_guard = nullptr; // state 0, ready to destruct
}
// deep copy of data from another block.
// MUST be of the same size...
void copy_from(const mem_block & X) {
assert(size_==X.size_);assert(p); assert(X.p);
storages::memcopy (p, X.p, size_);
}
// copy construct into state 1, always.
// This is a choice, even if X is state 2 (a numpy).
// We copy a numpy into a regular C++ array, which can then be used at max speed.
mem_block (mem_block const & X): size_(X.size()), py_numpy(nullptr), py_guard(nullptr) {
try { p = new ValueType[X.size()];}
catch (std::bad_alloc& ba) { TRIQS_RUNTIME_ERROR<< "Memory allocation error : bad_alloc : "<< ba.what();}
ref_count=1;
weak_ref_count =0;
// now we copy the data
#ifndef TRIQS_WITH_PYTHON_SUPPORT
copy_from(X);
#else
// if X is in state 1 or 3
if (X.py_numpy==nullptr) { copy_from(X); }
else { // X was in state 2
// else make a new copy of the numpy ...
import_numpy_array();
if (!is_scalar_or_pod<ValueType>::value) TRIQS_RUNTIME_ERROR << "Internal Error : memcpy on non-scalar";
#ifdef TRIQS_NUMPY_VERSION_LT_17
if ( ( PyArray_ISFORTRAN(X.py_obj)) || (PyArray_ISCONTIGUOUS(X.py_obj))) {
memcpy (p,PyArray_DATA(X.py_obj),size_ * sizeof(ValueType));
}
PyObject * arr3 = X.py_numpy;
#else
// STRANGE : uncommenting this leads to a segfault on mac ???
// TO BE INVESTIGATED, IT IS NOT NORMAL
//if (!PyArray_Check(X.py_obj)) TRIQS_RUNTIME_ERROR<<"Internal error : is not an array";
PyArrayObject * arr3 = (PyArrayObject *)(X.py_obj);
if ( ( PyArray_ISFORTRAN(arr3)) || (PyArray_ISCONTIGUOUS(arr3))) {
memcpy (p,PyArray_DATA(arr3),size_ * sizeof(ValueType));
}
// STRANGE : uncommenting this leads to a segfault on mac ???
// TO BE INVESTIGATED, IT IS NOT NORMAL
//if (!PyArray_Check(X.py_numpy)) TRIQS_RUNTIME_ERROR<<"Internal error : is not an array";
PyArrayObject * arr3 = (PyArrayObject *)(X.py_numpy);
#endif
else { // if the X.py_obj is not contiguous, first let numpy copy it properly
PyObject * na = PyObject_CallMethod(X.py_obj,(char *)"copy",NULL);
assert(na);
// if we can make a memcpy, do it.
if ( ( PyArray_ISFORTRAN(arr3)) || (PyArray_ISCONTIGUOUS(arr3))) {
memcpy (p,PyArray_DATA(arr3),size_ * sizeof(ValueType));
}
else { // if the X.py_numpy is not contiguous, first let numpy copy it properly, then memcpy
PyObject * na = PyObject_CallMethod(X.py_numpy,(char *)"copy",nullptr);
assert(na);
#ifdef TRIQS_NUMPY_VERSION_LT_17
assert( ( PyArray_ISFORTRAN(na)) || (PyArray_ISCONTIGUOUS(na)));
memcpy (p,PyArray_DATA(na),size_ * sizeof(ValueType));
PyObject * arr = na;
#else
if (!PyArray_Check(na)) TRIQS_RUNTIME_ERROR<<"Internal error : is not an array";
PyArrayObject * arr = (PyArrayObject *)(na);
assert( ( PyArray_ISFORTRAN(arr)) || (PyArray_ISCONTIGUOUS(arr)));
memcpy (p,PyArray_DATA(arr),size_ * sizeof(ValueType));
if (!PyArray_Check(na)) TRIQS_RUNTIME_ERROR<<"Internal error : is not an array";
PyArrayObject * arr = (PyArrayObject *)(na);
#endif
Py_DECREF(na);
}
assert( ( PyArray_ISFORTRAN(arr)) || (PyArray_ISCONTIGUOUS(arr)));
memcpy (p,PyArray_DATA(arr),size_ * sizeof(ValueType));
Py_DECREF(na);
}
}
#endif
}
static void delete_pointeur( void *ptr ) {
TRACE_MEM_DEBUG("deleting data block"<<(non_const_value_type*) ptr);
delete [] ( (non_const_value_type*) ptr) ;
}
#ifdef TRIQS_WITH_PYTHON_SUPPORT
// Precondition : state 3, postcondition: state 1
static void delete_python_guard(void *ptr ) {
mem_block * m = static_cast<mem_block*>(ptr);
TRACE_MEM_DEBUG("deleting data block"<<m);
assert(m->ref_count>0); assert(m->py_guard !=nullptr);assert(m->py_numpy ==nullptr);
m->py_guard=nullptr;
dec_ref<false>(m);// release the reference which was owned by the guard
}
PyObject * new_ref_to_guard() {
if (py_obj==NULL) {
TRACE_MEM_DEBUG(" activating python guard for C++ block"<<p<< " py_obj = "<< py_obj);
py_obj = PyCObject_FromVoidPtr( (void*) p, &mem_block<ValueType>::delete_pointeur);
}
Py_INCREF(py_obj);
return py_obj;
}
// returns a NEW python ref either to the numpy or to the guard.
// if the guard does not yet exists, create it.
PyObject * new_python_ref() {
// if we just have a borrowed numpy, just return a new ref to it
if (py_numpy) { Py_INCREF(py_numpy); return py_numpy;}
// if the guard is already set, then return it, otherwise create it...
if (py_guard) { Py_INCREF(py_guard); return py_guard;}
else {
TRACE_MEM_DEBUG(" activating python guard for C++ block"<<p<< " py_guard = "<< py_guard);
inc_ref<false>(this); // the guard owns a C++ reference !!
py_guard = PyCObject_FromVoidPtr( static_cast<void *>(this), &mem_block<ValueType>::delete_python_guard);
}
return py_guard;
}
#endif
non_const_value_type & operator[](size_t i) {return p[i];}
ValueType & operator[](size_t i) {return p[i];}
size_t size() const {return size_;}
size_t size() const {return size_;}
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
ar << boost::serialization::make_nvp("size",size_);
for (size_t i=0; i<size_; ++i) ar << boost::serialization::make_nvp("data",p[i]);
}
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
ar << boost::serialization::make_nvp("size",size_);
for (size_t i=0; i<size_; ++i) ar << boost::serialization::make_nvp("data",p[i]);
}
template<class Archive>
void load(Archive & ar, const unsigned int version) {
ar >> size_;
assert (p==NULL);
p = new non_const_value_type[size_];
for (size_t i=0; i<size_; ++i) ar >> p[i];
}
BOOST_SERIALIZATION_SPLIT_MEMBER();
template<class Archive>
void load(Archive & ar, const unsigned int version) {
ar >> size_;
assert (p==nullptr);
p = new ValueType[size_];
for (size_t i=0; i<size_; ++i) ar >> p[i];
}
BOOST_SERIALIZATION_SPLIT_MEMBER();
};
}}}}//namespace triqs::arrays
}}}//namespace triqs::arrays
#undef TRACE_MEM_DEBUG
#endif

View File

@ -22,128 +22,89 @@
#define TRIQS_STORAGE_SHARED_POINTER_H
#include <string.h>
#include <limits>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "../impl/make_const.hpp"
#ifdef TRIQS_WITH_PYTHON_SUPPORT
#include "./mem_block.hpp"
#else
#include <vector>
//#include "basic_block.hpp"
namespace triqs { namespace arrays { namespace storages {
/*
* This is a shared memory block, similar to a shared_ptr<mem_block>
* but a lot faster and adapted to model the Storage concept.
*/
template<typename ValueType, bool Weak=false>
class shared_block {
static_assert( !std::is_const<ValueType>::value, "oops : internal error : shared_block should never be instanciated with a const");
mem_block<ValueType> * sptr;
ValueType * restrict data_; // for optimization on some compilers. ?? obsolete : to be removed ?
size_t s;
void construct_delegate(size_t size) {
s = size;
if (size ==0) { sptr = nullptr; data_=nullptr; }
else { sptr = new mem_block<ValueType>(size); data_ = sptr->p;}
}
public:
typedef ValueType value_type;
static constexpr bool is_weak = Weak;
/// Construct a new block of memory of given size
explicit shared_block(size_t size, Tag::no_init) { construct_delegate(size); }
explicit shared_block(size_t size, Tag::default_init) {// C++11 : delegate to previous constructor when gcc 4.6 support is out.
construct_delegate(size);
const auto s = this->size(); for (size_t u=0; u<s; ++u) data_[u] = ValueType();
}
#ifdef TRIQS_WITH_PYTHON_SUPPORT
explicit shared_block(PyObject * arr, bool weak): sptr(new mem_block<ValueType>(arr,weak)) { data_ = sptr->p; s= sptr->size(); }
#endif
namespace triqs { namespace arrays {
namespace Tag {struct storage{}; struct shared_block:storage{}; }
explicit shared_block() { sptr =nullptr; data_=nullptr; s=0; }
namespace storages {
shared_block(shared_block const & X) noexcept { sptr =X.sptr; data_ = X.data_; s= X.s; if (sptr) inc_ref<Weak>(sptr); }
shared_block(shared_block<ValueType,!Weak> const & X) noexcept { sptr =X.sptr; data_ = X.data_; s= X.s; if (sptr) inc_ref<Weak>(sptr); }
template <class V, class Opt> struct __init_value;
template <class V> struct __init_value<V, Tag::no_init> { static void invoke (V * data, size_t s) {}};
template <class V> struct __init_value< V, Tag::default_init> {
static void invoke (V * restrict data, size_t s) { if (data!=NULL) for (size_t u=0; u<s; ++u) data[u] = V(); }
};
template <class V> struct __init_value< V, Tag::nan_inf_init> {
static void invoke (V * restrict data, size_t s) {
static_assert ( ( std::numeric_limits<V>::has_quiet_NaN || std::numeric_limits<V>::is_integer), "type has no Nan and is not integer. This init is impossible");
if (data==NULL) return;
if (std::numeric_limits<V>::has_quiet_NaN) for (size_t u=0; u<s; ++u) data[u] = std::numeric_limits<V>::quiet_NaN();
if (std::numeric_limits<V>::is_integer) for (size_t u=0; u<s; ++u) data[u] = std::numeric_limits<V>::max();
shared_block(shared_block && X) noexcept { sptr =X.sptr; data_ = X.data_; s= X.s; X.sptr=nullptr; }
~shared_block() { if (sptr) dec_ref<Weak>(sptr); }
shared_block & operator=(shared_block const & X) noexcept {
if (sptr) dec_ref<Weak>(sptr); sptr =X.sptr; if (sptr) inc_ref<Weak>(sptr);
data_ = X.data_; s = X.s;
return *this;
}
shared_block & operator=(shared_block && X) noexcept {
if (sptr) dec_ref<Weak>(sptr); sptr =X.sptr; X.sptr=nullptr;
data_ = X.data_; s = X.s;
return *this;
}
/// True copy of the data
shared_block clone() const {
shared_block res;
if (!empty()) { res.sptr = new mem_block<ValueType> (*sptr); res.data_ = res.sptr->p; res.s = s;}
return res;
}
value_type & operator[](size_t i) const { return data_[i];}
bool empty() const {return (sptr==nullptr);}
size_t size() const {return s;}
//size_t size() const {return (empty () ? 0 : sptr->size());}
#ifdef TRIQS_WITH_PYTHON_SUPPORT
PyObject * new_python_ref() const {return sptr->new_python_ref();}
#endif
private:
friend class shared_block<ValueType,!Weak>;
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar, const unsigned int version) {
ar & boost::serialization::make_nvp("ptr",sptr); data_ = (sptr ? sptr->p : nullptr); s = (sptr ? sptr->size() : 0);
}
};
template <class V> struct __init_value< std::complex<V>, Tag::nan_inf_init> {
static void invoke (std::complex<V> * restrict data, size_t s) {
static_assert ( ( std::numeric_limits<V>::has_quiet_NaN || std::numeric_limits<V>::is_integer), "type has no Nan and is not integer. This init is impossible");
if (data==NULL) return;
if (std::numeric_limits<V>::has_quiet_NaN) for (size_t u=0; u<s; ++u) data[u] = std::complex<V>(std::numeric_limits<V>::quiet_NaN(),std::numeric_limits<V>::quiet_NaN()) ;
if (std::numeric_limits<V>::is_integer) for (size_t u=0; u<s; ++u) data[u] = std::complex<V>(std::numeric_limits<V>::max(),std::numeric_limits<V>::max());
}
};
/* Storage as a shared_ptr to a basic_block
* The shared pointer guarantees that the data will not be destroyed during the life of the array.
* Impl: we are not using shared_array directly because of serialization support for shared_ptr */
template<typename ValueType >
class shared_block : Tag::shared_block {
typedef typename boost::add_const<ValueType>::type const_value_type;
typedef typename boost::remove_const<ValueType>::type non_const_value_type;
#ifdef TRIQS_WITH_PYTHON_SUPPORT
typedef details::mem_block<non_const_value_type> block_type;
#else
// typedef details::basic_block<non_const_value_type> block_type;
typedef std::vector<non_const_value_type> block_type;
#endif
public:
typedef triqs::arrays::Tag::shared_block tag;
typedef ValueType value_type;
typedef shared_block<value_type> clone_type;
typedef shared_block<const_value_type> const_clone_type;
/// Construct a new block of memory of given size
template<typename InitOpt>
explicit shared_block(size_t size, InitOpt opt ): sptr(size ? new block_type(size) : NULL) {
init_data();
__init_value<value_type,InitOpt>::invoke (this-> data_, this->size());
}
explicit shared_block(): sptr() { init_data(); }
#ifdef TRIQS_WITH_PYTHON_SUPPORT
/// Construct from a numpy object
explicit shared_block(PyObject * arr, bool borrowed): sptr(new block_type(arr,borrowed)) { init_data();}
#endif
/// Shallow copy
shared_block(const shared_block<const_value_type> & X): sptr(X.sptr) { init_data(); }
/// Shallow copy
shared_block(const shared_block<non_const_value_type> & X): sptr(X.sptr) { init_data(); }
void operator=(const shared_block & X) { sptr=X.sptr; init_data(); }
/// True copy of the data
clone_type clone() const {
if (empty()) return clone_type ();
#ifdef TRIQS_WITH_PYTHON_SUPPORT
clone_type res; res.sptr = boost::make_shared<block_type > (*sptr); res.init_data();
#else
clone_type res(this->size(), Tag::no_init() ); (*res.sptr) = (*sptr);
#endif
return res;
}
// Make a clone forced to have const value_type
const_clone_type const_clone() const {return clone();}
value_type & operator[](size_t i) const { return data_[i];}
bool empty() const {return (sptr.get()==NULL);}
size_t size() const {return (empty () ? 0 : sptr.get()->size());}
#ifdef TRIQS_WITH_PYTHON_SUPPORT
PyObject * new_ref_to_guard() const {return sptr->new_ref_to_guard();}
#endif
private:
boost::shared_ptr<block_type > sptr;
value_type * restrict data_; // for optimization on some compilers.
void init_data(){ data_ = (sptr ? &((*sptr)[0]) : NULL); }
friend class shared_block <non_const_value_type>; friend class shared_block <const_value_type>;
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar, const unsigned int version) { ar & boost::serialization::make_nvp("ptr",sptr); init_data(); }
};
}
namespace details {
template<bool Const, typename T> struct make_const_type<Const,storages::shared_block<T> > {
typedef storages::shared_block<typename make_const_type<Const,T>::type> type;
};
}
}}//namespace triqs::arrays
}}}//namespace
#endif

View File

@ -29,19 +29,20 @@
namespace triqs { namespace arrays {
template <typename ValueType, ull_t Opt=0> class vector_view;
template <typename ValueType, ull_t Opt=0, bool Borrowed =false> class vector_view;
template <typename ValueType, ull_t Opt=0> class vector;
// ---------------------- vector_view --------------------------------
#define IMPL_TYPE indexmap_storage_pair< indexmaps::cuboid::map<1,Opt,0> , storages::shared_block<ValueType>, Opt, 0, Tag::vector_view >
#define IMPL_TYPE indexmap_storage_pair< indexmaps::cuboid::map<1,Opt,0> , storages::shared_block<ValueType,Borrowed>, Opt, 0, Tag::vector_view >
/** */
template <typename ValueType, ull_t Opt >
template <typename ValueType, ull_t Opt, bool Borrowed>
class vector_view : Tag::vector_view, TRIQS_MODEL_CONCEPT(MutableVector), public IMPL_TYPE {
public :
typedef vector_view<ValueType,Opt> view_type;
typedef vector<ValueType,Opt> non_view_type;
typedef vector <ValueType,Opt> non_view_type;
typedef vector_view<ValueType,Opt,false> view_type;
typedef vector_view<ValueType,Opt,true> weak_view_type;
typedef void has_view_type_tag;
typedef typename IMPL_TYPE::indexmap_type indexmap_type;
@ -93,9 +94,12 @@ namespace triqs { namespace arrays {
//template<typename Arg> auto operator[](Arg && arg) const DECL_AND_RETURN((*this)(std::forward<Arg>(arg)));
//template<typename Arg> auto operator[](Arg && arg) DECL_AND_RETURN((*this)(std::forward<Arg>(arg)));
};
#undef IMPL_TYPE
template < class V, int R, ull_t OptionFlags, ull_t To > struct ViewFactory< V, R,OptionFlags,To, Tag::vector_view> { typedef vector_view<V,OptionFlags> type; };
template < class V, int R, ull_t OptionFlags, ull_t To, bool Borrowed >
struct ISPViewType< V, R,OptionFlags,To, Tag::vector_view, Borrowed> { typedef vector_view<V,OptionFlags,Borrowed> type; };
// ---------------------- vector--------------------------------
#define IMPL_TYPE indexmap_storage_pair< indexmaps::cuboid::map<1,Opt,0> , storages::shared_block<ValueType>, Opt, 0, Tag::vector_view >
template <typename ValueType, ull_t Opt>
class vector: Tag::vector, TRIQS_MODEL_CONCEPT(MutableVector), public IMPL_TYPE {
@ -103,8 +107,9 @@ namespace triqs { namespace arrays {
typedef typename IMPL_TYPE::value_type value_type;
typedef typename IMPL_TYPE::storage_type storage_type;
typedef typename IMPL_TYPE::indexmap_type indexmap_type;
typedef vector_view<ValueType,Opt> view_type;
typedef vector<ValueType,Opt> non_view_type;
typedef vector <ValueType,Opt> non_view_type;
typedef vector_view<ValueType,Opt> view_type;
typedef vector_view<ValueType,Opt,true> weak_view_type;
typedef void has_view_type_tag;
/// Empty vector.
@ -277,8 +282,8 @@ namespace triqs { namespace arrays {
}
// swapping 2 vector
template <typename V, ull_t S1, ull_t S2>
void deep_swap(vector_view <V,S1> x, vector_view<V,S2> y) {
template <typename V, ull_t S1, ull_t S2, bool B1, bool B2>
void deep_swap(vector_view <V,S1,B1> x, vector_view<V,S2,B2> y) {
blas::swap(x,y);
}

View File

@ -65,7 +65,10 @@ namespace triqs { namespace lattice_tools {
brillouin_zone::brillouin_zone( bravais_lattice const & bl_) : lattice_(bl_), K_reciprocal(3,3) {
bravais_lattice::units_type Units(lattice().units());
std::cout << Units << std::endl;
double delta = dot(Units(0,range()), cross_product(Units(1,range()),Units(2,range())));
std::cout << dot(Units(0,range()), cross_product(Units(1,range()),Units(2,range())))<<std::endl;
std::cout << cross_product(Units(1,range()),Units(2,range()))<<std::endl;
if (abs(delta)<almost_zero) TRIQS_RUNTIME_ERROR<<"Tiling : the 3 vectors of Units are not independant";
K_reciprocal(0,range()) = cross_product(Units(1,range()),Units(2,range())) / delta;
K_reciprocal(1,range()) = cross_product(Units(2,range()),Units(0,range())) / delta;

View File

@ -24,6 +24,7 @@
#include <triqs/arrays/matrix.hpp>
#include <triqs/arrays/vector.hpp>
#include <triqs/utility/exceptions.hpp>
#include <unordered_map>
#include <map>
#include <string>
#include <unordered_map>

View File

@ -22,8 +22,17 @@
#define TRIQS_COMPILER_DETAILS_H
#ifdef __GNUC__
#define restrict __restrict__
#define restrict __restrict__
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40801
#define TRIQS_COMPILER_IS_OBSOLETE
// we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11
#endif
#endif
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#define TRIQS_USE_STATIC_ASSERT