Exemple #1
0
 def set_TR(self, radius, B_op):
     assert self.parameters["zero_initial_guess"]
     self.TR_radius_2 = radius * radius
     self.update_x = self.update_x_with_TR
     self.B_op = B_op
     self.Bx = Vector()
     self.B_op.init_vector(self.Bx, 0)
Exemple #2
0
    def trace(self, W=None):
        """
        Compute the trace of A.
        If the weight W is given compute the trace of W^1/2AW^1/2.
        This is equivalent to
        tr_W(A) = \sum_i lambda_i,
        where lambda_i are the generalized eigenvalues of
        A x = lambda W^-1 x.
        
        Note if U is a W-orthogonal matrix then
        tr_W(A) = \sum_i D(i,i). 
        """
        if W is None:
            diagUtU = np.sum(self.U * self.U, 0)
            tr = np.sum(self.d * diagUtU)
        else:
            WU = np.zeros(self.U.shape, dtype=self.U.dtype)
            u, wu = Vector(), Vector()
            W.init_vector(u, 1)
            W.init_vector(wu, 0)
            for i in range(self.U.shape[1]):
                u.set_local(self.U[:, i])
                W.mult(u, wu)
                WU[:, i] = wu.array()
            diagWUtU = np.sum(WU * self.U, 0)
            tr = np.sum(self.d * diagWUtU)

        return tr
Exemple #3
0
def nonzero_values(function):
    serialized_vector = Vector(MPI.COMM_SELF)
    function.vector().gather(
        serialized_vector, array(range(function.function_space().dim()),
                                 "intc"))
    indices = nonzero(serialized_vector.get_local())
    return sort(serialized_vector.get_local()[indices])
Exemple #4
0
    def __init__(self,
                 form,
                 Space,
                 bcs=[],
                 name="x",
                 matvec=[None, None],
                 method="default",
                 solver_type="cg",
                 preconditioner_type="default"):

        Function.__init__(self, Space, name=name)
        self.form = form
        self.method = method
        self.bcs = bcs
        self.matvec = matvec
        self.trial = trial = TrialFunction(Space)
        self.test = test = TestFunction(Space)
        Mass = inner(trial, test) * dx()
        self.bf = inner(form, test) * dx()
        self.rhs = Vector(self.vector())

        if method.lower() == "default":
            self.A = A_cache[(Mass, tuple(bcs))]
            self.sol = Solver_cache[(Mass, tuple(bcs), solver_type,
                                     preconditioner_type)]

        elif method.lower() == "lumping":
            assert Space.ufl_element().degree() < 2
            self.A = A_cache[(Mass, tuple(bcs))]
            ones = Function(Space)
            ones.vector()[:] = 1.
            self.ML = self.A * ones.vector()
            self.ML.set_local(1. / self.ML.array())
Exemple #5
0
def get_diagonal(A, d, solve_mode=True):
    """
    Compute the diagonal of the square operator A
    or its inverse A^{-1} (if solve_mode=True).
    """
    ej, xj = Vector(), Vector()

    if hasattr(A, "init_vector"):
        A.init_vector(ej, 1)
        A.init_vector(xj, 0)
    else:
        A.get_operator().init_vector(ej, 1)
        A.get_operator().init_vector(xj, 0)

    ncol = ej.size()
    da = np.zeros(ncol, dtype=ej.array().dtype)

    for j in range(ncol):
        ej[j] = 1.
        if solve_mode:
            A.solve(xj, ej)
        else:
            A.mult(ej, xj)
        da[j] = xj[j]
        ej[j] = 0.

    d.set_local(da)
def estimate_diagonal_inv2(Asolver, k, d):
    """
    An unbiased stochastic estimator for the diagonal of A^-1.
    d = [ \sum_{j=1}^k vj .* A^{-1} vj ] ./ [ \sum_{j=1}^k vj .* vj ]
    where
    - vj are i.i.d. ~ N(0, I)
    - .* and ./ represent the element-wise multiplication and division
      of vectors, respectively.
      
    REFERENCE:
    Costas Bekas, Effrosyni Kokiopoulou, and Yousef Saad,
    An estimator for the diagonal of a matrix,
    Applied Numerical Mathematics, 57 (2007), pp. 1214-1229.
    """
    x, b = Vector(), Vector()

    if hasattr(Asolver, "init_vector"):
        Asolver.init_vector(x, 1)
        Asolver.init_vector(b, 0)
    else:
        Asolver.get_operator().init_vector(x, 1)
        Asolver.get_operator().init_vector(b, 0)

    d.zero()
    for i in range(k):
        x.zero()
        Random.normal(b, 1., True)
        Asolver.solve(x, b)
        x *= b
        d.axpy(1. / float(k), x)
Exemple #7
0
def estimate_diagonal_inv2(Asolver, k, d):
    """
    An unbiased stochastic estimator for the diagonal of :math:`A^{-1}`.
    :math:`d = [ \sum_{j=1}^k v_j .* A^{-1} v_j ] ./ [ \sum_{j=1}^k v_j .* v_j ]`
    where

    - :math:`v_j` are i.i.d. :math:`\mathcal{N}(0, I)`
    - :math:`.*` and :math:`./` represent the element-wise multiplication and division
      of vectors, respectively.
      
    Reference:
        `Costas Bekas, Effrosyni Kokiopoulou, and Yousef Saad, 
        An estimator for the diagonal of a matrix, 
        Applied Numerical Mathematics, 57 (2007), pp. 1214-1229.`
    """
    x, b = Vector(d.mpi_comm()), Vector(d.mpi_comm())
    
    if hasattr(Asolver, "init_vector"):
        Asolver.init_vector(x,1)
        Asolver.init_vector(b,0)
    else:       
        Asolver.get_operator().init_vector(x,1)
        Asolver.get_operator().init_vector(b,0)
        
    d.zero()
    for i in range(k):
        x.zero()
        parRandom.normal(1., b)
        Asolver.solve(x,b)
        x *= b
        d.axpy(1./float(k), x)
    def __init__(self, A, solve_mode=False, accurancy = 1e-1, init_vector=None, random_engine=rademacher_engine, mpi_comm=mpi_comm_world()):
        """
        Constructor:

        - :code:`A`:             an operator
        - :code:`solve_mode`:    if :code:`True` we estimate the trace of :code:`A`:math:`^{-1}`, otherwise of :code:`A`.
        - code:`accurancy`:     we stop when the standard deviation of the estimator is less then
                         :code:`accurancy`*tr(:code:`A`).
        - :code:`init_vector`:   use a custom function to initialize a vector compatible with the
                         range/domain of :code:`A`.
        - :code:`random_engine`: which type of i.i.d. random variables to use (Rademacher or Gaussian). 
        """
        if solve_mode:
            self.A = Solver2Operator(A)
        else:
            self.A = A
        self.accurancy = accurancy
        self.random_engine = random_engine
        self.iter = 0
        
        self.z = Vector(mpi_comm)
        self.Az = Vector(mpi_comm)
        
        if init_vector is None:
            A.init_vector(self.z, 0)
            A.init_vector(self.Az, 0)
        else:
            init_vector(self.z, 0)
            init_vector(self.Az, 0)
Exemple #9
0
    def __init__(self,
                 A,
                 solve_mode=False,
                 accurancy=1e-1,
                 init_vector=None,
                 random_engine=rademacher_engine):
        """
        Constructor:
        - A: an operator
        - solve_mode:    if True we estimate the trace of A^{-1}, otherwise of A.
        - accurancy:     we stop when the standard deviation of the estimator is less then
                         accurancy*tr(A).
        - init_vector:   use a custom function to initialize a vector compatible with the
                         range/domain of A
        - random_engine: which type of i.i.d. random variables to use (Rademacher or Gaussian)  
        """
        self.A = A
        self.accurancy = accurancy
        self.random_engine = random_engine
        self.iter = 0

        self.z = Vector()
        self.Az = Vector()

        if solve_mode:
            self._apply = self._apply_solve
        else:
            self._apply = self._apply_mult

        if init_vector is None:
            A.init_vector(self.z, 0)
            A.init_vector(self.Az, 0)
        else:
            init_vector(self.z, 0)
            init_vector(self.Az, 0)
Exemple #10
0
def estimate_diagonal_inv2(Asolver, k, d):
    """
    An unbiased stochastic estimator for the diagonal of :math:`A^{-1}`.
    :math:`d = [ \sum_{j=1}^k v_j .* A^{-1} v_j ] ./ [ \sum_{j=1}^k v_j .* v_j ]`
    where

    - :math:`v_j` are i.i.d. :math:`\mathcal{N}(0, I)`
    - :math:`.*` and :math:`./` represent the element-wise multiplication and division
      of vectors, respectively.
      
    Reference:
        `Costas Bekas, Effrosyni Kokiopoulou, and Yousef Saad, 
        An estimator for the diagonal of a matrix, 
        Applied Numerical Mathematics, 57 (2007), pp. 1214-1229.`
    """
    x, b = Vector(d.mpi_comm()), Vector(d.mpi_comm())

    if hasattr(Asolver, "init_vector"):
        Asolver.init_vector(x, 1)
        Asolver.init_vector(b, 0)
    else:
        Asolver.get_operator().init_vector(x, 1)
        Asolver.get_operator().init_vector(b, 0)

    d.zero()
    for i in range(k):
        x.zero()
        parRandom.normal(1., b)
        Asolver.solve(x, b)
        x *= b
        d.axpy(1. / float(k), x)
Exemple #11
0
    def trace2(self, W=None):
        """
        Compute the trace of A*A (Note this is the square of Frob norm, since A is symmetic).
        If the weight W is provided, it will compute the trace of (AW)^2.
        
        This is equivalent to 
        tr_W(A) = \sum_i lambda_i^2,
        where lambda_i are the generalized eigenvalues of
        A x = lambda W^-1 x.
        
        Note if U is a W-orthogonal matrix then
        tr_W(A) = \sum_i D(i,i)^2. 
        """
        if W is None:
            UtU = np.dot(self.U.T, self.U)
            dUtU = self.d[:, None] * UtU  #diag(d)*UtU.
            tr2 = np.sum(dUtU * dUtU)
        else:
            WU = np.zeros(self.U.shape, dtype=self.U.dtype)
            u, wu = Vector(), Vector()
            W.init_vector(u, 1)
            W.init_vector(wu, 0)
            for i in range(self.U.shape[1]):
                u.set_local(self.U[:, i])
                W.mult(u, wu)
                WU[:, i] = wu.array()
            UtWU = np.dot(self.U.T, WU)
            dUtWU = self.d[:, None] * UtWU  #diag(d)*UtU.
            tr2 = np.power(np.linalg.norm(dUtWU), 2)

        return tr2
Exemple #12
0
 def __init__(self, prior, d, U):
     self.prior = prior
     self.LowRankH = LowRankOperator(d, U)
     dsolve = d / (np.ones(d.shape, dtype=d.dtype) + d)
     self.LowRankHinv = LowRankOperator(dsolve, U)
     self.help = Vector()
     self.init_vector(self.help, 0)
     self.help1 = Vector()
     self.init_vector(self.help1, 0)
Exemple #13
0
    def __init__(self, S, mpi_comm=mpi_comm_world(), init_vector=None):
        self.S = S
        self.tmp = Vector(mpi_comm)
        self.my_init_vector = init_vector

        if self.my_init_vector is None:
            if hasattr(self.S, "init_vector"):
                self.my_init_vector = self.S.init_vector
            elif hasattr(self.S, "operator"):
                self.my_init_vector = self.S.operator().init_vector
            elif hasattr(self.S, "get_operator"):
                self.my_init_vector = self.S.get_operator().init_vector
Exemple #14
0
    def build_pressure_null_space(self):
        # Prepare function used to correct pressure values
        null_fcn = Function(self.subspace("p"))
        null_fcn.vector()[:] = 1.0

        # Create vector that spans the null space and normalize
        null_vec = Vector(null_fcn.vector())
        null_vec *= 1.0 / null_vec.norm("l2")
        # FIXME: Check what are relevant norms for different Krylov methods

        # Create null space basis object
        null_space = VectorSpaceBasis([null_vec])

        return (null_space, null_fcn)
Exemple #15
0
def AorthogonalityCheck(A, U, d):
    """
    Test the frobenious norm of  D^{-1}(U^TAU) - I_k
    """
    V = np.zeros(U.shape)
    AV = np.zeros(U.shape)
    Av = Vector()
    v = Vector()
    A.init_vector(Av,0)
    A.init_vector(v,1)
    
    nvec  = U.shape[1]
    for i in range(0,nvec):
        v.set_local(U[:,i])
        v *= 1./math.sqrt(d[i])
        A.mult(v,Av)
        AV[:,i] = Av.array()
        V[:,i] = v.array()
        
    VtAV = np.dot(V.T, AV)    
    err = VtAV - np.eye(nvec, dtype=VtAV.dtype)
    
#    plt.imshow(np.abs(err))
#    plt.colorbar()
#    plt.show()
    
    print "i, ||Vt(i,:)AV(:,i) - I_i||_F, V[:,i] = 1/sqrt(lambda_i) U[:,i]"
    for i in range(1,nvec+1):
        print i, np.linalg.norm(err[0:i,0:i], 'fro')
Exemple #16
0
def doublePass(A,Omega,k):
    """
    The double pass algorithm for the HEP as presented in [1].
    Inputs:
    - A: the operator for which we need to estimate the dominant eigenpairs.
    - Omega: a random gassian matrix with m >= k columns.
    - k: the number of eigenpairs to extract.
    
    Outputs:
    - d: the estimate of the k dominant eigenvalues of A
    - U: the estimate of the k dominant eigenvectors of A. U^T U = I_k
    """
    w = Vector()
    y = Vector()
    A.init_vector(w,1)
    A.init_vector(y,0)
    
    nvec  = Omega.shape[1]
    
    assert(nvec >= k )
    
    Y = np.zeros(Omega.shape)
    
    for ivect in range(0,nvec):
        w.set_local(Omega[:,ivect])
        A.mult(w,y)
        Y[:,ivect] = y.array()
                
    Q,_ = np.linalg.qr(Y)
    
    AQ = np.zeros(Omega.shape)
    for ivect in range(0,nvec):
        w.set_local(Q[:,ivect])
        A.mult(w,y)
        AQ[:,ivect] = y.array()
                
    T = np.dot(Q.T, AQ)
        
    d, V = np.linalg.eigh(T)
    sort_perm = d.argsort()
        
    sort_perm = sort_perm[::-1]
    d = d[sort_perm[0:k]]
    V = V[:, sort_perm[0:k]] 
        
    U = np.dot(Q,V)
        
    return d, U
Exemple #17
0
 def __init__(self, prior, d, U):
     self.prior = prior
     ones = np.ones(d.shape, dtype=d.dtype)
     self.d = ones - np.power(ones + d, -.5)
     self.lrsqrt = LowRankOperator(self.d, U)
     self.help = Vector()
     self.init_vector(self.help, 0)
Exemple #18
0
class Solver2Operator:
    def __init__(self, S, mpi_comm=mpi_comm_world(), init_vector=None):
        self.S = S
        self.tmp = Vector(mpi_comm)
        self.my_init_vector = init_vector

        if self.my_init_vector is None:
            if hasattr(self.S, "init_vector"):
                self.my_init_vector = self.S.init_vector
            elif hasattr(self.S, "operator"):
                self.my_init_vector = self.S.operator().init_vector
            elif hasattr(self.S, "get_operator"):
                self.my_init_vector = self.S.get_operator().init_vector

    def init_vector(self, x, dim):
        if self.my_init_vector:
            self.my_init_vector(x, dim)
        else:
            raise NotImplementedError("Solver2Operator.init_vector")

    def mult(self, x, y):
        self.S.solve(y, x)

    def inner(self, x, y):
        self.S.solve(self.tmp, y)
        return self.tmp.inner(x)
Exemple #19
0
    def __init__(self, form, Space, bcs=[],
                 name="x",
                 matvec=[None, None],
                 method="default",
                 solver_type="cg",
                 preconditioner_type="default"):

        Function.__init__(self, Space, name=name)
        self.form = form
        self.method = method
        self.bcs = bcs
        self.matvec = matvec
        self.trial = trial = TrialFunction(Space)
        self.test = test = TestFunction(Space)
        Mass = inner(trial, test) * dx()
        self.bf = inner(form, test) * dx()
        self.rhs = Vector(self.vector())

        if method.lower() == "default":
            self.A = A_cache[(Mass, tuple(bcs))]
            self.sol = Solver_cache[(Mass, tuple(
                bcs), solver_type, preconditioner_type)]

        elif method.lower() == "lumping":
            assert Space.ufl_element().degree() < 2
            self.A = A_cache[(Mass, tuple(bcs))]
            ones = Function(Space)
            ones.vector()[:] = 1.
            self.ML = self.A * ones.vector()
            self.ML.set_local(1. / self.ML.array())
Exemple #20
0
class LowRankHessian:
    """
    Operator that represents the action of the low rank approximation
    of the Hessian and of its inverse.
    """
    def __init__(self, prior, d, U):
        self.prior = prior
        self.LowRankH = LowRankOperator(d, U)
        dsolve = d / (np.ones(d.shape, dtype=d.dtype) + d)
        self.LowRankHinv = LowRankOperator(dsolve, U)
        self.help = Vector(U[0].mpi_comm())
        self.init_vector(self.help, 0)
        self.help1 = Vector(U[0].mpi_comm())
        self.init_vector(self.help1, 0)
        
    def init_vector(self,x, dim):
        self.prior.init_vector(x,dim)
    
    def inner(self,x,y):
        Hx = Vector(self.help.mpi_comm())
        self.init_vector(Hx, 0)
        self.mult(x, Hx)
        return Hx.inner(y)
        
    def mult(self, x, y):
        self.prior.R.mult(x,y)
        self.LowRankH.mult(y, self.help)
        self.prior.R.mult(self.help,self.help1)
        y.axpy(1, self.help1)
        
        
    def solve(self, sol, rhs):
        self.prior.Rsolver.solve(sol, rhs)
        self.LowRankHinv.mult(rhs, self.help)
        sol.axpy(-1, self.help)
Exemple #21
0
 def __init__(self, form, Space, bcs=[], 
              name="x", 
              matvec=[None, None], 
              method="default", 
              solver_type="cg", 
              preconditioner_type="default"):
     
     Function.__init__(self, Space, name=name)
     self.form = form
     self.method = method
     self.bcs = bcs
     self.matvec = matvec
     self.trial = trial = TrialFunction(Space)
     self.test = test = TestFunction(Space)
     Mass = inner(trial, test)*dx()
     self.bf = inner(form, test)*dx()
     self.rhs = Vector(self.vector())
     
     if method.lower() == "default":
         self.A = A_cache[(Mass, tuple(bcs))]
         self.sol = KrylovSolver(solver_type, preconditioner_type)
         self.sol.parameters["preconditioner"]["structure"] = "same"
         self.sol.parameters["error_on_nonconvergence"] = False
         self.sol.parameters["monitor_convergence"] = False
         self.sol.parameters["report"] = False
             
     elif method.lower() == "lumping":
         assert Space.ufl_element().degree() < 2
         self.A = A_cache[(Mass, tuple(bcs))]
         ones = Function(Space)
         ones.vector()[:] = 1.
         self.ML = self.A * ones.vector()
         self.ML.set_local(1. / self.ML.array())
Exemple #22
0
class LowRankHessian:
    """
    Operator that represents the action of the low rank approximation
    of the Hessian and of its inverse.
    """
    def __init__(self, prior, d, U):
        self.prior = prior
        self.LowRankH = LowRankOperator(d, U)
        dsolve = d / (np.ones(d.shape, dtype=d.dtype) + d)
        self.LowRankHinv = LowRankOperator(dsolve, U)
        self.help = Vector(U[0].mpi_comm())
        self.init_vector(self.help, 0)
        self.help1 = Vector(U[0].mpi_comm())
        self.init_vector(self.help1, 0)

    def init_vector(self, x, dim):
        self.prior.init_vector(x, dim)

    def inner(self, x, y):
        Hx = Vector(self.help.mpi_comm())
        self.init_vector(Hx, 0)
        self.mult(x, Hx)
        return Hx.inner(y)

    def mult(self, x, y):
        self.prior.R.mult(x, y)
        self.LowRankH.mult(y, self.help)
        self.prior.R.mult(self.help, self.help1)
        y.axpy(1, self.help1)

    def solve(self, sol, rhs):
        self.prior.Rsolver.solve(sol, rhs)
        self.LowRankHinv.mult(rhs, self.help)
        sol.axpy(-1, self.help)
Exemple #23
0
def les_setup(u_, mesh, KineticEnergySGS, assemble_matrix, CG1Function,
              nut_krylov_solver, bcs, **NS_namespace):
    """
    Set up for solving the Kinetic Energy SGS-model.
    """
    DG = FunctionSpace(mesh, "DG", 0)
    CG1 = FunctionSpace(mesh, "CG", 1)
    dim = mesh.geometry().dim()
    delta = Function(DG)
    delta.vector().zero()
    delta.vector().axpy(1.0, assemble(TestFunction(DG) * dx))
    delta.vector().set_local(delta.vector().array()**(1. / dim))
    delta.vector().apply('insert')

    Ck = KineticEnergySGS["Ck"]
    ksgs = interpolate(Constant(1E-7), CG1)
    bc_ksgs = DirichletBC(CG1, 0, "on_boundary")
    A_mass = assemble_matrix(TrialFunction(CG1) * TestFunction(CG1) * dx)
    nut_form = Ck * delta * sqrt(ksgs)
    bcs_nut = derived_bcs(CG1, bcs['u0'], u_)
    nut_ = CG1Function(nut_form,
                       mesh,
                       method=nut_krylov_solver,
                       bcs=bcs_nut,
                       bounded=True,
                       name="nut")
    At = Matrix()
    bt = Vector(nut_.vector())
    ksgs_sol = KrylovSolver("bicgstab", "additive_schwarz")
    #ksgs_sol.parameters["preconditioner"]["structure"] = "same_nonzero_pattern"
    ksgs_sol.parameters["error_on_nonconvergence"] = False
    ksgs_sol.parameters["monitor_convergence"] = False
    ksgs_sol.parameters["report"] = False
    del NS_namespace
    return locals()
Exemple #24
0
class Solver2Operator:
    def __init__(self,S,mpi_comm=mpi_comm_world(), init_vector = None):
        self.S = S
        self.tmp = Vector(mpi_comm)
        self.my_init_vector = init_vector
        
        if self.my_init_vector is None:
            if hasattr(self.S, "init_vector"):
                self.my_init_vector = self.S.init_vector
            elif hasattr(self.S, "operator"):
                self.my_init_vector = self.S.operator().init_vector
            elif hasattr(self.S, "get_operator"):
                self.my_init_vector = self.S.get_operator().init_vector
        
    def init_vector(self, x, dim):
        if self.my_init_vector:
            self.my_init_vector(x,dim)
        else:
            raise NotImplementedError("Solver2Operator.init_vector")
        
        
    def mult(self,x,y):
        self.S.solve(y,x)
        
    def inner(self, x, y):
        self.S.solve(self.tmp,y)
        return self.tmp.inner(x)
Exemple #25
0
    def build_pressure_null_space(self):
        # Prepare function used to correct pressure values
        W_ns = self.function_spaces()[1]
        # NOTE: The following works only for nodal elements
        # null_fcn = Function(W_ns)
        # W_ns.sub(1).dofmap().set(null_fcn.vector(), 1.0)
        null_fcn = self._get_constant_pressure(W_ns)

        # Create vector that spans the null space and normalize
        null_vec = Vector(null_fcn.vector())
        null_vec *= 1.0 / null_vec.norm("l2")
        # FIXME: Check what are relevant norms for different Krylov methods

        # Create null space basis object
        null_space = VectorSpaceBasis([null_vec])

        return (null_space, null_fcn)
Exemple #26
0
 def __init__(self, prior, d, U):
     self.prior = prior
     self.LowRankH = LowRankOperator(d, U)
     dsolve = d / (np.ones(d.shape, dtype=d.dtype) + d)
     self.LowRankHinv = LowRankOperator(dsolve, U)
     self.help = Vector(U[0].mpi_comm())
     self.init_vector(self.help, 0)
     self.help1 = Vector(U[0].mpi_comm())
     self.init_vector(self.help1, 0)
Exemple #27
0
 def apply_sqrtM(self, vect):
     """Compute M^{1/2}.vect from Vector() vect"""
     sqrtMv = Function(self.Vm)
     for ii in range(self.Vm.dim()):
         r, c, rx, cx = self.eigsolM.get_eigenpair(ii)
         RX = Vector(rx)
         sqrtMv.vector().axpy(
             np.sqrt(r) * np.dot(rx.array(), vect.array()), RX)
     return sqrtMv.vector()
def trace(A):
    """
    Compute the trace of a sparse matrix A.
    """
    v = Vector()
    A.init_vector(v)
    mpi_comm = v.mpi_comm()
    nprocs = MPI.size(mpi_comm)

    if nprocs > 1:
        raise Exception("trace is only serial")

    n = A.size(0)
    tr = 0.
    for i in range(0, n):
        [j, val] = A.getrow(i)
        tr += val[j == i]
    return tr
    def __init__(self):
        self.parameters = {}
        self.parameters["rel_tolerance"] = 1e-9
        self.parameters["abs_tolerance"] = 1e-12
        self.parameters["max_iter"]      = 1000
        self.parameters["zero_initial_guess"] = True
        self.parameters["print_level"] = 0
        
        self.A = None
        self.B = None
        self.converged = False
        self.iter = 0
        self.reasonid = 0
        self.final_norm = 0
        
        self.r = Vector()
        self.z = Vector()
        self.d = Vector()

        if dolfin.__version__[2] == '5':    self.vrs150 = True
        else:   self.vrs150 = False
    def __init__(self, parameters=CGSolverSteihaug_ParameterList(),comm = mpi_comm_world()):
        
        self.parameters = parameters
        
        self.A = None
        self.B_solver = None
        self.B_op = None
        self.converged = False
        self.iter = 0
        self.reasonid = 0
        self.final_norm = 0

        self.TR_radius_2 = None

        self.update_x = self.update_x_without_TR
        
        self.r = Vector(comm)
        self.z = Vector(comm)
        self.Ad = Vector(comm)
        self.d = Vector(comm)
        self.Bx = Vector(comm)
Exemple #31
0
 def __init__(self,S,mpi_comm=mpi_comm_world(), init_vector = None):
     self.S = S
     self.tmp = Vector(mpi_comm)
     self.my_init_vector = init_vector
     
     if self.my_init_vector is None:
         if hasattr(self.S, "init_vector"):
             self.my_init_vector = self.S.init_vector
         elif hasattr(self.S, "operator"):
             self.my_init_vector = self.S.operator().init_vector
         elif hasattr(self.S, "get_operator"):
             self.my_init_vector = self.S.get_operator().init_vector
Exemple #32
0
def estimate_diagonal_inv2(Asolver, k, d):
    """
    An unbiased stochastic estimator for the diagonal of A^-1.
    d = [ \sum_{j=1}^k vj .* A^{-1} vj ] ./ [ \sum_{j=1}^k vj .* vj ]
    where
    - vj are i.i.d. ~ N(0, I)
    - .* and ./ represent the element-wise multiplication and division
      of vectors, respectively.
      
    REFERENCE:
    Costas Bekas, Effrosyni Kokiopoulou, and Yousef Saad,
    An estimator for the diagonal of a matrix,
    Applied Numerical Mathematics, 57 (2007), pp. 1214-1229.
    """
    x, b = Vector(), Vector()

    if hasattr(Asolver, "init_vector"):
        Asolver.init_vector(x, 1)
        Asolver.init_vector(b, 0)
    else:
        Asolver.get_operator().init_vector(x, 1)
        Asolver.get_operator().init_vector(b, 0)

    num = np.zeros(b.array().shape, dtype=b.array().dtype)
    den = np.zeros(num.shape, dtype=num.dtype)
    for i in range(k):
        x.zero()
        b.set_local(np.random.randn(num.shape[0]))
        Asolver.solve(x, b)
        num = num + (x.array() * b.array())
        den = den + (b.array() * b.array())

    d.set_local(num / den)
Exemple #33
0
    def set_operator(self, A):
        """
        Set the operator :math:`A`.
        """
        self.r = Vector()
        self.z = Vector()
        self.Ad = Vector()
        self.d = Vector()

        self.A = A
        self.A.init_vector(self.r, 0)
        self.A.init_vector(self.z, 0)
        self.A.init_vector(self.d, 0)
        self.A.init_vector(self.Ad, 0)
Exemple #34
0
    def update_x_with_TR(self,x,alpha,d):
        x_bk = x.copy()
        x.axpy(alpha,d)
        self.Bx.zero()
        self.B_op.mult(x, self.Bx)
        x_Bnorm2 = self.Bx.inner(x)

        if x_Bnorm2 < self.TR_radius_2:
            return  False
        else:
            # Move point to boundary of trust region
            self.Bx.zero()
            self.B_op.mult(x_bk, self.Bx)
            x_Bnorm2 = self.Bx.inner(x_bk)
            Bd = Vector()
            self.B_op.init_vector(Bd,0)
            Bd.zero()
            self.B_op.mult(self.d,Bd)
            d_Bnorm2 = Bd.inner(d)
            d_Bx = Bd.inner(x_bk)
            a_tau = alpha*alpha*d_Bnorm2
            b_tau_half = alpha* d_Bx
            c_tau = x_Bnorm2- self.TR_radius_2
            # Solve quadratic for tau
            tau = (-b_tau_half + math.sqrt(b_tau_half*b_tau_half - a_tau*c_tau))/a_tau
            x.zero()
            x.axpy(1,x_bk)
            x.axpy(tau*alpha, d)

            return  True
Exemple #35
0
 def __init__(self):
     """
     Construct the solver with default parameters
     :code:`tolerance = 1e-4`
     
     :code:`print_level = 0`
     
     :code:`verbose = 0`
     """
     self.parameters = {}
     self.parameters["tolerance"] = 1e-4
     self.parameters["print_level"] = 0
     self.parameters["verbose"] = 0
     
     self.A = None
     self.converged = False
     self.iter = 0
     
     self.b = Vector()
     self.r = Vector()
     self.p = Vector()
     self.Ap = Vector()
Exemple #36
0
 def pointwise_variance(self, method="Exact", path_len=8):
     """
     Compute/Estimate the pointwise variance of the posterior, prior distribution
     and the pointwise variance reduction informed by the data.
     
     See _Prior.pointwise_variance for more details. 
     """
     pr_pointwise_variance = self.prior.pointwise_variance(method, path_len)
     correction_pointwise_variance = Vector()
     self.init_vector(correction_pointwise_variance, 0)
     self.Hlr.LowRankHinv.get_diagonal(correction_pointwise_variance)
     post_pointwise_variance = pr_pointwise_variance - correction_pointwise_variance
     return post_pointwise_variance, pr_pointwise_variance, correction_pointwise_variance
Exemple #37
0
 def pointwise_variance(self, **kwargs):
     """
     Compute/estimate the pointwise variance of the posterior, prior distribution
     and the pointwise variance reduction informed by the data.
     
     See :code:`_Prior.pointwise_variance` for more details. 
     """
     pr_pointwise_variance = self.prior.pointwise_variance(**kwargs)
     correction_pointwise_variance = Vector(self.prior.R.mpi_comm())
     self.init_vector(correction_pointwise_variance, 0)
     self.Hlr.LowRankHinv.get_diagonal(correction_pointwise_variance)
     post_pointwise_variance = pr_pointwise_variance - correction_pointwise_variance
     return post_pointwise_variance, pr_pointwise_variance, correction_pointwise_variance
Exemple #38
0
    def __init__(self, times, tol=1e-10):
        """
        Constructor:
        - times: time frame at which snapshots are stored
        - tol  : tolerance to identify the frame of the
                 snapshot.
        """
        self.nsteps = len(times)
        self.data = []

        for i in range(self.nsteps):
            self.data.append(Vector())

        self.times = times
        self.tol = tol
Exemple #39
0
    def __init__(self, times, tol=1e-10, mpi_comm = mpi_comm_world()):
        """
        Constructor:

        - :code:`times`: time frame at which snapshots are stored.
        - :code:`tol`  : tolerance to identify the frame of the snapshot.
        """
        self.nsteps = len(times)
        self.data = [];
        
        for i in range(self.nsteps):
            self.data.append( Vector(mpi_comm) )
             
        self.times = times
        self.tol = tol
Exemple #40
0
class Operator2Solver:
    def __init__(self,op, mpi_comm=mpi_comm_world()):
        self.op = op
        self.tmp = Vector(mpi_comm)
        
    def init_vector(self, x, dim):
        if hasattr(self.op, "init_vector"):
            self.op.init_vector(x,dim)
        else:
            raise
        
    def solve(self,y,x):
        self.op.mult(x,y)
        
    def inner(self, x, y):
        self.op.mult(y,self.tmp)
        return self.tmp.inner(x)
Exemple #41
0
def get_diagonal(A, d):
    """
    Compute the diagonal of the square operator :math:`A`.
    Use :code:`Solver2Operator` if :math:`A^{-1}` is needed.
    """
    ej, xj = Vector(d.mpi_comm()), Vector(d.mpi_comm())
    A.init_vector(ej,1)
    A.init_vector(xj,0)
                    
    g_size = ej.size()    
    d.zero()
    for gid in range(g_size):
        owns_gid = ej.owns_index(gid)
        if owns_gid:
            SetToOwnedGid(ej, gid, 1.)
        ej.apply("insert")
        A.mult(ej,xj)
        if owns_gid:
            val = GetFromOwnedGid(xj, gid)
            SetToOwnedGid(d, gid, val)
            SetToOwnedGid(ej, gid, 0.)
        ej.apply("insert")
        
    d.apply("insert")
    def solve(self, F, u, grad = None, H = None):
        
        if grad is None:
            print "Using Automatic Differentiation to compute the gradient"
            grad = derivative(F,u)
            
        if H is None:
            print "Using Automatic Differentiation to compute the Hessian"
            H = derivative(grad, u)
        
        rtol = self.parameters["rel_tolerance"]
        atol = self.parameters["abs_tolerance"]
        gdu_tol = self.parameters["gdu_tolerance"]
        max_iter = self.parameters["max_iter"]
        c_armijo = self.parameters["c_armijo"] 
        max_backtrack = self.parameters["max_backtracking_iter"]
        prt_level =  self.parameters["print_level"]
        cg_coarsest_tol = self.parameters["cg_coarse_tolerance"]
        
        Fn = assemble(F)
        gn = assemble(grad)
        g0_norm = gn.norm("l2")
        gn_norm = g0_norm
        tol = max(g0_norm*rtol, atol)
        du = Vector()
        
        self.converged = False
        self.reason = 0
        
        if prt_level > 0:
            print "{0:3} {1:15} {2:15} {3:15} {4:15} {5:15} {6:5}".format(
                "It", "Energy", "||g||", "(g,du)", "alpha", "tol_cg", "cg_it")
        
        for self.it in range(max_iter):
            Hn = assemble(H)
            
            Hn.init_vector(du,1)
            solver = PETScKrylovSolver("cg", "petsc_amg")
            solver.set_operator(Hn)
            solver.parameters["nonzero_initial_guess"] = False
            cg_tol = min(cg_coarsest_tol, math.sqrt( gn_norm/g0_norm) )
            solver.parameters["relative_tolerance"] = cg_tol
            lin_it = solver.solve(du,gn)
            
            self.total_cg_iter += lin_it
            

            du_gn = -du.inner(gn)
            
            if(-du_gn < gdu_tol):
                self.converged=True
                self.reason = 3
                break
             
            u_backtrack = u.copy(deepcopy=True)
            alpha = 1.   
            bk_converged = False
            
            #Backtrack
            for j in range(max_backtrack):
                u.assign(u_backtrack)
                u.vector().axpy(-alpha, du)
                Fnext = assemble(F)
                if Fnext < Fn + alpha*c_armijo*du_gn:
                    Fn = Fnext
                    bk_converged = True
                    break
                
                alpha = alpha/2.
                
            if not bk_converged:
                self.reason = 2
                break
                   
            gn = assemble(grad)
            gn_norm = gn.norm("l2")
            
            if prt_level > 0:
                print "{0:3d} {1:15f} {2:15f} {3:15f} {4:15f} {5:15f} {6:5d}".format(
                        self.it, Fn, gn_norm, du_gn, alpha, cg_tol, lin_it)
                
            if gn_norm < tol:
                self.converged = True
                self.reason = 1
                break
            
        self.final_grad_norm = gn_norm
        
        if prt_level > -1:
            print self.termination_reasons[self.reason]
            if self.converged:
                print "Inexact Newton CG converged in ", self.it, \
                "nonlinear iterations and ", self.total_cg_iter, "linear iterations."
            else:
                print "Inexact Newton CG did NOT converge after ", self.it, \
                "nonlinear iterations and ", self.total_cg_iter, "linear iterations."
            print "Final norm of the gradient", self.final_grad_norm
            print "Value of the cost functional", Fn
Exemple #43
0
 def __init__(self,op, mpi_comm=mpi_comm_world()):
     self.op = op
     self.tmp = Vector(mpi_comm)
Exemple #44
0
def to_dense(A, mpi_comm = mpi_comm_world() ):
    """
    Convert a sparse matrix A to dense.
    For debugging only.
    """
    v = Vector(mpi_comm)
    A.init_vector(v)
    nprocs = MPI.size(mpi_comm)
    
    if nprocs > 1:
        raise Exception("to_dense is only serial")
    
    if hasattr(A, "getrow"):
        n  = A.size(0)
        m  = A.size(1)
        B = np.zeros( (n,m), dtype=np.float64)
        for i in range(0,n):
            [j, val] = A.getrow(i)
            B[i,j] = val
        
        return B
    else:
        x = Vector(mpi_comm)
        Ax = Vector(mpi_comm)
        A.init_vector(x,1)
        A.init_vector(Ax,0)
        
        n = Ax.get_local().shape[0]
        m = x.get_local().shape[0]
        B = np.zeros( (n,m), dtype=np.float64) 
        for i in range(0,m):
            i_ind = np.array([i], dtype=np.intc)
            x.set_local(np.ones(i_ind.shape), i_ind)
            x.apply("sum_values")
            A.mult(x,Ax)
            B[:,i] = Ax.get_local()
            x.set_local(np.zeros(i_ind.shape), i_ind)
            x.apply("sum_values")
            
        return B
Exemple #45
0
class OasisFunction(Function):
    """Function with more or less efficient projection methods
    of associated linear form.

    The matvec option is provided for letting the right hand side
    be computed through a fast matrix vector product. Both the matrix
    and the Coefficient of the required vector must be provided.

      method = "default"
        Solve projection with regular linear algebra using solver_type
        and preconditioner_type

      method = "lumping"
        Solve through lumping of mass matrix

    """

    def __init__(self, form, Space, bcs=[],
                 name="x",
                 matvec=[None, None],
                 method="default",
                 solver_type="cg",
                 preconditioner_type="default"):

        Function.__init__(self, Space, name=name)
        self.form = form
        self.method = method
        self.bcs = bcs
        self.matvec = matvec
        self.trial = trial = TrialFunction(Space)
        self.test = test = TestFunction(Space)
        Mass = inner(trial, test) * dx()
        self.bf = inner(form, test) * dx()
        self.rhs = Vector(self.vector())

        if method.lower() == "default":
            self.A = A_cache[(Mass, tuple(bcs))]
            self.sol = Solver_cache[(Mass, tuple(
                bcs), solver_type, preconditioner_type)]

        elif method.lower() == "lumping":
            assert Space.ufl_element().degree() < 2
            self.A = A_cache[(Mass, tuple(bcs))]
            ones = Function(Space)
            ones.vector()[:] = 1.
            self.ML = self.A * ones.vector()
            self.ML.set_local(1. / self.ML.array())

    def assemble_rhs(self):
        """
        Assemble right hand side (form*test*dx) in projection
        """
        if not self.matvec[0] is None:
            mat, func = self.matvec
            self.rhs.zero()
            self.rhs.axpy(1.0, mat * func.vector())

        else:
            assemble(self.bf, tensor=self.rhs)

    def __call__(self, assemb_rhs=True):
        """
        Compute the projection
        """
        timer = Timer("Projecting {}".format(self.name()))

        if assemb_rhs:
            self.assemble_rhs()

        for bc in self.bcs:
            bc.apply(self.rhs)

        if self.method.lower() == "default":
            self.sol.solve(self.A, self.vector(), self.rhs)

        else:
            self.vector().zero()
            self.vector().axpy(1.0, self.rhs * self.ML)
Exemple #46
0
 def inner(self,x,y):
     Hx = Vector(self.help.mpi_comm())
     self.init_vector(Hx, 0)
     self.mult(x, Hx)
     return Hx.inner(y)
Exemple #47
0
class CGSampler:
    """ 
    This class implements the CG sampler algorithm to generate samples from :math:`\mathcal{N}(0, A^{-1})`.

    Reference:
        `Albert Parker and Colin Fox Sampling Gaussian Distributions in Krylov Spaces with Conjugate Gradient
        SIAM J SCI COMPUT, Vol 34, No. 3 pp. B312-B334`
    """

    def __init__(self):
        """
        Construct the solver with default parameters
        :code:`tolerance = 1e-4`
        
        :code:`print_level = 0`
        
        :code:`verbose = 0`
        """
        self.parameters = {}
        self.parameters["tolerance"] = 1e-4
        self.parameters["print_level"] = 0
        self.parameters["verbose"] = 0
        
        self.A = None
        self.converged = False
        self.iter = 0
        
        self.b = Vector()
        self.r = Vector()
        self.p = Vector()
        self.Ap = Vector()
                
    def set_operator(self, A):
        """
        Set the operator :code:`A`, such that :math:`x \sim \mathcal{N}(0, A^{-1})`.
        
        .. note:: :code:`A` is any object that provides the methods :code:`init_vector()` and :code:`mult()`
        
        """
        self.A = A
        self.A.init_vector(self.r,0)
        self.A.init_vector(self.p,0)
        self.A.init_vector(self.Ap,0)
        
        self.A.init_vector(self.b,0)
        parRandom.normal(1., self.b)
                        
    def sample(self, noise, s):
        """
        Generate a sample :math:`s ~ N(0, A^{-1})`.
        
        :code:`noise` is a :code:`numpy.array` of i.i.d. normal variables used as input.
        For a fixed realization of noise the algorithm is fully deterministic.
        The size of noise determine the maximum number of CG iterations.
        """
        s.zero()
        
        self.iter = 0
        self.converged = False
        
        # r0 = b
        self.r.zero()
        self.r.axpy(1., self.b)
        
        #p0 = r0
        self.p.zero()
        self.p.axpy(1., self.r)
        
        self.A.mult(self.p, self.Ap)
        
        d = self.p.inner(self.Ap)
        
        tol2 = self.parameters["tolerance"]*self.parameters["tolerance"]
        
        rnorm2_old = self.r.inner(self.r)
        
        if self.parameters["verbose"] > 0:
            print("initial residual = {0:g}".format( math.sqrt(rnorm2_old) ))
        
        while (not self.converged) and (self.iter < noise.shape[0]):
            gamma = rnorm2_old/d
            s.axpy(noise[self.iter]/math.sqrt(d), self.p)
            self.r.axpy(-gamma, self.Ap)
            rnorm2 = self.r.inner(self.r)
            beta = rnorm2/rnorm2_old
            # p_new = r + beta p
            self.p *= beta
            self.p.axpy(1., self.r)
            self.A.mult(self.p, self.Ap)
            d = self.p.inner(self.Ap)
            rnorm2_old = rnorm2
            
            if rnorm2 < tol2:
                self.converged = True
            else:
                rnorm2_old = rnorm2
                self.iter = self.iter+1
         
        if self.parameters["verbose"] > 0:       
            print("Final residual {0} after {1} iterations".format( math.sqrt(rnorm2_old), self.iter))
class CGSolverSteihaug:
    """
    Solve the linear system A x = b using preconditioned conjugate gradient ( B preconditioner)
    and the Steihaug stopping criterion:
    - reason of termination 0: we reached the maximum number of iterations (no convergence)
    - reason of termination 1: we reduced the residual up to the given tolerance (convergence)
    - reason of termination 2: we reached a negative direction (premature termination due to not spd matrix)
    
    The operator A is set using the method set_operator(A).
    A must provide the following two methods:
    - A.mult(x,y): y = A*x
    - A.init_vector(x, dim): initialize the vector x so that it is compatible with the range (dim = 0) or
      the domain (dim = 1) of A.
      
    The preconditioner B is set using the method set_preconditioner(B).
    B must provide the following method:
    - B.solve(z,r): z is the action of the preconditioner B on the vector r
    
    To solve the linear system A*x = b call solve(x,b). Here x and b are assumed
    to be FEniCS::Vector objects
    
    Maximum number of iterations, tolerances, verbosity level etc can be
    set using the parameters attributes.
    """
    reason = ["Maximum Number of Iterations Reached",
              "Relative/Absolute residual less than tol",
              "Reached a negative direction"
              ]
    def __init__(self):
        self.parameters = {}
        self.parameters["rel_tolerance"] = 1e-9
        self.parameters["abs_tolerance"] = 1e-12
        self.parameters["max_iter"]      = 1000
        self.parameters["zero_initial_guess"] = True
        self.parameters["print_level"] = 0
        
        self.A = None
        self.B = None
        self.converged = False
        self.iter = 0
        self.reasonid = 0
        self.final_norm = 0
        
        self.r = Vector()
        self.z = Vector()
        self.d = Vector()

        if dolfin.__version__[2] == '5':    self.vrs150 = True
        else:   self.vrs150 = False
                
    def set_operator(self, A):
        self.A = A
        if self.vrs150:
            self.A.init_vector(self.r,0)
            self.A.init_vector(self.z,0)
            self.A.init_vector(self.d,0)
        else:
            self.r = self.A.init_vector130()
            self.z = self.A.init_vector130()
            self.d = self.A.init_vector130()
        
    def set_preconditioner(self, B):
        self.B = B
        
    def solve(self,x,b):
        
        self.iter = 0
        self.converged = False
        self.reasonid  = 0
        
        betanom = 0.0
        alpha = 0.0 
        beta = 0.0
                
        if self.parameters["zero_initial_guess"]:
            self.r.zero()
            self.r.axpy(1.0, b)
            x.zero()
        else:
            self.A.mult(x,self.r)
            self.r *= -1.0
            self.r.axpy(1.0, b)
        
        self.z.zero()
        self.B.solve(self.z,self.r) #z = B^-1 r  
              
        self.d.zero()
        self.d.axpy(1.,self.z); #d = z
        
        nom0 = self.d.inner(self.r)
        nom = nom0
        
        if self.parameters["print_level"] == 1:
            print " Iterartion : ", 0, " (B r, r) = ", nom
            
        rtol2 = nom * self.parameters["rel_tolerance"] * self.parameters["rel_tolerance"]
        atol2 = self.parameters["abs_tolerance"] * self.parameters["abs_tolerance"]
        r0 = max(rtol2, atol2)
        
        if nom <= r0:
            self.converged  = True
            self.reasonid   = 1
            self.final_norm = math.sqrt(nom)
            if(self.parameters["print_level"] >= 0):
                print self.reason[self.reasonid]
                print "Converged in ", self.iter, " iterations with final norm ", self.final_norm
            return
        
        self.A.mult(self.d, self.z)  #z = A d
        den = self.z.inner(self.d)
        
        if den <= 0.0:
            self.converged = True
            self.reasonid = 2
            self.final_norm = math.sqrt(nom)
            if(self.parameters["print_level"] >= 0):
                print self.reason[self.reasonid]
                print "Converged in ", self.iter, " iterations with final norm ", self.final_norm
            return
        
        # start iteration
        self.iter = 1
        while True:
            alpha = nom/den
            x.axpy(alpha,self.d)        # x = x + alpha d
            self.r.axpy(-alpha, self.z) # r = r - alpha A d
            
            self.B.solve(self.z, self.r)     # z = B^-1 r
            betanom = self.r.inner(self.z)
            
            if self.parameters["print_level"] == 1:
                print " Iteration : ", self.iter, " (B r, r) = ", betanom
                
            if betanom < r0:
                self.converged = True
                self.reasonid = 1
                self.final_norm = math.sqrt(betanom)
                if(self.parameters["print_level"] >= 0):
                    print self.reason[self.reasonid]
                    print "Converged in ", self.iter, " iterations with final norm ", self.final_norm
                break
            
            self.iter += 1
            if self.iter > self.parameters["max_iter"]:
                self.converged = False
                self.reasonid = 0
                self.final_norm = math.sqrt(betanom)
                if(self.parameters["print_level"] >= 0):
                    print self.reason[self.reasonid]
                    print "Not Converged. Final residual norm ", self.final_norm
                break
            
            beta = betanom/nom
            self.d *= beta
            self.d.axpy(1., self.z)  #d = z + beta d
            
            self.A.mult(self.d,self.z)   # z = A d
            
            den = self.d.inner(self.z)
            
            if den <= 0.0:
                self.converged = True
                self.reasonid = 2
                self.final_norm = math.sqrt(nom)
                if(self.parameters["print_level"] >= 0):
                    print self.reason[self.reasonid]
                    print "Converged in ", self.iter, " iterations with final norm ", self.final_norm
                break
            
            nom = betanom