3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 22:03:43 +01:00

Change tail implementation with fixed array size

Now the tail have a fixed size. It actually makes everything simpler. I took
order_min = -1 and order_max = 8. This makes the tails compatible with the
previous implementation. However we might want to change this to something like
-10, 10 so that they are self-contained. This commit should also fix issue #11.
This commit is contained in:
Michel Ferrero 2013-09-11 18:23:38 +02:00
parent d4c96a9d93
commit f0dfabff38
13 changed files with 359 additions and 369 deletions

View File

@ -6,10 +6,15 @@ Changelog
This document describes the main changes in TRIQS. This document describes the main changes in TRIQS.
From TRIQS 0.x to TRIQS 1.0 master (latest commit on github)
--------------------------- --------------------------------
There have been changes from versions 0.x to 1.0 that will most likely have * The tails now have fixed size avoid mpi problems
version 1.0.0
-------------
There have been changes from versions 0.x to 1.0.0 that will most likely have
consequences for your scripts and archives. consequences for your scripts and archives.
Python classes Python classes

View File

@ -23,7 +23,7 @@ r""" """
import numpy import numpy
from math import * from math import *
from gf import MeshImFreq, TailGf, MeshReFreq from gf import MeshImFreq, MeshReFreq
from lazy_expressions import LazyExprTerminal, LazyExpr, transform from lazy_expressions import LazyExprTerminal, LazyExpr, transform
def is_lazy(y): def is_lazy(y):
@ -68,7 +68,7 @@ class Function (Base):
:param function: the function:math:`\omega \rightarrow function(\omega)` :param function: the function:math:`\omega \rightarrow function(\omega)`
:param tail: The tail. Use None if you don't use any tail (will be put to 0) :param tail: The tail. Use None if you don't use any tail (will be put to 0)
""" """
Base.__init__(self,function=function, tail=tail) Base.__init__(self, function=function, tail=tail)
def __call__(self,G): def __call__(self,G):
if not(callable(self.function)): raise RuntimeError, "GFInitializer.Function: f must be callable" if not(callable(self.function)): raise RuntimeError, "GFInitializer.Function: f must be callable"
@ -97,8 +97,7 @@ class Const(Base):
C = C*numpy.identity(G.N1) C = C*numpy.identity(G.N1)
if C.shape !=(G.N1,G.N2): raise RuntimeError, "Size of constant incorrect" if C.shape !=(G.N1,G.N2): raise RuntimeError, "Size of constant incorrect"
t = G.tail G.tail.zero()
G.tail = TailGf(shape = t.shape, size = t.size, order_min=0)
G.tail[0][:,:] = C G.tail[0][:,:] = C
Function(lambda om: C, None)(G) Function(lambda om: C, None)(G)
@ -116,9 +115,12 @@ class Omega_(Base):
Id = numpy.identity(G.N1) Id = numpy.identity(G.N1)
G.tail.zero() G.tail.zero()
G.tail[-1][:,:] = Id G.tail[-1][:,:] = Id
for n,om in enumerate(G.mesh): G.data[n,:,:] = om*Id for n,om in enumerate(G.mesh): G.data[n,:,:] = om*Id
return G return G
##########################################################################
Omega = Omega_() Omega = Omega_()
iOmega_n = Omega_() iOmega_n = Omega_()
@ -139,8 +141,7 @@ class A_Omega_Plus_B(Base):
if A.shape !=(G.N1,G.N2): raise RuntimeError, "Size of A incorrect" if A.shape !=(G.N1,G.N2): raise RuntimeError, "Size of A incorrect"
if B.shape !=(G.N1,G.N2): raise RuntimeError, "Size of B incorrect" if B.shape !=(G.N1,G.N2): raise RuntimeError, "Size of B incorrect"
t,Id = G.tail, numpy.identity(G.N1) G.tail.zero()
G.tail = TailGf(shape = t.shape, size = t.size, order_min=-1)
G.tail[-1][:,:] = A G.tail[-1][:,:] = A
G.tail[0][:,:] = B G.tail[0][:,:] = B
@ -160,17 +161,17 @@ class OneFermionInTime(Base):
if G.mesh.TypeGF not in [GF_Type.Imaginary_Time]: if G.mesh.TypeGF not in [GF_Type.Imaginary_Time]:
raise TypeError, "This initializer is only correct in frequency" raise TypeError, "This initializer is only correct in frequency"
t,Id = G.tail, numpy.identity(G.N1) Id = numpy.identity(G.N1)
G.tail = TailGf(shape = t.shape, size = 3, order_min=1) G.tail.zero()
t[1][:,:] = 1 G.tail[1][:,:] = 1*Id
t[2][:,:] = L G.tail[2][:,:] = L*Id
t[3][:,:] = L*L G.tail[3][:,:] = L*L*Id
G.tail.mask.fill(3)
fact = -1/(1+exp(-L*G.beta)) fact = -1/(1+exp(-L*G.beta))
Function(lambda t: fact* exp(-L*t) *Id, None)(G) Function(lambda t: fact* exp(-L*t) *Id, None)(G)
return G return G
################################################## ##################################################
def _SemiCircularDOS(half_bandwidth): def _SemiCircularDOS(half_bandwidth):
@ -223,11 +224,12 @@ class SemiCircular (Base):
raise TypeError, "This initializer is only correct in frequency" raise TypeError, "This initializer is only correct in frequency"
# Let's create a new tail # Let's create a new tail
G.tail = TailGf(shape = G.tail.shape, size=5, order_min=1) Id = numpy.identity(G.N1)
for i in range(G.N1): G.tail.zero()
G.tail[1][i,i] = 1.0 G.tail[1][:,:] = 1.0*Id
G.tail[3][i,i] = D**2/4.0 G.tail[3][:,:] = D**2/4.0*Id
G.tail[5][i,i] = D**4/8.0 G.tail[5][:,:] = D**4/8.0*Id
G.tail.mask.fill(6)
Function(f,None)(G) Function(f,None)(G)
return G return G
@ -267,11 +269,12 @@ class Wilson (Base):
raise TypeError, "This initializer is only correct in frequency" raise TypeError, "This initializer is only correct in frequency"
# Let's create a new tail # Let's create a new tail
G.tail = TailGf(shape = G.tail.shape, size=5, order_min=1) Id = numpy.identity(G.N1)
for i in range(G.N1): G.tail.zero()
G.tail[1][i,i] = 1.0 G.tail[1][:,:] = 1.0*Id
G.tail[3][i,i] = D**2/3.0 G.tail[3][:,:] = D**2/3.0*Id
G.tail[5][i,i] = D**4/5.0 G.tail[5][:,:] = D**4/5.0*Id
G.tail.mask.fill(6)
Function(f,None)(G) Function(f,None)(G)
return G return G

View File

@ -238,13 +238,8 @@ class GfGeneric:
else: else:
raise RuntimeError, " argument type not recognized in += for %s"%arg raise RuntimeError, " argument type not recognized in += for %s"%arg
if rhs !=None : if rhs !=None :
new_tail = TailGf(shape=lhs.tail.shape, size=lhs.tail.size, order_min=min(0,lhs.tail.order_min)) new_tail = TailGf(shape=lhs.tail.shape)
new_tail[0][:,:] = rhs new_tail[0][:,:] = rhs
# if it is add, then we CAN change the shape of the tail, and
# reassign it since it is a new object, just create (then use the
# _singularity object.
# otherwise we can not, since it could be view, so we use the tail
# and if shape is not correct, = i.e. copy_from will raise an error
if is_add : lhs._singularity = lhs.tail + new_tail if is_add : lhs._singularity = lhs.tail + new_tail
else : lhs.tail = lhs.tail + new_tail else : lhs.tail = lhs.tail + new_tail
return lhs return lhs
@ -275,7 +270,7 @@ class GfGeneric:
else: else:
raise RuntimeError, " argument type not recognized in -= for %s"%arg raise RuntimeError, " argument type not recognized in -= for %s"%arg
if rhs !=None : if rhs !=None :
new_tail = TailGf(shape=lhs.tail.shape, size=lhs.tail.size, order_min=min(0,lhs.tail.order_min)) new_tail = TailGf(shape=lhs.tail.shape)
new_tail[0][:,:] = rhs new_tail[0][:,:] = rhs
if is_sub : lhs._singularity = lhs.tail - new_tail if is_sub : lhs._singularity = lhs.tail - new_tail
else : lhs.tail = lhs.tail - new_tail else : lhs.tail = lhs.tail - new_tail
@ -336,7 +331,7 @@ class GfGeneric:
MatrixStack(self.data).matmul_L_R(L, G.data, R) MatrixStack(self.data).matmul_L_R(L, G.data, R)
# this might be a bit slow # this might be a bit slow
t = TailGf(shape=(N1,N2), size=G.tail.order_max-G.tail.order_min+1, order_min=G.tail.order_min) t = TailGf(shape=(N1,N2))
for o in range(t.order_min, t.order_max+1): for o in range(t.order_min, t.order_max+1):
t[o] = numpy.dot(L, numpy.dot(G.tail[o], R)) t[o] = numpy.dot(L, numpy.dot(G.tail[o], R))
self.tail = t self.tail = t

View File

@ -49,7 +49,7 @@ class GfImFreq ( GfGeneric, GfImFreq_cython ) :
indicesL, indicesR = indices_pack indicesL, indicesR = indices_pack
N1, N2 = len(indicesL),len(indicesR) N1, N2 = len(indicesL),len(indicesR)
data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype ) data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2), size=10, order_min=-1) tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
symmetry = d.pop('symmetry', Nothing()) symmetry = d.pop('symmetry', Nothing())
name = d.pop('name','g') name = d.pop('name','g')
assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys() assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys()
@ -93,7 +93,7 @@ class GfImFreq ( GfGeneric, GfImFreq_cython ) :
# Change the order_max # Change the order_max
# It is assumed that any known_coef will start at order -1 # It is assumed that any known_coef will start at order -1
self.tail = TailGf(shape = (self.N1,self.N2), size = order_max+2, order_min = -1) self.tail = TailGf(shape = (self.N1,self.N2))
# Fill up two arrays with the frequencies and values over the range of interest # Fill up two arrays with the frequencies and values over the range of interest
ninit, nstop = 0, -1 ninit, nstop = 0, -1

View File

@ -49,7 +49,7 @@ class GfImTime ( GfGeneric, GfImTime_cython ) :
indicesL, indicesR = indices_pack indicesL, indicesR = indices_pack
N1, N2 = len(indicesL),len(indicesR) N1, N2 = len(indicesL),len(indicesR)
data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype ) data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2), size=10, order_min=-1) tail = d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
symmetry = d.pop('symmetry', Nothing()) symmetry = d.pop('symmetry', Nothing())
name = d.pop('name','g') name = d.pop('name','g')
assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys() assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys()

View File

@ -47,7 +47,7 @@ class GfReFreq ( GfGeneric, GfReFreq_cython ) :
indicesL, indicesR = indices_pack indicesL, indicesR = indices_pack
N1, N2 = len(indicesL),len(indicesR) N1, N2 = len(indicesL),len(indicesR)
data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype ) data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
tail= d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2), size=10, order_min=-1) tail= d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
symmetry = d.pop('symmetry',None) symmetry = d.pop('symmetry',None)
name = d.pop('name','g') name = d.pop('name','g')
assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys() assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys()

View File

@ -47,7 +47,7 @@ class GfReTime ( GfGeneric, GfReTime_cython ) :
indicesL, indicesR = indices_pack indicesL, indicesR = indices_pack
N1, N2 = len(indicesL),len(indicesR) N1, N2 = len(indicesL),len(indicesR)
data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype ) data = d.pop('data') if 'data' in d else numpy.zeros((len(mesh),N1,N2), self.dtype )
tail= d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2), size=10, order_min=-1) tail= d.pop('tail') if 'tail' in d else TailGf(shape = (N1,N2))
symmetry = d.pop('symmetry',None) symmetry = d.pop('symmetry',None)
name = d.pop('name','g') name = d.pop('name','g')
assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys() assert len(d) ==0, "Unknown parameters in GFBloc constructions %s"%d.keys()

View File

@ -3,7 +3,7 @@ from arrays cimport *
cdef extern from "triqs/gfs/local/tail.hpp" : cdef extern from "triqs/gfs/local/tail.hpp" :
cdef cppclass tail "triqs::python_tools::cython_proxy<triqs::gfs::local::tail_view>" : cdef cppclass tail "triqs::python_tools::cython_proxy<triqs::gfs::local::tail_view>" :
tail() tail()
tail(array_view[dcomplex,THREE], int, array_view[long,TWO]) except + tail(array_view[dcomplex,THREE], array_view[long,TWO], long) except +
matrix_view[dcomplex] operator()(int) except + matrix_view[dcomplex] operator()(int) except +
array_view[dcomplex,THREE] data() array_view[dcomplex,THREE] data()
array_view[long,TWO] mask_view() except + array_view[long,TWO] mask_view() except +

View File

@ -5,8 +5,8 @@ cdef class TailGf:
cdef tail _c cdef tail _c
def __init__(self, **d): def __init__(self, **d):
""" """
TailGf ( shape, size, order_min ) TailGf ( shape )
TailGf ( data, order_min ) TailGf ( data, mask, order_min )
""" """
c_obj = d.pop('encapsulated_c_object', None) c_obj = d.pop('encapsulated_c_object', None)
if c_obj : if c_obj :
@ -20,17 +20,24 @@ cdef class TailGf:
boost_unserialize_into(<std_string>bss,self._c) boost_unserialize_into(<std_string>bss,self._c)
return return
omin = d.pop('order_min') # default values
omin = -1
omax = 8
a = d.pop('data',None) a = d.pop('data',None)
if a==None : if a==None :
(N1, N2), s = d.pop('shape'), d.pop('size') (N1, N2) = d.pop('shape')
a = numpy.zeros((s,N1,N2), numpy.complex) a = numpy.zeros((omax-omin+1,N1,N2), numpy.complex)
m = d.pop('mask',None) m = d.pop('mask',None)
if m==None : if m==None :
m = numpy.zeros(a.shape[1:3], int) m = numpy.zeros(a.shape[1:3], int)
m.fill(omin+a.shape[0]-1) m.fill(omax)
o = d.pop('order_min',None)
if o==None: o = omin
assert len(d) == 0, "Unknown parameters in TailGf constructions %s"%d.keys() assert len(d) == 0, "Unknown parameters in TailGf constructions %s"%d.keys()
self._c = tail(array_view[dcomplex,THREE](a), omin, array_view[long,TWO](m))
self._c = tail(array_view[dcomplex,THREE](a), array_view[long,TWO](m), o)
#-------------- Reduction ------------------------------- #-------------- Reduction -------------------------------
@ -71,17 +78,22 @@ cdef class TailGf:
def __get__(self) : return self._c.size() def __get__(self) : return self._c.size()
def copy(self) : def copy(self) :
return self.__class__(data = self.data.copy(), order_min = self.order_min, mask = self.mask.copy()) return self.__class__(data = self.data.copy(), mask = self.mask.copy())
def copy_from(self, TailGf T) : def copy_from(self, TailGf T) :
assert self.order_min <= T.order_min, "Copy_from error "
self._c << T._c self._c << T._c
def _make_slice(self, sl1, sl2): def _make_slice(self, sl1, sl2):
return self.__class__(data = self.data[:,sl1,sl2], order_min = self.order_min, mask = self.mask[sl1,sl2]) return self.__class__(data = self.data[:,sl1,sl2], mask = self.mask[sl1,sl2])
def __repr__ (self) : def __repr__ (self) :
return string.join([ "%s"%self[r]+ (" /" if r>0 else "") + " Om^%s"%(abs(r)) for r in range(self.order_min, self.order_max+1) ] , " + ") omin = self.order_min
while ((omin <= self.order_max) and (numpy.max(numpy.abs(self.data[omin-self.order_min,:,:])) < 1e-8)):
omin = omin+1
if omin == self.order_max+1:
return "%s"%numpy.zeros(self.shape)
else:
return string.join([ "%s"%self[r]+ (" /" if r>0 else "") + " Om^%s"%(abs(r)) for r in range(omin, self.order_max+1) ] , " + ")
def __getitem__(self,i) : def __getitem__(self,i) :
"""Returns the i-th coefficient of the expansion, or order Om^i""" """Returns the i-th coefficient of the expansion, or order Om^i"""
@ -164,11 +176,11 @@ cdef class TailGf:
def transpose (self) : def transpose (self) :
"""Transpose the array : new view as in numpy""" """Transpose the array : new view as in numpy"""
return TailGf(data=self.data.transpose(), order_min=self.order_min, mask=self.mask.transpose()) return TailGf(data=self.data.transpose(), mask=self.mask.transpose())
def conjugate(self) : def conjugate(self) :
"""Transpose the array : new view as in numpy""" """Transpose the array : new view as in numpy"""
return TailGf(data=self.data.conjugate(), order_min=self.order_min, mask=self.mask) return TailGf(data=self.data.conjugate(), mask=self.mask)
def __write_hdf5__ (self, gr , char * key) : def __write_hdf5__ (self, gr , char * key) :
h5_write (make_h5_group(gr), key, self._c) h5_write (make_h5_group(gr), key, self._c)

Binary file not shown.

View File

@ -94,9 +94,7 @@ void test_1(){
/* ----- Fourier ----- */ /* ----- Fourier ----- */
size_t N1=1; size_t N1=1;
size_t N2=1; size_t N2=1;
size_t size_ = 5; triqs::gfs::local::tail t(N1,N2);
long order_min=-1;
triqs::gfs::local::tail t(N1,N2, size_, order_min);
t(1)=1; t(1)=1;
auto Gt = make_gf<imtime> (beta, Fermion, make_shape(1,1),100,full_bins, t); auto Gt = make_gf<imtime> (beta, Fermion, make_shape(1,1),100,full_bins, t);

View File

@ -90,7 +90,7 @@ namespace triqs { namespace gfs {
local::tail_view get_tail(gf_view<legendre> const & gl, int size = 10, int omin = -1) { local::tail_view get_tail(gf_view<legendre> const & gl, int size = 10, int omin = -1) {
auto sh = gl.data().shape().front_pop(); auto sh = gl.data().shape().front_pop();
local::tail t(sh, size, omin); local::tail t(sh);
t.data() = 0.0; t.data() = 0.0;
for (int p=1; p<=t.order_max(); p++) for (int p=1; p<=t.order_max(); p++)

View File

@ -27,375 +27,352 @@
namespace triqs { namespace gfs { namespace local { namespace triqs { namespace gfs { namespace local {
namespace details { namespace details {
static constexpr double small = 1.e-10; static constexpr double small = 1.e-10;
} }
namespace tqa= triqs::arrays; namespace tql= triqs::clef; namespace mpl= boost::mpl; namespace tqa= triqs::arrays; namespace tql= triqs::clef; namespace mpl= boost::mpl;
typedef std::complex<double> dcomplex; typedef std::complex<double> dcomplex;
class tail; // the value class class tail; // the value class
class tail_view; // the view class class tail_view; // the view class
template<typename G> struct LocalTail : mpl::false_{}; // a boolean trait to identify the objects modelling the concept LocalTail template<typename G> struct LocalTail : mpl::false_{}; // a boolean trait to identify the objects modelling the concept LocalTail
template<> struct LocalTail<tail > : mpl::true_{}; template<> struct LocalTail<tail > : mpl::true_{};
template<> struct LocalTail<tail_view >: mpl::true_{}; template<> struct LocalTail<tail_view >: mpl::true_{};
template<> struct LocalTail<python_tools::cython_proxy<tail_view>>: mpl::true_{}; template<> struct LocalTail<python_tools::cython_proxy<tail_view>>: mpl::true_{};
// a trait to find the scalar of the algebra i.e. the true scalar and the matrix ... // a trait to find the scalar of the algebra i.e. the true scalar and the matrix ...
template <typename T> struct is_scalar_or_element : mpl::or_< tqa::ImmutableMatrix<T>, utility::is_in_ZRC<T> > {}; template <typename T> struct is_scalar_or_element : mpl::or_< tqa::ImmutableMatrix<T>, utility::is_in_ZRC<T> > {};
// ---------------------- implementation -------------------------------- // ---------------------- implementation --------------------------------
/// A common implementation class. Idiom : ValueView /// A common implementation class. Idiom : ValueView
template<bool IsView> class tail_impl { template<bool IsView> class tail_impl {
public : public :
typedef tail_view view_type; typedef tail_view view_type;
typedef tail regular_type; typedef tail regular_type;
typedef arrays::array <dcomplex,3> data_regular_type; typedef arrays::array <dcomplex,3> data_regular_type;
typedef arrays::array_view <dcomplex,3> data_view_type; typedef arrays::array_view <dcomplex,3> data_view_type;
typedef typename mpl::if_c<IsView, data_view_type, data_regular_type>::type data_type; typedef typename mpl::if_c<IsView, data_view_type, data_regular_type>::type data_type;
typedef arrays::array<long,2> mask_regular_type; typedef arrays::array<long,2> mask_regular_type;
typedef arrays::array_view<long,2> mask_view_type; typedef arrays::array_view<long,2> mask_view_type;
typedef typename mpl::if_c<IsView, mask_view_type, mask_regular_type>::type mask_type; typedef typename mpl::if_c<IsView, mask_view_type, mask_regular_type>::type mask_type;
typedef arrays::matrix_view<dcomplex> mv_type; typedef arrays::matrix_view<dcomplex> mv_type;
typedef arrays::matrix_view<dcomplex> const_mv_type; typedef arrays::matrix_view<dcomplex> const_mv_type;
//typedef arrays::matrix_view<const dcomplex> const_mv_type;
data_view_type data() { return _data;} data_view_type data() { return _data;}
const data_view_type data() const { return _data;} const data_view_type data() const { return _data;}
mask_view_type mask_view() { return mask;} mask_view_type mask_view() { return mask;}
const mask_view_type mask_view() const { return mask;} const mask_view_type mask_view() const { return mask;}
long order_min() const {return omin;} long order_min() const {return omin;}
long order_max() const {return min_element(mask);} long order_max() const {return min_element(mask);}
size_t size() const {return _data.shape()[0];} size_t size() const {return _data.shape()[0];}
long smallest_nonzero() const { long smallest_nonzero() const {
long om = omin; long om = omin;
while ((om < this->order_max()) && (max_element(abs(_data(om-omin,tqa::range(),tqa::range()))) < details::small)) om++; while ((om < this->order_max()) && (max_element(abs(_data(om-omin,tqa::range(),tqa::range()))) < details::small)) om++;
return om; return om;
} }
typedef tqa::mini_vector<size_t,2> shape_type; typedef tqa::mini_vector<size_t,2> shape_type;
shape_type shape() const { return shape_type(_data.shape()[1], _data.shape()[2]);} shape_type shape() const { return shape_type(_data.shape()[1], _data.shape()[2]);}
size_t shape(int i) const { return _data.shape()[i];} size_t shape(int i) const { return _data.shape()[i];}
bool is_decreasing_at_infinity() const { return (smallest_nonzero() >=1);} bool is_decreasing_at_infinity() const { return (smallest_nonzero() >=1);}
protected: protected:
long omin; long omin;
mask_type mask; mask_type mask;
data_type _data; data_type _data;
// All constructors // All constructors
tail_impl(): omin(0), mask(), _data() {} // all arrays of zero size (empty) tail_impl(): mask(), _data(), omin(0) {} // all arrays of zero size (empty)
tail_impl(size_t N1, size_t N2, size_t size_, long order_min): tail_impl(size_t N1, size_t N2, long omin_, long size_):
omin(order_min), mask(tqa::make_shape(N1,N2)), _data(tqa::make_shape(size_,N1,N2)) { omin(omin_), mask(tqa::make_shape(N1,N2)), _data(tqa::make_shape(size_,N1,N2)) {
mask() = order_min+size_-1; mask() = omin+size_-1;
_data() = 0; _data() = 0;
} }
tail_impl(data_type const &d, long order_min, mask_type const &om): omin(order_min), mask(om), _data(d) {} tail_impl(data_type const &d, mask_type const &m, long omin_): mask(m), _data(d), omin(omin_) {}
// tail_impl(tail_impl const & x): omin(x.omin), mask(x.mask), _data(x._data){} tail_impl(tail_impl<!IsView> const & x): mask(x.mask), _data(x._data), omin(x.omin) {}
tail_impl(tail_impl<!IsView> const & x): omin(x.omin), mask(x.mask), _data(x._data){} tail_impl(tail_impl const &) = default;
tail_impl(tail_impl const &) = default; tail_impl(tail_impl &&) = default;
tail_impl(tail_impl &&) = default;
friend class tail_impl<!IsView>; friend class tail_impl<!IsView>;
public:
mv_type operator() (int n) { public:
if (n>this->order_max()) TRIQS_RUNTIME_ERROR<<" n > Max Order. n= "<<n <<", Max Order = "<<order_max() ;
if (n<this->order_min()) TRIQS_RUNTIME_ERROR<<" n < Min Order. n= "<<n <<", Min Order = "<<order_min() ;
return this->_data(n-omin, tqa::range(), tqa::range());
}
const_mv_type operator() (int n) const { mv_type operator() (int n) {
if (n>this->order_max()) TRIQS_RUNTIME_ERROR<<" n > Max Order. n= "<<n <<", Max Order = "<<order_max() ; if (n>this->order_max()) TRIQS_RUNTIME_ERROR<<" n > Max Order. n= "<<n <<", Max Order = "<<order_max() ;
if (n<this->order_min()) { mv_type::regular_type r(this->shape()); r()=0; return r;} if (n<this->order_min()) TRIQS_RUNTIME_ERROR<<" n < Min Order. n= "<<n <<", Min Order = "<<order_min() ;
return this->_data(n-omin,tqa::range(), tqa::range()); return this->_data(n-omin, tqa::range(), tqa::range());
} }
/// same as (), but if n is too large, then returns 0 instead of raising an exception const_mv_type operator() (int n) const {
const_mv_type get_or_zero (int n) const { if (n>this->order_max()) TRIQS_RUNTIME_ERROR<<" n > Max Order. n= "<<n <<", Max Order = "<<order_max() ;
if ( (n>this->order_max()) || (n<this->order_min()) ) { mv_type::regular_type r(this->shape()); r()=0; return r;} if (n<this->order_min()) { mv_type::regular_type r(this->shape()); r()=0; return r;}
return this->_data(n-omin,tqa::range(), tqa::range()); return this->_data(n-omin, tqa::range(), tqa::range());
} }
operator freq_infty() const { return freq_infty();} /// same as (), but if n is too large, then returns 0 instead of raising an exception
const_mv_type get_or_zero (int n) const {
if ( (n>this->order_max()) || (n<this->order_min()) ) { mv_type::regular_type r(this->shape()); r()=0; return r; }
return this->_data(n-omin, tqa::range(), tqa::range());
}
/// Save in txt file : doc the format ? ---> prefer serialization or hdf5 ! operator freq_infty() const { return freq_infty(); }
void save(std::string file, bool accumulate=false) const {}
/// Load from txt file : doc the format ? /// Save in txt file : doc the format ? ---> prefer serialization or hdf5 !
//void load(std::string file){} void save(std::string file, bool accumulate=false) const {}
friend std::string get_triqs_hdf5_data_scheme(tail_impl const & g) { return "TailGf";} /// Load from txt file : doc the format ?
//void load(std::string file){}
/// friend std::string get_triqs_hdf5_data_scheme(tail_impl const & g) { return "TailGf"; }
friend void h5_write (h5::group fg, std::string subgroup_name, tail_impl const & t) {
auto gr = fg.create_group(subgroup_name);
// tagging the hdf5 file
//gr.write_triqs_hdf5_data_scheme(t);
h5_write(gr,"omin",t.omin);
h5_write(gr,"mask",t.mask);
h5_write(gr,"data",t._data);
}
friend void h5_read (h5::group fg, std::string subgroup_name, tail_impl & t){ ///
auto gr = fg.open_group(subgroup_name); friend void h5_write (h5::group fg, std::string subgroup_name, tail_impl const & t) {
// Check the attribute or throw auto gr = fg.create_group(subgroup_name);
//auto tag_file = gr.read_triqs_hdf5_data_scheme(); // tagging the hdf5 file
//auto tag_expected= get_triqs_hdf5_data_scheme(t); //gr.write_triqs_hdf5_data_scheme(t);
//if (tag_file != tag_expected) h5_write(gr,"omin",t.omin);
// TRIQS_RUNTIME_ERROR<< "h5_read : mismatch of the tag TRIQS_HDF5_data_scheme tag in the h5 group : found "<<tag_file << " while I expected "<< tag_expected; h5_write(gr,"mask",t.mask);
h5_read(gr,"omin",t.omin); h5_write(gr,"data",t._data);
h5_read(gr,"mask",t.mask); }
h5_read(gr,"data",t._data);
}
// BOOST Serialization friend void h5_read (h5::group fg, std::string subgroup_name, tail_impl & t){
friend class boost::serialization::access; auto gr = fg.open_group(subgroup_name);
template<class Archive> // Check the attribute or throw
void serialize(Archive & ar, const unsigned int version) { //auto tag_file = gr.read_triqs_hdf5_data_scheme();
ar & boost::serialization::make_nvp("omin",omin); //auto tag_expected= get_triqs_hdf5_data_scheme(t);
ar & boost::serialization::make_nvp("mask",mask); //if (tag_file != tag_expected)
ar & boost::serialization::make_nvp("data",_data); // TRIQS_RUNTIME_ERROR<< "h5_read : mismatch of the tag TRIQS_HDF5_data_scheme tag in the h5 group : found "<<tag_file << " while I expected "<< tag_expected;
h5_read(gr,"omin",t.omin);
h5_read(gr,"mask",t.mask);
h5_read(gr,"data",t._data);
}
// BOOST Serialization
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & boost::serialization::make_nvp("omin",omin);
ar & boost::serialization::make_nvp("mask",mask);
ar & boost::serialization::make_nvp("data",_data);
}
friend std::ostream & operator << (std::ostream & out, tail_impl const & x) {
out <<"tail/tail_view: min/smallest/max = "<< x.order_min() << " " << x.smallest_nonzero() << " "<< x.order_max();
for (long u = x.order_min(); u <= x.order_max(); ++u) out <<"\n ... Order "<<u << " = " << x(u);
return out;
}
};
// -----------------------------
// the view class
class tail_view : public tail_impl <true> {
typedef tail_impl <true> B;
friend class tail;
public :
template<bool V> tail_view(tail_impl<V> const & t): B(t){}
tail_view(B::data_type const &d, B::mask_type const &m, long order_min=-1): B(d, m, order_min) {}
tail_view(tail_view const &) = default;
tail_view(tail_view &&) = default;
void rebind(tail_view const &X) {
omin = X.omin;
mask.rebind(X.mask);
_data.rebind(X._data);
}
inline void rebind(tail const &X);
// operator = for views
tail_view & operator = (const tail_view & rhs) {
if ((_data.shape()[1] != rhs._data.shape()[1]) || (_data.shape()[2] != rhs._data.shape()[2]) || (omin != rhs.omin))
TRIQS_RUNTIME_ERROR<<"tails are incompatible";
mask = rhs.mask;
_data = rhs._data;
return *this;
}
inline tail_view & operator=(const tail & rhs);
tail_view & operator = (std::complex<double> const & x) {
_data() = 0.0;
mv_type(_data(-omin, tqa::range(), tqa::range())) = x;
mask() = omin+_data.shape()[0]-1;
return *this;
} }
friend std::ostream & operator << (std::ostream & out, tail_impl const & x) { using B::operator(); // import all previously defined operator() for overloading
out <<"tail/tail_view: min/smallest/max = "<< x.order_min() << " " << x.smallest_nonzero() << " "<< x.order_max(); friend std::ostream & triqs_nvl_formal_print(std::ostream & out, tail_view const & x) { return out<<"tail_view"; }
for (long u = x.order_min(); u <= x.order_max(); ++u) out <<"\n ... Order "<<u << " = " << x(u);
return out;
}
}; };
// ----------------------------- // -----------------------------
///The View class of GF // the regular class
class tail_view : public tail_impl <true> { class tail : public tail_impl <false> {
typedef tail_impl <true> B; typedef tail_impl <false> B;
friend class tail; friend class tail_view;
public :
tail():B() {}
typedef tqa::mini_vector<size_t,2> shape_type;
tail(size_t N1, size_t N2, long order_min=-1, long size=10): B(N1,N2,order_min,size) {}
tail(shape_type const & sh, long order_min=-1, long size=10): B(sh[0],sh[1],order_min,size) {}
tail(tail const & g): B(g) {}
tail(tail_view const & g): B(g) {}
tail(tail &&) = default;
public : // operator = for values
template<bool V> tail_view(tail_impl<V> const & t): B(t){} tail & operator = (tail_view const & rhs) {
tail_view(B::data_type const &d, long order_min, B::mask_type const &om): B(d, order_min, om){} omin = rhs.omin;
tail_view(tail_view const &) = default; mask = rhs.mask;
tail_view(tail_view &&) = default; _data = rhs._data;
void rebind( tail_view const &X) { return *this;
}
tail & operator = (tail const & rhs) {
omin = rhs.omin;
mask = rhs.mask;
_data = rhs._data;
return *this;
}
using B::operator();
/// The simplest tail corresponding to : omega
static tail_view omega(size_t N1, size_t N2) {
tail t(N1, N2);
t(-1) = 1;
return t;
}
/// The simplest tail corresponding to : omega, constructed from a shape for convenience
static tail_view omega(tail::shape_type const & sh) { return omega(sh[0],sh[1]); }
};
template<typename RHS> void assign_from_expression(tail_view & t,RHS const & rhs) { t = rhs( tail::omega(t.shape()) ); }
inline void tail_view::rebind(tail const &X) {
omin = X.omin; omin = X.omin;
mask.rebind(X.mask); mask.rebind(X.mask);
_data.rebind(X._data); _data.rebind(X._data);
} }
inline void rebind( tail const &X);
//using B::operator=; // import operator = from impl. class or the default = is synthetized inline tail_view & tail_view::operator = (const tail & rhs) {
//tail_view & operator=(const tail_view & rhs) { if (this->data.is_empty()) rebind(rhs); else B::operator=(rhs); return *this; } if ((_data.shape()[1] != rhs._data.shape()[1]) || (_data.shape()[2] != rhs._data.shape()[2]) || (omin != rhs.omin))
TRIQS_RUNTIME_ERROR<<"rhs has different shape";
// operator = for views
tail_view & operator = (const tail_view & rhs) {
if (this->_data.is_empty()) rebind(rhs);
else {
if (rhs.omin < omin) TRIQS_RUNTIME_ERROR<<"rhs has too small omin";
if ((_data.shape()[1] != rhs._data.shape()[1]) || (_data.shape()[2] != rhs._data.shape()[2]))
TRIQS_RUNTIME_ERROR<<"rhs has different shape";
for (size_t i=0; i<mask.shape()[0]; ++i)
for (size_t j=0; j<mask.shape()[1]; ++j)
mask(i,j) = std::min(rhs.mask(i,j), long(omin+size()-1));
for (size_t n=0; n<std::min(size(), size_t(rhs.size()-omin+rhs.omin)); ++n)
if (n < rhs.omin-omin) _data(n,tqa::range(),tqa::range()) = 0.0;
else _data(n,tqa::range(),tqa::range()) = rhs._data(n-rhs.omin+omin,tqa::range(),tqa::range());
}
return *this;
}
inline tail_view & operator=(const tail & rhs);
tail_view & operator=(std::complex<double> const & x) {
if (omin > 0) TRIQS_RUNTIME_ERROR<<"lhs has too large omin";
for (size_t n=0; n<size(); ++n) _data(n, tqa::range(), tqa::range()) = 0.0;
_data(-omin, tqa::range(), tqa::range()) = x;
mask() = omin+size()-1;
return *this;
}
using B::operator(); // import all previously defined operator() for overloading
friend std::ostream & triqs_nvl_formal_print(std::ostream & out, tail_view const & x) { return out<<"tail_view";}
void print_me() const { std::cout << *this << std::endl ; }
};
// -----------------------------
///The regular class
class tail : public tail_impl <false> {
typedef tail_impl <false> B;
friend class tail_view;
public :
tail():B() {}
typedef tqa::mini_vector<size_t,2> shape_type;
tail(size_t N1, size_t N2, size_t size_ = 10, long order_min=-1): B(N1,N2,size_,order_min) {}
tail(shape_type const & sh, size_t size_ = 10, long order_min=-1): B(sh[0],sh[1],size_,order_min) {}
tail(tail const & g): B(g){}
tail(tail_view const & g): B(g){}
tail(tail &&) = default;
// operator = for values
tail & operator = (tail_view const & rhs) {
omin = rhs.omin;
mask = rhs.mask;
_data = rhs._data;
return *this;
}
tail & operator = (tail const & rhs) {
omin = rhs.omin;
mask = rhs.mask; mask = rhs.mask;
_data = rhs._data; _data = rhs._data;
return *this; return *this;
} }
using B::operator(); /// Slice in orbital space
template<bool V> tail_view slice_target(tail_impl<V> const & t, tqa::range R1, tqa::range R2) {
/// The simplest tail corresponding to : omega return tail_view(t.data()(tqa::range(),R1,R2), t.mask_view()(R1,R2), t.order_min());
static tail_view omega(size_t N1, size_t N2, size_t size_) {
tail t(N1, N2, size_, -1);
t(-1) = 1;
return t;
} }
/// The simplest tail corresponding to : omega, constructed from a shape for convenience inline tail inverse(tail_view const & t) {
static tail_view omega(tail::shape_type const & sh, size_t size_) { return omega(sh[0],sh[1],size_);} long omin1 = - t.smallest_nonzero();
long omax1 = std::min(t.order_max() + 2*omin1, t.order_min()+long(t.size())-1);
size_t si = omax1-omin1+1;
}; tail res(t);
res.data() = 0.0;
res.mask_view() = omax1;
template<typename RHS> void assign_from_expression(tail_view & t,RHS const & rhs) { t = rhs( tail::omega(t.shape(),t.size())); } res(omin1) = inverse(t(-omin1));
inline void tail_view::rebind( tail const &X) { for (size_t n=1; n<si; n++) {
omin = X.omin; for (size_t p=0; p<n; p++) {
mask.rebind(X.mask); res(omin1 + n) -= t(n-omin1-p) * res(omin1+p);
_data.rebind(X._data); }
} res(omin1 + n) = res(omin1) * make_clone(res(omin1 + n));
inline tail_view & tail_view::operator = (const tail & rhs) {
if (this->_data.is_empty()) rebind(rhs);
else {
if (rhs.omin < omin) TRIQS_RUNTIME_ERROR<<"rhs has too small omin";
if ((_data.shape()[1] != rhs._data.shape()[1]) || (_data.shape()[2] != rhs._data.shape()[2]))
TRIQS_RUNTIME_ERROR<<"rhs has different shape";
for (size_t i=0; i<mask.shape()[0]; ++i)
for (size_t j=0; j<mask.shape()[1]; ++j)
mask(i,j) = std::min(rhs.mask(i,j), long(omin+size()-1));
for (size_t n=0; n<std::min(size(),size_t(rhs.size()-omin+rhs.omin)); ++n)
if (n < rhs.omin-omin) _data(n,tqa::range(),tqa::range()) = 0.0;
else _data(n,tqa::range(),tqa::range()) = rhs._data(n-rhs.omin+omin, tqa::range(), tqa::range());
} }
return *this; return res;
} }
/// Slice in orbital space inline tail mult_impl(tail_view const & l, tail_view const& r) {
template<bool V> tail_view slice_target(tail_impl<V> const & t, tqa::range R1, tqa::range R2) { if (l.shape()[1] != r.shape()[0] || l.order_min() != r.order_min()) TRIQS_RUNTIME_ERROR<< "tail multiplication : shape mismatch";
return tail_view(t.data()(tqa::range(),R1,R2),t.order_min(),t.mask_view()(R1,R2)); long omin1 = l.smallest_nonzero() + r.smallest_nonzero();
} long omax1 = std::min(r.order_max()+l.smallest_nonzero(), l.order_max()+r.smallest_nonzero());
size_t si = omax1-omin1+1;
inline tail inverse(tail_view const & t) { tail res(l);
res.data() = 0.0;
res.mask_view() = omax1;
// find in t for (long n=res.order_min(); n<=res.order_max(); ++n) {
long omin1 = - t.smallest_nonzero(); // sum_{p}^n a_p b_{n-p}. p <= a.n_max, p >= a.n_min and n-p <=b.n_max and n-p >= b.n_min
long omax1 = t.order_max() + 2*omin1; // hence p <= min ( a.n_max, n-b.n_min ) and p >= max ( a.n_min, n- b.n_max)
size_t si = omax1-omin1+1; const long pmin = std::max(l.smallest_nonzero(), n - r.order_max() );
tail t_inv(t.shape(), si, omin1); const long pmax = std::min(l.order_max(), n - r.smallest_nonzero() );
for (long p = pmin; p <= pmax; ++p) { res(n) += l(p) * r(n-p);}
t_inv(omin1) = inverse(t(-omin1)); }
return res;
for (size_t n=1; n<si; n++) {
for (size_t p=0; p<n; p++) {
t_inv(omin1 + n) -= t(n-omin1-p) * t_inv(omin1+p);
}
t_inv(omin1 + n) = t_inv(omin1) * make_clone(t_inv(omin1 + n));
}
return t_inv;
}
inline tail mult_impl(tail_view const & l, tail_view const& r) {
if (l.shape()[1] != r.shape()[0]) TRIQS_RUNTIME_ERROR<< "tail multiplication : shape mismatch";
long omin1 = l.smallest_nonzero() + r.smallest_nonzero();
long omax1 = std::min(r.order_max()+l.smallest_nonzero(), l.order_max()+r.smallest_nonzero());
size_t si = omax1-omin1+1;
tail res(l.shape()[0], r.shape()[1], si, omin1);
res.data() =0;
for (long n=res.order_min(); n<=res.order_max(); ++n) {
// sum_{p}^n a_p b_{n-p}. p <= a.n_max, p >= a.n_min and n-p <=b.n_max and n-p >= b.n_min
// hence p <= min ( a.n_max, n-b.n_min ) and p >= max ( a.n_min, n- b.n_max)
const long pmin = std::max(l.smallest_nonzero(), n - r.order_max() );
const long pmax = std::min(l.order_max(), n - r.smallest_nonzero() );
for (long p = pmin; p <= pmax; ++p) { res(n) += l(p) * r(n-p);}
}
return res;
}
template<typename T1, typename T2>
TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>)
operator* (T1 const & a, T2 const & b) { return mult_impl(a,b); }
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<tqa::ImmutableMatrix<T1>, LocalTail<T2>>)
operator* (T1 const & a, T2 const & b) {
tail res(b); for (long n=res.order_min(); n<=res.order_max(); ++n) res(n)=a*res(n); return res;
} }
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, tqa::ImmutableMatrix<T2>>) template<typename T1, typename T2>
operator* (T1 const & a, T2 const & b) { TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>)
tail res(a); for (long n=res.order_min(); n<=res.order_max(); ++n) res(n)=res(n)*b; return res; operator* (T1 const & a, T2 const & b) { return mult_impl(a,b); }
}
inline tail operator * (dcomplex a, tail_view const & r) { tail res(r); res.data()*=a; return res;} template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<tqa::ImmutableMatrix<T1>, LocalTail<T2>>)
inline tail operator * (tail_view const & r, dcomplex a) { return a*r; } operator* (T1 const & a, T2 const & b) {
tail res(b); for (long n=res.order_min(); n<=res.order_max(); ++n) res(n)=a*res(n); return res;
}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>) template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, tqa::ImmutableMatrix<T2>>)
operator/ (T1 const & a, T2 const & b) { return a *inverse(b); } operator* (T1 const & a, T2 const & b) {
tail res(a); for (long n=res.order_min(); n<=res.order_max(); ++n) res(n)=res(n)*b; return res;
}
inline tail operator / (tail_view const & r, dcomplex a) { tail res(r); res.data() /=a; return res;} inline tail operator * (dcomplex a, tail_view const & r) { tail res(r); res.data()*=a; return res;}
inline tail operator / (dcomplex a, tail_view const & r) { return a * inverse(r); } inline tail operator * (tail_view const & r, dcomplex a) { return a*r; }
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>) template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>)
operator + (T1 const & l, T2 const& r) { operator/ (T1 const & a, T2 const & b) { return a * inverse(b); }
using arrays::range;
if (l.shape() != r.shape()) TRIQS_RUNTIME_ERROR<< "tail addition : shape mismatch";
long omin1 = std::min(l.smallest_nonzero(),r.smallest_nonzero());
long omax1 = std::min(l.order_max(),r.order_max());
size_t si = omax1-omin1+1;
tail res(l.shape(), si, omin1);
for (long i = res.order_min(); i<=res.order_max(); ++i) res(i) = l(i) + r(i);
return res;
}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>) inline tail operator / (tail_view const & r, dcomplex a) { tail res(r); res.data() /=a; return res;}
operator - (T1 const & l, T2 const& r) { inline tail operator / (dcomplex a, tail_view const & r) { return a * inverse(r); }
using arrays::range;
if (l.shape() != r.shape()) TRIQS_RUNTIME_ERROR<< "tail substraction : shape mismatch";
long omin1 = std::min(l.smallest_nonzero(),r.smallest_nonzero());
long omax1 = std::min(l.order_max(),r.order_max());
size_t si = omax1-omin1+1;
tail res(l.shape(), si, omin1);
for (long i = res.order_min(); i<=res.order_max(); ++i) res(i) = l(i) - r(i);
return res;
}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<is_scalar_or_element<T1>, LocalTail<T2>>) template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>)
operator + (T1 const & a, T2 const & t) { operator + (T1 const & l, T2 const& r) {
tail res(t); if (l.shape() != r.shape() || l.order_min() != r.order_min()) TRIQS_RUNTIME_ERROR<< "tail addition : shape mismatch";
res(0) += a; tail res(l.shape());
return res; res.mask_view() = std::min(l.order_max(), r.order_max());
} for (long i = res.order_min(); i<=res.order_max(); ++i) res(i) = l(i) + r(i);
return res;
}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, LocalTail<T2>>)
operator - (T1 const & l, T2 const& r) {
if (l.shape() != r.shape() || l.order_min() != r.order_min()) TRIQS_RUNTIME_ERROR<< "tail addition : shape mismatch";
tail res(l.shape());
res.mask_view() = std::min(l.order_max(), r.order_max());
for (long i = res.order_min(); i<=res.order_max(); ++i) res(i) = l(i) - r(i);
return res;
}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, is_scalar_or_element<T2>>) template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<is_scalar_or_element<T1>, LocalTail<T2>>)
operator + (T1 const & t, T2 const & a) { return a+t;} operator + (T1 const & a, T2 const & t) {
tail res(t);
res(0) += a;
return res;
}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<is_scalar_or_element<T1>, LocalTail<T2>>) template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, is_scalar_or_element<T2>>)
operator - (T1 const & a, T2 const & t) { return (-a) + t;} operator + (T1 const & t, T2 const & a) { return a+t;}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, is_scalar_or_element<T2>>) template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<is_scalar_or_element<T1>, LocalTail<T2>>)
operator - (T1 const & t, T2 const & a) { return (-a) + t;} operator - (T1 const & a, T2 const & t) { return (-a) + t;}
template<typename T1, typename T2> TYPE_ENABLE_IF(tail,mpl::and_<LocalTail<T1>, is_scalar_or_element<T2>>)
operator - (T1 const & t, T2 const & a) { return (-a) + t;}
}}} }}}
#endif #endif