def __init__(self, **other):
     BDSEEstimator.__init__(self, **other)
     
     self.T = ExpectationWeighted()
     self.U = ExpectationWeighted()
     self.y_mean = ExpectationWeighted()  # XXX: not necessary, y_stats.get_mean()
     self.y_stats = MeanCovariance()  # TODO: make robust
     self.u_stats = MeanCovariance()
     self.once = False
    def __init__(self):
        self.Q = ExpectationWeighted()  # XXX bug
        self.P = ExpectationWeighted()
        self.G = ExpectationWeighted()
        self.B = ExpectationWeighted()
 
        self.C = None
        self.C_needs_update = True
        self.R = None
        self.R_needs_update = True
        self.H = None
        self.H_needs_update = True 
 
        self.once = False
class BGDSEstimator1DRobust(BGDSEstimator):
    '''
     
        Dimensions of G:
        - for 1D signals:  (K x 1 x N )
        Dimensions of P (covariance of gradient):  
            (1 x 1 x H x W )    
        Dimensions of Q:
            (K x K)
         
        Dimensions of C:
        - for 1D signals:  (K x N )
     
    '''
    def __init__(self):
        self.Q = ExpectationWeighted()  # XXX bug
        self.P = ExpectationWeighted()
        self.G = ExpectationWeighted()
        self.B = ExpectationWeighted()
 
        self.C = None
        self.C_needs_update = True
        self.R = None
        self.R_needs_update = True
        self.H = None
        self.H_needs_update = True 
 
        self.once = False
        
    @contract(y='(array[M]|array[MxN]),shape(x)',
            y_dot='shape(x)', u='array[K]', w='array[M]')
    def update(self, y, y_dot, u, w):
        self.once = True
        
        M = y.shape[0]
        check_all_finite(y)
        check_all_finite(y_dot)
        check_all_finite(u)
        # TODO: check shape is conserved
        self.is1D = y.ndim == 1
        self.is2D = y.ndim == 2
 
        gy = generalized_gradient(y)
  
        y_dot_w = w
        u_w = np.ones(u.shape)         
        gy_w = w.reshape((1, M)) 
        assert gy.shape == gy_w.shape
        
        Qi = outer(u, u)
        Qi_w = outer(u_w, u_w)
        self.Q.update(Qi, Qi_w)
        
        Pi = outer_first_dim(gy)
        Pi_w = outer_first_dim(gy_w)
         
        self.P.update(Pi, Pi_w)
        self.R_needs_update = True
 
        Gi = outer(u, gy * y_dot)
        Gi_w = outer(u_w, gy_w * y_dot_w)
        
        self.G.update(Gi, Gi_w)
        self.H_needs_update = True
 
        Bk = outer(u, y_dot)
        Bk_w = outer(u_w, y_dot_w)
        self.B.update(Bk, Bk_w)
        self.C_needs_update = True
 
        self.last_y = y
        self.last_gy = gy
        self.last_y_dot = y_dot
        self.last_u = u
        self.last_w = w
class BDSEEstimatorRobust(BDSEEstimator):

    def __init__(self, **other):
        BDSEEstimator.__init__(self, **other)
        
        self.T = ExpectationWeighted()
        self.U = ExpectationWeighted()
        self.y_mean = ExpectationWeighted()  # XXX: not necessary, y_stats.get_mean()
        self.y_stats = MeanCovariance()  # TODO: make robust
        self.u_stats = MeanCovariance()
        self.once = False
        
    def merge(self, other):
        assert isinstance(other, BDSEEstimatorRobust)
        self.T.merge(other.T)
        self.U.merge(other.U)
        self.y_stats.merge(other.y_stats)
        self.y_mean.merge(other.y_mean)
        self.u_stats.merge(other.u_stats)

    @contract(u='array[K],K>0,finite',
              y='array[N],N>0,finite',
              y_dot='array[N],finite',
              w='array[N]')
    def update(self, y, u, y_dot, w):
        self.once = True
        self.nsamples += 1
        
        check_all_finite(y)
        check_all_finite(u)
        check_all_finite(y_dot)
        check_all_finite(w)
        
        self.n = y.size
        self.k = u.size   

        self.y_stats.update(y)  # TODO: make robust 
        self.u_stats.update(u)
        
        # remove mean
        u_n = u - self.u_stats.get_mean()
        self.y_mean.update(y, w)  # TODO: make robust
        y_n = y - self.y_mean.get_value(fill_value=0.5)
        
        # weights
        y_n_w = w
        y_dot_w = w
        u_n_w = np.ones(u.shape)
        
        T_k = outer(outer(y_n, y_dot), u_n)
        T_k_w = outer(outer(y_n_w, y_dot_w), u_n_w)
        
        U_k = outer(y_dot, u_n)
        U_k_w = outer(y_dot_w, u_n_w) 

        assert T_k.shape == (self.n, self.n, self.k)
        assert U_k.shape == (self.n, self.k)
        
        # update tensor
        self.T.update(T_k, T_k_w)
        self.U.update(U_k, U_k_w)