예제 #1
0
def BuildFilteredMatrix(A, neighborhoods, tol):
    tab=Tab()
    print('{}in BuildFilteredMatrix()'.format(tab))
    timer = Timer('BuildFilteredMatrix')
    timer.start()
    # Expects A as csr
    Af = A.copy()
    for i in range(A.shape[0]):
        N = neighborhoods[i]

        start = Af.indptr[i]
        end = Af.indptr[i+1]

        for k in range(start, end):
            j = Af.indices[k]
            if i==j:
                iPtr = k
                break

        for k in range(start, end):
            j = Af.indices[k]
            if j not in N:
                Af.data[iPtr] -= Af.data[k]
                Af.data[k]=0

    timer.stop()
    return Af
예제 #2
0
 def makeProlongator(self, lev):
     '''Make the prologator to go from level k to k+1.'''
     tab = Tab()
     print('{}making prolongator from level {} to {}'.format(tab,lev,lev+1))
     (I_up, aggregates) = SA_coarsen(
                     self.matrix(lev+1), tol=self.tol, lvl=lev+1
                     )
     return I_up
예제 #3
0
 def reportFailure(self, iter, normR, normB):
     '''If control.showFinal==True, print a message upon failure to converge.'''
     tab = Tab()
     if self._control.showFinal:
         normRel = normR
         if normR != 0:
             normRel = normR / normB
         print('%s%s solve FAILED: iters=%7d, ||r||/r0=%12.5g' %
               (tab, self.name(), iter, normR / normB))
예제 #4
0
 def reportSuccess(self, iter, normR, normB):
     '''If control.showFinal==True, print a message upon convergence.'''
     tab = Tab()
     if self._control.showFinal:
         normRel = normR
         if normR != 0:
             normRel = normR / normB
         print('%s%s solve succeeded: iters=%7d, ||r||/r0=%12.5g' %
               (tab, self.name(), iter, normRel))
예제 #5
0
 def reportIter(self, iter, normR, normR0):
     '''
     If control.showIters==True, print information about the current iteration
     at intervals specified by the control.interval parameter. Otherwise,
     do nothing.
     '''
     tab = Tab()
     if self._control.showIters and (iter % self._control.interval) == 0:
         print('%s%s iter=%7d ||r||=%12.5g ||r||/r0=%12.5g' %
               (tab, self.name(), iter, normR, normR / normR0))
예제 #6
0
def BuildTentativeProlongator(A, aggregates):
    tab=Tab()
    timer = Timer('BuildTentativeProlongator')
    timer.start()
    print('{}in BuildTentativeProlongator()'.format(tab))
    P = sp.dok_matrix((A.shape[0], len(aggregates)))
    for i in range(len(aggregates)):
        for j in aggregates[i]:
            P[j,i] = 1
    timer.stop()
    return P
예제 #7
0
def getNeighborhood(A, i, tol, a_diag):
    tab = Tab()
    #print('{}in getNeighborhood()'.format(tab))
    N = {i}
    a_ii = a_diag[i]
    start = A.indptr[i]
    end = A.indptr[i+1]

    for k in range(start, end):
        j = A.indices[k]
        a_ij = A.data[k]
        a_jj = a_diag[j]
        if abs(a_ij) >= tol*np.sqrt(a_ii*a_jj):
            N.add(j)
    return N
예제 #8
0
    def solve(self, A, b):
        tab = Tab()

        # Get size of matrix
        n, nc = A.shape
        # Make sure matrix is square
        assert (n == nc)
        # Make sure A and b are compatible
        assert (n == len(b))

        # Check for the trivial case b=0, x=0
        normB = self.norm(b)
        if normB == 0.0:
            return self.handleConvergence(0, np.zeros_like(b), 0, 0)

        # Create vectors for residual r and solution x
        r = np.copy(b)
        x = np.copy(b)

        if self._cycleMgr == None or not self.matrixFrozen():
            mlh = SmoothedAggregationMLHierarchy(A, numLevels=self.numLevels)

            self._cycleMgr = VCycleManager(mlh,
                                           nuPre=self.nuPre,
                                           nuPost=self.nuPost,
                                           smoother=self.smoother)

        # Main loop
        for k in range(self.maxiter()):
            # Run a V-cycle
            x = self._cycleMgr.runCycle(b, x)

            # Compute residual
            r = b - A * x

            # Check for convergence
            normR = self.norm(r)

            self.reportIter(k, normR, normB)
            if normR < self.tau() * normB:
                return self.handleConvergence(k, x, normR, normB)

        # If we're here, maxiter has been reached. This is normally a failure,
        # but may be acceptable if failOnMaxiter is set to false.
        return self.handleMaxiter(k, x, normR, normB)
예제 #9
0
    def search(self, x0, normF0, newtStep, func):
        tab = Tab()
        t = 1.0
        for k in range(self.maxsteps()):
            x_k = x0 + t * newtStep
            F_k = func.evalF(x_k)
            normF_k = self.norm(F_k)
            ratio = normF_k / normF0
            self.report(k, t, ratio)
            # Test for convergence of line search
            if normF_k <= (1.0 - self.alpha() * t) * normF0:
                return (True, x_k, F_k, normF_k)
            # Shrink step
            factor = 0.5 / ratio
            if factor < self.low():
                factor = self.low()
            t = t * factor

        # If here, the line step hasn't produced sufficient decrease.
        return (False, x_k, F_k, normF_k)
예제 #10
0
def SmoothProlongator(Phat, A, Af, omega=(2/3)):
    tab=Tab()
    print('{}in SmoothProlongator()'.format(tab))
    timer = Timer('SmoothProlongator')
    timer.start()
    smoothmat = omega*Af
    d_A = A.diagonal()
    for i in range(A.shape[0]):
        start = smoothmat.indptr[i]
        end = smoothmat.indptr[i+1]
        for k in range(start, end):
            j = smoothmat.indices[k]
            smoothmat.data[k] /= d_A[i]
            if i==j:
                smoothmat.data[k] = 1 - smoothmat.data[k]
            else:
                smoothmat.data[k] = -smoothmat.data[k]

    smoothed = smoothmat.dot(Phat)
    timer.stop()
    return smoothed
예제 #11
0
def SA_coarsen(A, tol=None, lvl=1):
    tab=Tab()
    print('{}in SA_coarsen()'.format(tab))
    # lvl will only be used if tol is None

    # If tol is None, use Vanek's suggestion
    if tol is None:
        tol = 0.08*(0.5)**(lvl-1)

    # Build the aggregates
    (aggregates, neighborhoods) = BuildAggregates(A, lvl=lvl)

    # Build the tentative prolongator from the aggregates, A needed for it's dimensions
    Phat = BuildTentativeProlongator(A, aggregates)

    # Build the filtered matrix for the smoother
    Af = BuildFilteredMatrix(A, neighborhoods, tol)

    # Smooth the Prolongation Operator with weighted Jacobi using the filtered matrix
    P = SmoothProlongator(Phat, A, Af)

    return (P.tocsr(), aggregates)
예제 #12
0
    def solve(self, A, b):
        '''
        Solve the system A*x=b for x.
        * Input:
            * A -- System matrix, can be a numpy 2D array or a scipy sparse matrix.
                 Must be SPD; this is not checked (doing so is too expensive).
            * b -- RHS vector, must be a numpy 1D array compatible with A.
        * Return:
            * A SolveStatus object containing the solution estimate, a
              success/failure flag, and convergence information.
        '''

        tab = Tab()

        # Get size of matrix
        n, nc = A.shape
        # Make sure matrix is square
        assert (n == nc)
        # Make sure A and b are compatible
        assert (n == len(b))

        # Check for the trivial case b=0, x=0
        normB = self.norm(b)
        if normB == 0.0:
            return self.handleConvergence(0, np.zeros_like(b), 0, 0)

        # Form the preconditioner
        print('prec frozen = ', self.precFrozen())
        if self.precond == None or not self.precFrozen():
            print('building prec')
            self.precond = self.precondType().form(A)

        # Initialize the step, residual, and solution vectors
        r = np.copy(b)
        p = self.precond.applyRight(r)
        u = np.copy(p)
        x = np.zeros_like(b)

        uDotR = np.dot(u, r)  # Should never be zero, since we've caught b=0
        # Check anyway
        if uDotR == 0.0:
            return self.handleBreakdown(0, 'breakdown dot(u,r)==0')

        # Preconditioned CG loop
        for k in range(self.maxiter()):
            # Compute A*p
            Ap = mvmult(A, p)

            pTAp = np.dot(p, Ap)
            if pTAp == 0.0:
                return self.handleBreakdown(k, 'breakdown dot(p, Ap)==0')

            # calculate step length
            alpha = uDotR / pTAp

            # Make step and compute updated residual
            x = x + alpha * p
            r = r - alpha * Ap
            u = self.precond.applyRight(r)

            normR = self.norm(r)
            self.reportIter(k, normR, normB)

            # Check for convergence
            if ((normR <= self.tau() * normB) or
                ((not self.failOnMaxiter()) and k == self.maxiter() - 1)):
                return self.handleConvergence(k, x, normR, normB)

            # Find next step direction
            newUDotR = np.dot(u, r)
            beta = newUDotR / uDotR
            uDotR = newUDotR

            p = u + beta * p

        # If we're here, maxiter has been reached. This is normally a failure,
        # but may be acceptable if failOnMaxiter is set to false.
        return self.handleMaxiter(k, x, normR, normB)
예제 #13
0
 def reportBreakdown(self, msg=''):
     '''If control.showFinal==True, print a message upon breakdown.'''
     tab = Tab()
     if self._control.showFinal:
         print('%s%s solve broke down: %s' % (tab, self.name(), msg))
예제 #14
0
def BuildAggregates(A, lvl=1, tol=None, phase=3):
    tab=Tab()
    tab1 = Tab()
    print('{}in BuildAggregates()'.format(tab))
    # If tol isn't specified, then use the default by Vanek
    if tol is None:
        tol = 0.08*(0.5)**(lvl-1)

    timer0 = Timer('BuildAggregates init step')
    timer0.start()
    # Initialization
    R = {i for i in range(A.shape[0])}
    a_diag = A.diagonal()
    neighborhoods = [getNeighborhood(A,i,tol,a_diag) for i in range(A.shape[0])]
    aggregates = []
    # isolated nodes aren't aggregated
    for n in neighborhoods:
        if len(n) == 1:
            aggregates.append(n)
            [elem] = n
            R.remove(elem)
    timer0.stop()

    timer1 = Timer('BuildAggregates phase 1')
    timer1.start()
    # Phase 1
    if phase > 0:
        for i in range(A.shape[0]):
            # If the neighborhood of i is completely in R, create an aggregate
            # from the neighborhood
            if i in R and neighborhoods[i].issubset(R):
                aggregates.append(neighborhoods[i])
                R -= neighborhoods[i]
    timer1.stop()

    timer2 = Timer('BuildAggregates phase 2')
    timer2.start()

    # Phase 2
    if phase > 1:
        # Copy the aggregates since we need to modify and check the
        # original aggregates
        timer_copy = Timer('agg copy')
        timer_copy.start()
        aggcopy = copy.deepcopy(aggregates)
        timer_copy.stop()
        # Loop through elements still in R
        for i in range(A.shape[0]):
            if i in R:
                # We need the strongest connection
                max_conn_strength = 0.0
                agg_idx_of_max = -1
                # Loop through all aggregates, looking to see if the current
                # neighborhood intersections
                for (j, agg) in enumerate(aggcopy):
                    #timer_disj = Timer('agg disjoint check')
                    #timer_disj.start()
                    isDisjoint_i_j = agg.isdisjoint(neighborhoods[i])
                    #timer_disj.stop()
                    if not isDisjoint_i_j:
                        #timer_loop = Timer('loop to find max strength')
                        #timer_loop.start()
                        for k in agg:
                            if abs(A[i,k]) > max_conn_strength:
                                max_conn_strength = abs(A[i,k])
                                agg_idx_of_max = j
                        #timer_loop.stop()
                timer_insert = Timer('agg insertion')
                timer_insert.start()
                aggregates[agg_idx_of_max].add(i)
                timer_insert.stop()

    timer2.stop()

    timer3 = Timer('BuildAggregates phase 2')
    timer3.start()

    # Phase 3
    if phase > 2 and not R:
        # Loop through elements still in R
        for i in range(A.shape[0]):
            if i in R:
                aggregates.append(R.intersection(neighborhoods[i]))
                R -= neighborhoods[i]
    timer3.stop()

    return (aggregates, neighborhoods)
예제 #15
0
    def solve(self, func, xInit):
        '''
        '''

        tab = Tab()
        xCur = xInit.copy()
        FCur = func.evalF(xCur)
        newtStep = np.ones_like(xCur)

        print('freeze prec for solver=', self.freezePrec)
        freeze = PreconditionerFreeze(self.solver, self.freezePrec)

        self.linesearch.setNorm(self.norm)

        # Initial residual; to be used for relative residual tests
        r0 = self.norm(FCur)
        normFCur = r0

        # Newton loop
        for i in range(self.maxiter()):

            # Report progress
            self.reportIter(i, normFCur, r0)

            # Check for convergence
            if normFCur <= r0 * self.tau() + self.tau():
                return self.handleConvergence(i, xCur, normFCur, r0)

            # Evaluate Jacobian
            J = func.evalJ(xCur)

            # Set tolerance to be used in linear solve
            if isinstance(self.solver, IterativeLinearSolver):
                if self.fixLinTol:  # Use fixed tolerance if desired (for testing)
                    tau_lin = self.minLinTol
                else:  # Adjust linear tol according to nonlinear residual.
                    # new linear tolerance is the larger of:
                    # (*) "fudge factor" times relative residual of nonlinear solve
                    # (*) a minimum linear tolerance.
                    # The minimum tolerance avoids pointlessly small tolerances
                    # for the linear solver
                    tau_lin = max(self.tolFudge * normFCur / r0,
                                  self.minLinTol)

                self.solver.setTolerance(tau_lin)

            # Solve for the Newton step
            tab.indent()
            status = self.solver.solve(J, -FCur)
            tab.unindent()

            if not status.success():
                return self.handleBreakdown(
                    i, 'solve for Newton step failed with msg={}'.format(
                        status.msg()))

            p = status.soln()

            # Do line search to find a step length giving sufficient decrease
            tab.indent()
            (success, xCur, FCur,
             normFCur) = self.linesearch.search(xCur, normFCur, p, func)
            tab.unindent()
            if not success:
                return self.handleBreakdown(i, msg='Line search failed')

        # End of Newton loop. At this point, xCur, FCur, and normFCur have been
        # updated to the new step.

        # If here, we've reached the maximum number of iterations without
        # convergence. Report failure to converge.

        return self.handleMaxiter(self.maxiter(), xCur, normFCur, r0)
예제 #16
0
 def report(self, k, t, ratio):
     tab = Tab()
     if self._report:
         print('%sk=%4d t=%12.5g ||F_k||/||F_0||=%12.5g' %
               (tab, k, t, ratio))