class WPHandler(object):
    def __init__(self):
        try:
            self.kvdb = sae.kvdb.KVClient()
        except:
            self.kvdb = Nothing()

    def POST(self):
        cur_key = const.QUOTE_PREFIX + str(time.time()+86400) #datetime.datetime.today().isoformat()
        handler = CGIXMLRPCRequestHandler()
        handler.register_introspection_functions()
        handler.register_instance(Mt(partial(self.kvdb.set, cur_key))) #timeout won't work
        return handler.handle_xmlrpc(web.data())

    def GET(self):
        if web.input().get('del') and web.input(confirm='')['confirm']=='yes':
            self.kvdb.delete(web.input(_unicode=False).get('del'))
        if not self.kvdb.get_by_prefix(const.QUOTE_PREFIX): return 'not yet.'
        quotes = self.kvdb.get_by_prefix(const.QUOTE_PREFIX)
        body_frag = []
        for q in quotes:
            body_frag.append('<tr><td>%s</td><td>%s</td><td><a href="?del=%s"> X </a></td></tr>' % (q[0], q[1], q[0]))
        body = '<table border="1px">' + ''.join(body_frag) + '</table>'
        web.header('Content-Type', 'text/html; charset=utf-8', unique=True)
        web.header('Content-Length', len(body), unique=True)
        return body

# sae.kvdb.KVClient().delete('quotes_2012-11-20T00:57:01.754429')

# cur_key = 'quotes_1353582306.66'
# sae.kvdb.KVClient().delete(cur_key)

# cur_key = const.QUOTE_PREFIX + '1353581051.907943'
# sae.kvdb.KVClient().set(cur_key, '''<p>当年,弗里德曼的《世界是平的》对我影响最深的一句话:“你可以当会计师,可以当医生,但是不管你当什么,你都要当一个搜索引擎排名靠前者”。</p>''', time=86400)
示例#2
0
 def tail(self, t):
     if type(t) == TailGf:
         assert (self.N1, self.N2) == (t.N1, t.N2)
         self._singularity.copy_from (t)
     elif type(t) == Nothing:
         self._singularity = Nothing()
     else:
         raise RuntimeError, "invalid rhs for tail assignment"
示例#3
0
 def tail(self, t):
     if type(t) == TailGf:
         assert (self.N1, self.N2) == (t.N1, t.N2)
         self._singularity.copy_from (t)
     elif type(t) == Nothing:
         self._singularity = Nothing()
     else:
         raise RuntimeError, "invalid rhs for tail assignment"
示例#4
0
    def __init__(self, **d):
        """
        The constructor have two variants : you can either provide the mesh in
        Matsubara frequencies yourself, or give the parameters to build it.
        All parameters must be given with keyword arguments.

        GfImFreq(indices, beta, statistic, n_points, data, tail, name)

              * ``indices``:  a list of indices names of the block
              * ``beta``:  Inverse Temperature
              * ``statistic``:  'F' or 'B'
              * ``positive_only``:  True or False
              * ``n_points``:  Number of Matsubara frequencies
              * ``data``:   A numpy array of dimensions (len(indices),len(indices),n_points) representing the value of the Green function on the mesh.
              * ``tail``:  the tail
              * ``name``:  a name of the GF

        GfImFreq(indices, mesh, data, tail, name)

              * ``indices``:  a list of indices names of the block
              * ``mesh``:  a MeshGf object, such that mesh.TypeGF== GF_Type.Imaginary_Frequency
              * ``data``:   A numpy array of dimensions (len(indices),len(indices),:) representing the value of the Green function on the mesh.
              * ``tail``:  the tail
              * ``name``:  a name of the GF

        .. warning::

          The Green function take a **view** of the array data, and a **reference** to the tail.

        """
        mesh = d.pop('mesh', None)
        if mesh is None:
            if 'beta' not in d: raise ValueError, "beta not provided"
            beta = float(d.pop('beta'))
            n_points = d.pop('n_points', 1025)
            stat = d.pop('statistic', 'F')
            positive_only = d.pop('positive_only', True)
            mesh = MeshImFreq(beta, stat, n_points, positive_only)

        self.dtype = numpy.complex_
        indices_pack = get_indices_in_dict(d)
        indicesL, indicesR = indices_pack
        N1, N2 = len(indicesL), len(indicesR)
        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))
        symmetry = d.pop('symmetry', Nothing())
        name = d.pop('name', 'g')
        assert len(
            d
        ) == 0, "Unknown parameters in GFBloc constructions %s" % d.keys()

        GfGeneric.__init__(self, mesh, data, tail, symmetry, indices_pack,
                           name, GfImFreq)
        GfImFreq_cython.__init__(self, mesh, data, tail)
 def __init__(self):
     try:
         self.kvdb = sae.kvdb.KVClient()
     except:
         self.kvdb = Nothing()
示例#6
0
class GfGeneric:

    def __init__(self, mesh, data, singularity, symmetry, indices_pack, name, derived):

        self._mesh = mesh
        self._data = data
        self._singularity = singularity
        self._symmetry = symmetry
        self._indices_pack = indices_pack
        self.name = name
        self._derived = derived

        self.indicesR, self.indicesL = indices_pack

        copy_reg.pickle(derived, reductor, builder_cls_with_dict_arg )

    @property
    def mesh(self): return self._mesh

    @property
    def tail(self): return self._singularity
    @tail.setter
    def tail(self, t):
        if type(t) == TailGf:
            assert (self.N1, self.N2) == (t.N1, t.N2)
            self._singularity.copy_from (t)
        elif type(t) == Nothing:
            self._singularity = Nothing()
        else:
            raise RuntimeError, "invalid rhs for tail assignment"

    @property
    def data(self): return self._data
    @data.setter
    def data (self, value): self._data[:,:,:] = value

    @property
    def indices(self):
      assert (self.indicesR == self.indicesL), "right and left indices are different"
      return self.indicesR

    @property
    def N1(self): return self._data.shape[1]

    @property
    def N2(self): return self._data.shape[2]

    #---------------------   h5 and reduction ------------------------------------------

    def __reduce_to_dict__(self):
        return {'mesh': self._mesh, 'data': self._data,
                'tail': self._singularity, 'symmetry': self._symmetry,
                'indices_pack': self._indices_pack, 'name': self.name }

    def __write_hdf5__ (self, gr, key):
        self.__write_hdf5_cython__(gr, key)
        gr[key].create_group('indices')
        gr[key]['indices']['left'] = self.indicesL
        gr[key]['indices']['right'] = self.indicesR
        #gr[key]['name'] = self.name

    #---------------------   copies        ------------------------------------------

    def copy(self):
        return self._derived(indices_pack = self._indices_pack, mesh = self._mesh,
                             data = self._data.copy(), tail = self._singularity.copy(),
                             name = self.name)

    def copy_from(self, X):
        assert self._derived is X._derived
        assert self.mesh == X.mesh
        self.data = X.data
        self.tail = X.tail
        #assert list(self._indices)== list(X._indices)
        self._symmetry = X._symmetry
        self.name = X.name

    #---------------------   [  ] operator        ------------------------------------------

    def __getitem__(self, key):
        """Key is a tuple of index (n1, n2) as defined at construction"""
        if len(key) !=2: raise KeyError, "[ ] must be given two arguments"
        sl1, sl2 = key
        if type(sl1) == StringType and type(sl2) == StringType:
            # Convert the indices to integer
            indices_converter = [ IndicesConverter(self.indicesL), IndicesConverter(self.indicesR)]
            sl1, sl2 =  [ indices_converter[i].convertToNumpyIndex(k) for i, k in enumerate(key) ]
        if type (sl1) != slice: sl1 = slice (sl1, sl1+1)
        if type (sl2) != slice: sl2 = slice (sl2, sl2+1)
        return self.__class__(indicesL = list(self.indicesL)[sl1],
                              indicesR = list(self.indicesR)[sl2],
                              name = self.name,
                              mesh = self.mesh,
                              data = self.data[:,sl1,sl2],
                              tail = self.tail._make_slice(sl1, sl2))

    def __setitem__(self, key, val):
        g = self.__getitem__(key)
        g <<= val

    #------------- Iteration ------------------------------------

    def __iter__(self):
        for i in self.indicesL:
            for j in self.indicesR:
                b =self[i, j]
                b.name = "%s_%s_%s"%(self.name if hasattr(self, 'name') else '', i, j)
                yield i, j, b

    #---------------- Repr, str ---------------------------------

    def __str__(self):
        return self.name if self.name else repr(self)

    def __repr__(self):
        return """%s %s: indicesL = %s, indicesR = %s"""%(self.__class__.__name__, self.name,
          [x for x in self.indicesL], [x for x in self.indicesR])

    #--------------   PLOT   ---------------------------------------

    @property
    def real(self):
        """Use self.real in a plot to plot only the real part"""
        return PlotWrapperPartialReduce(self, RI='R')

    @property
    def imag(self):
        """Use self.imag in a plot to plot only the imag part"""
        return PlotWrapperPartialReduce(self, RI='I')

    #------------------

    def x_data_view(self, x_window = None, flatten_y = False):
        """
        :param x_window: the window of x variable (omega/omega_n/t/tau) for which data is requested
                          if None, take the full window
        :param flatten_y: If the Green function is of size (1, 1) flatten the array as a 1d array
        :rtype: a tuple (X, data) where
                 * X is a 1d numpy of the x variable inside the window requested
                 * data is a 3d numpy array of dim (:,:, len(X)), the corresponding slice of data
                   If flatten_y is True and dim is (1, 1, *), returns a 1d numpy
        """
        X = [x.imag for x in self.mesh] if type(self.mesh) == MeshImFreq else [x for x in self.mesh]
        X, data = numpy.array(X), self.data
        if x_window:
          sl = clip_array (X, *x_window) if x_window else slice(len(X)) # the slice due to clip option x_window
          X, data = X[sl],  data[sl,:,:]
        if flatten_y and data.shape[1:3]==(1, 1): data = data[:,0,0]
        return X, data

    #--------  LAZY expression system -----------------------------------------

    def __lazy_expr_eval_context__(self):
        return LazyCTX(self)

    def __eq__(self, other):
        raise RuntimeError, " Operator not defined "

    def __ilshift__(self, A):
        """ A can be two things:
          * G <<= any_init will init the GFBloc with the initializer
          * G <<= g2 where g2 is a GFBloc will copy g2 into self
        """
        if isinstance(A, self.__class__):
            if self is not A: self.copy_from(A) # otherwise it is useless AND does not work !!
        elif isinstance(A, lazy_expressions.LazyExpr): # A is a lazy_expression made of GF, scalars, descriptors
            A2= descriptors.convert_scalar_to_const(A)
            def e_t (x):
                if not isinstance(x, descriptors.Base): return x
                tmp = self.copy()
                x(tmp)
                return tmp
            self.copy_from (lazy_expressions.eval_expr_with_context(e_t, A2) )
        elif isinstance(A, lazy_expressions.LazyExprTerminal): #e.g. g<<= SemiCircular (...)
            self <<= lazy_expressions.LazyExpr(A)
        elif descriptors.is_scalar(A): #in the case it is a scalar ....
            self <<= lazy_expressions.LazyExpr(A)
        else:
            raise RuntimeError, " <<= operator: RHS  not understood"
        return self

    #--------------------  Arithmetic operations  ---------------------------------

    def __add_iadd_impl (self, lhs,  arg, is_add):
        d, t, rhs = lhs.data, lhs.tail,None
        if type(lhs) == type(arg):
            d[:,:,:] += arg.data
            t += arg.tail
        elif isinstance(arg, numpy.ndarray): # an array considered as a constant function
            MatrixStack(lhs.data).add(arg)
            rhs = arg
        elif descriptors.is_scalar(arg): # just a scalar
            arg = arg*numpy.identity(lhs.N1,dtype = lhs.data.dtype )
            MatrixStack(lhs.data).add(arg)
            assert lhs.tail.shape[0] == lhs.tail.shape[1], "tail + scalar only valid in diagonal case"
            rhs = numpy.identity(lhs.tail.shape[0]) *arg
        else:
            raise RuntimeError, " argument type not recognized in += for %s"%arg
        if rhs !=None :
            new_tail = TailGf(shape=lhs.tail.shape)
            new_tail[0][:,:] = rhs
            if is_add : lhs._singularity = lhs.tail + new_tail
            else : lhs.tail = lhs.tail + new_tail
        return lhs
 
    def __iadd__(self, arg):
        return self.__add_iadd_impl(self,arg,False)

    def __add__(self, y):
        if descriptors.is_lazy(y): return lazy_expressions.make_lazy(self) + y
        c = self.copy()
        return self.__add_iadd_impl(c,y,True)

    def __radd__(self, y): return self.__add__(y)

    def __sub_isub_impl (self, lhs,  arg, is_sub):
        d, t, rhs = lhs.data, lhs.tail,None
        if type(lhs) == type(arg):
            d[:,:,:] -= arg.data
            t -= arg.tail
        elif isinstance(arg, numpy.ndarray): # an array considered as a constant function
            MatrixStack(lhs.data).sub(arg)
            rhs = arg
        elif descriptors.is_scalar(arg): # just a scalar
            arg = arg*numpy.identity(lhs.N1,dtype = lhs.data.dtype )
            MatrixStack(lhs.data).sub(arg)
            assert lhs.tail.shape[0] == lhs.tail.shape[1], "tail - scalar only valid in diagonal case"
            rhs = numpy.identity(lhs.tail.shape[0]) *arg
        else:
            raise RuntimeError, " argument type not recognized in -= for %s"%arg
        if rhs !=None :
            new_tail = TailGf(shape=lhs.tail.shape)
            new_tail[0][:,:] = rhs
            if is_sub : lhs._singularity = lhs.tail - new_tail
            else : lhs.tail = lhs.tail - new_tail
        return lhs
 
    def __isub__(self, arg):
        return self.__sub_isub_impl(self,arg,False)

    def __sub__(self, y):
        if descriptors.is_lazy(y): return lazy_expressions.make_lazy(self) - y
        c = self.copy()
        return self.__sub_isub_impl(c,y,True)

    def __rsub__(self, y):
        c = (-1)*self.copy()
        return c + y # very important to use the as +, cf above, _singularity vs tail

    def __imul__(self, arg):

        if type(self) == type(arg):
            d, d2 = self.data, arg.data
            assert d.shape == d2.shape, " Green function block multiplication with arrays of different size !"
            for om in range (d.shape[0]):
                d[om,:,:] = numpy.dot(d[om,:,:], d2[om,:,:])
            self.tail = self.tail * arg.tail
        elif descriptors.is_scalar(arg):
            self.data *= arg
            self.tail *= arg
        else:
            raise RuntimeError, " argument type not recognized in *= for %s"%arg
        return self

    def __mul__(self, arg):

        if descriptors.is_lazy(arg):
          return lazy_expressions.make_lazy(self) * arg
        else:
          res = self.copy()
          res *= arg
          return res

    def __rmul__(self, arg):

        if descriptors.is_lazy(arg):
          return arg * lazy_expressions.make_lazy(self)
        elif descriptors.is_scalar(arg):
          return self.__mul__(arg)

    def from_L_G_R(self, L, G, R):

      N1 = self.data.shape[1]
      N2 = self.data.shape[2]
      assert L.shape[0] == N1
      assert L.shape[1] == G.data.shape[1]
      assert R.shape[0] == G.data.shape[2]
      assert R.shape[1] == N2

      MatrixStack(self.data).matmul_L_R(L, G.data, R)

      # this might be a bit slow
      t = TailGf(shape=(N1,N2))
      for o in range(t.order_min, t.order_max+1):
        t[o] = numpy.dot(L, numpy.dot(G.tail[o], R))
      self.tail = t

    def __idiv__(self, arg):
        """ If arg is a scalar, simple scalar multiplication
        """
        if descriptors.is_lazy(arg): return lazy_expressions.make_lazy(self) / arg
        if descriptors.is_scalar(arg):
            self.data /= arg
            self.tail /= arg
        else:
            raise RuntimeError, " argument type not recognized in imul for %s"%arg
        return self

    def __div__(self, arg):
        assert descriptors.is_scalar(arg), "Error in /"
        res = self.copy()
        res /= arg
        return res

    #---------------------------------------------------

    def zero(self):
      self <<= 0.0

    #---------------------------------------------------

    def invert(self):
        """Invert the matrix for all arguments"""
        MatrixStack(self.data).invert()
        self.tail.invert()

    #---------------------------------------------------

    def transpose(self):
        """Transposes the GF Bloc: return a new transposed view"""
        ### WARNING: this depends on the C++ layering ....
        return self.__class__(
                indices = list(self.indices),
                mesh = self.mesh,
                data = self.data.transpose( (0, 2, 1) ),
                tail = self.tail.transpose(),
                name = self.name+'(t)')

    #---------------------------------------------------

    def conjugate(self):
        """Complex conjugate of the GF Bloc. It follow the policy of numpy and
        make a copy only if the Green function is complex valued"""

        return self.__class__(
                indices = list(self.indices),
                mesh = self.mesh,
                data = self.data.conjugate(),
                tail = self.tail.conjugate(),
                name = self.name+'*')

    #------------------  Density -----------------------------------

    def total_density(self):
        """Trace density"""
        return numpy.trace(self.density())
示例#7
0
class GfGeneric:

    def __init__(self, mesh, data, singularity, symmetry, indices_pack, name, derived):

        self._mesh = mesh
        self._data = data
        self._singularity = singularity
        self._symmetry = symmetry
        self._indices_pack = indices_pack
        self.name = name
        self._derived = derived

        self.indicesL, self.indicesR = indices_pack

        copy_reg.pickle(derived, reductor, builder_cls_with_dict_arg )

    @property
    def mesh(self): return self._mesh

    @property
    def tail(self): return self._singularity
    @tail.setter
    def tail(self, t):
        if type(t) == TailGf:
            assert (self.N1, self.N2) == (t.N1, t.N2)
            self._singularity.copy_from (t)
        elif type(t) == Nothing:
            self._singularity = Nothing()
        else:
            raise RuntimeError, "invalid rhs for tail assignment"

    @property
    def data(self): return self._data
    @data.setter
    def data (self, value): self._data[:,:,:] = value

    @property
    def indices(self):
      assert (self.indicesR == self.indicesL), "right and left indices are different"
      return self.indicesR

    @property
    def N1(self): return self._data.shape[1]

    @property
    def N2(self): return self._data.shape[2]

    #---------------------   h5 and reduction ------------------------------------------

    def __reduce_to_dict__(self):
        return {'mesh': self._mesh, 'data': self._data,
                'tail': self._singularity, 'symmetry': self._symmetry,
                'indices_pack': self._indices_pack, 'name': self.name }

    def __write_hdf5__ (self, gr, key):
        self.__write_hdf5_cython__(gr, key)
        gr[key].create_group('indices')
        gr[key]['indices']['left'] = self.indicesL
        gr[key]['indices']['right'] = self.indicesR
        #gr[key]['name'] = self.name

    #---------------------   copies        ------------------------------------------

    def copy(self):
        return self._derived(indices_pack = self._indices_pack, mesh = self._mesh,
                             data = self._data.copy(), tail = self._singularity.copy(),
                             name = self.name)

    def copy_from(self, X):
        assert self._derived is X._derived
        assert self.mesh == X.mesh
        self.data = X.data
        self.tail = X.tail
        #assert list(self._indices)== list(X._indices)
        self._symmetry = X._symmetry
        self.name = X.name

    #---------------------   [  ] operator        ------------------------------------------

    def __getitem__(self, key):
        """Key is a tuple of index (n1, n2) as defined at construction"""
        if len(key) !=2: raise KeyError, "[ ] must be given two arguments"
        sl1, sl2 = key
        if type(sl1) == StringType and type(sl2) == StringType:
            # Convert the indices to integer
            indices_converter = [ IndicesConverter(self.indicesL), IndicesConverter(self.indicesR)]
            sl1, sl2 =  [ indices_converter[i].convertToNumpyIndex(k) for i, k in enumerate(key) ]
        if type (sl1) != slice: sl1 = slice (sl1, sl1+1)
        if type (sl2) != slice: sl2 = slice (sl2, sl2+1)
        return self.__class__(indicesL = list(self.indicesL)[sl1],
                              indicesR = list(self.indicesR)[sl2],
                              name = self.name,
                              mesh = self.mesh,
                              data = self.data[:,sl1,sl2],
                              tail = self.tail._make_slice(sl1, sl2))

    def __setitem__(self, key, val):
        g = self.__getitem__(key)
        g <<= val

    #------------- Iteration ------------------------------------

    def __iter__(self):
        for i in self.indicesL:
            for j in self.indicesR:
                b =self[i, j]
                b.name = "%s_%s_%s"%(self.name if hasattr(self, 'name') else '', i, j)
                yield i, j, b

    #---------------- Repr, str ---------------------------------

    def __str__(self):
        return self.name if self.name else repr(self)

    def __repr__(self):
        return """%s %s: indicesL = %s, indicesR = %s"""%(self.__class__.__name__, self.name,
          [x for x in self.indicesL], [x for x in self.indicesR])

    #--------------   PLOT   ---------------------------------------

    @property
    def real(self):
        """Use self.real in a plot to plot only the real part"""
        return PlotWrapperPartialReduce(self, RI='R')

    @property
    def imag(self):
        """Use self.imag in a plot to plot only the imag part"""
        return PlotWrapperPartialReduce(self, RI='I')

    #------------------

    def x_data_view(self, x_window = None, flatten_y = False):
        """
        :param x_window: the window of x variable (omega/omega_n/t/tau) for which data is requested
                          if None, take the full window
        :param flatten_y: If the Green function is of size (1, 1) flatten the array as a 1d array
        :rtype: a tuple (X, data) where
                 * X is a 1d numpy of the x variable inside the window requested
                 * data is a 3d numpy array of dim (:,:, len(X)), the corresponding slice of data
                   If flatten_y is True and dim is (1, 1, *), returns a 1d numpy
        """
        X = [x.imag for x in self.mesh] if type(self.mesh) == MeshImFreq else [x for x in self.mesh]
        X, data = numpy.array(X), self.data
        if x_window:
          sl = clip_array (X, *x_window) if x_window else slice(len(X)) # the slice due to clip option x_window
          X, data = X[sl],  data[sl,:,:]
        if flatten_y and data.shape[1:3]==(1, 1): data = data[:,0,0]
        return X, data

    #--------  LAZY expression system -----------------------------------------

    def __lazy_expr_eval_context__(self):
        return LazyCTX(self)

    def __eq__(self, other):
        raise RuntimeError, " Operator not defined "

    def __ilshift__(self, A):
        """ A can be two things:
          * G <<= any_init will init the GFBloc with the initializer
          * G <<= g2 where g2 is a GFBloc will copy g2 into self
        """
        if isinstance(A, self.__class__):
            if self is not A: self.copy_from(A) # otherwise it is useless AND does not work !!
        elif isinstance(A, lazy_expressions.LazyExpr): # A is a lazy_expression made of GF, scalars, descriptors
            A2= descriptors.convert_scalar_to_const(A)
            def e_t (x):
                if not isinstance(x, descriptors.Base): return x
                tmp = self.copy()
                x(tmp)
                return tmp
            self.copy_from (lazy_expressions.eval_expr_with_context(e_t, A2) )
        elif isinstance(A, lazy_expressions.LazyExprTerminal): #e.g. g<<= SemiCircular (...)
            self <<= lazy_expressions.LazyExpr(A)
        elif descriptors.is_scalar(A): #in the case it is a scalar ....
            self <<= lazy_expressions.LazyExpr(A)
        else:
            raise RuntimeError, " <<= operator: RHS  not understood"
        return self

    #--------------------  Arithmetic operations  ---------------------------------

    def __add_iadd_impl (self, lhs,  arg, is_add):
        d, t, rhs = lhs.data, lhs.tail,None
        if type(lhs) == type(arg):
            d[:,:,:] += arg.data
            t += arg.tail
        elif isinstance(arg, numpy.ndarray): # an array considered as a constant function
            MatrixStack(lhs.data).add(arg)
            rhs = arg
        elif descriptors.is_scalar(arg): # just a scalar
            arg = arg*numpy.identity(lhs.N1,dtype = lhs.data.dtype )
            MatrixStack(lhs.data).add(arg)
            assert lhs.tail.shape[0] == lhs.tail.shape[1], "tail + scalar only valid in diagonal case"
            rhs = numpy.identity(lhs.tail.shape[0]) *arg
        else:
            raise RuntimeError, " argument type not recognized in += for %s"%arg
        if rhs !=None :
            new_tail = TailGf(shape=lhs.tail.shape)
            new_tail[0][:,:] = rhs
            if is_add : lhs._singularity = lhs.tail + new_tail
            else : lhs.tail = lhs.tail + new_tail
        return lhs
 
    def __iadd__(self, arg):
        return self.__add_iadd_impl(self,arg,False)

    def __add__(self, y):
        if descriptors.is_lazy(y): return lazy_expressions.make_lazy(self) + y
        c = self.copy()
        return self.__add_iadd_impl(c,y,True)

    def __radd__(self, y): return self.__add__(y)

    def __sub_isub_impl (self, lhs,  arg, is_sub):
        d, t, rhs = lhs.data, lhs.tail,None
        if type(lhs) == type(arg):
            d[:,:,:] -= arg.data
            t -= arg.tail
        elif isinstance(arg, numpy.ndarray): # an array considered as a constant function
            MatrixStack(lhs.data).sub(arg)
            rhs = arg
        elif descriptors.is_scalar(arg): # just a scalar
            arg = arg*numpy.identity(lhs.N1,dtype = lhs.data.dtype )
            MatrixStack(lhs.data).sub(arg)
            assert lhs.tail.shape[0] == lhs.tail.shape[1], "tail - scalar only valid in diagonal case"
            rhs = numpy.identity(lhs.tail.shape[0]) *arg
        else:
            raise RuntimeError, " argument type not recognized in -= for %s"%arg
        if rhs !=None :
            new_tail = TailGf(shape=lhs.tail.shape)
            new_tail[0][:,:] = rhs
            if is_sub : lhs._singularity = lhs.tail - new_tail
            else : lhs.tail = lhs.tail - new_tail
        return lhs
 
    def __isub__(self, arg):
        return self.__sub_isub_impl(self,arg,False)

    def __sub__(self, y):
        if descriptors.is_lazy(y): return lazy_expressions.make_lazy(self) - y
        c = self.copy()
        return self.__sub_isub_impl(c,y,True)

    def __rsub__(self, y):
        c = (-1)*self.copy()
        return c + y # very important to use the as +, cf above, _singularity vs tail

    def __imul__(self, arg):

        if type(self) == type(arg):
            d, d2 = self.data, arg.data
            assert d.shape == d2.shape, " Green function block multiplication with arrays of different size !"
            for om in range (d.shape[0]):
                d[om,:,:] = numpy.dot(d[om,:,:], d2[om,:,:])
            self.tail = self.tail * arg.tail
        elif descriptors.is_scalar(arg):
            self.data *= arg
            self.tail *= arg
        else:
            raise RuntimeError, " argument type not recognized in *= for %s"%arg
        return self

    def __mul__(self, arg):

        if descriptors.is_lazy(arg):
          return lazy_expressions.make_lazy(self) * arg
        else:
          res = self.copy()
          res *= arg
          return res

    def __rmul__(self, arg):

        if descriptors.is_lazy(arg):
          return arg * lazy_expressions.make_lazy(self)
        elif descriptors.is_scalar(arg):
          return self.__mul__(arg)

    def from_L_G_R(self, L, G, R):

      N1 = self.data.shape[1]
      N2 = self.data.shape[2]
      assert L.shape[0] == N1
      assert L.shape[1] == G.data.shape[1]
      assert R.shape[0] == G.data.shape[2]
      assert R.shape[1] == N2

      MatrixStack(self.data).matmul_L_R(L, G.data, R)

      # this might be a bit slow
      for o in range(G.tail.order_min, G.tail.order_max+1):
        self.tail[o] = numpy.dot(L, numpy.dot(G.tail[o], R))
      self.tail.mask.fill(G.tail.order_max)

    def __idiv__(self, arg):
        """ If arg is a scalar, simple scalar multiplication
        """
        if descriptors.is_lazy(arg): return lazy_expressions.make_lazy(self) / arg
        if descriptors.is_scalar(arg):
            self.data /= arg
            self.tail /= arg
        else:
            raise RuntimeError, " argument type not recognized in imul for %s"%arg
        return self

    def __div__(self, arg):
        assert descriptors.is_scalar(arg), "Error in /"
        res = self.copy()
        res /= arg
        return res

    #---------------------------------------------------

    def zero(self):
      self <<= 0.0

    #---------------------------------------------------

    def invert(self):
        """Invert the matrix for all arguments"""
        MatrixStack(self.data).invert()
        self.tail.invert()

    #---------------------------------------------------

    def transpose(self):
        """Transposes the GF Bloc: return a new transposed view"""
        ### WARNING: this depends on the C++ layering ....
        return self.__class__(
                indices = list(self.indices),
                mesh = self.mesh,
                data = self.data.transpose( (0, 2, 1) ),
                tail = self.tail.transpose(),
                name = self.name+'(t)')

    #---------------------------------------------------

    def conjugate(self):
        """Complex conjugate of the GF Bloc. It follow the policy of numpy and
        make a copy only if the Green function is complex valued"""

        return self.__class__(
                indices = list(self.indices),
                mesh = self.mesh,
                data = self.data.conjugate(),
                tail = self.tail.conjugate(),
                name = self.name+'*')

    #------------------  Density -----------------------------------

    def total_density(self):
        """Trace density"""
        return numpy.trace(self.density())