def extend_hierarchy(levels, CF, l, maxp, theta_a, keep): """Extend the multigrid hierarchy.""" def unpack_arg(v): if isinstance(v, tuple): return v[0], v[1] else: return v, {} A = levels[-1].A # Generate the C/F splitting fn, kwargs = unpack_arg(CF) if fn == 'CR': splitting = CR(A, **kwargs) else: raise ValueError('unknown C/F splitting method (%s)' % CF) # rs_C = classical_strength_of_connection(A, theta=0.25) # rs_splitting = split.RS(rs_C) # rs_P = direct_interpolation(A.copy(), rs_C.copy(), rs_splitting.copy()) # # rs_P_sparsity = rs_P.copy() # rs_P_sparsity.data[:] = 1 # # rs_fine = np.where(rs_splitting == 0)[0] # rs_coarse = np.where(rs_splitting == 1)[0] # rs_A_fc = A[rs_fine][:, rs_coarse] # rs_W = rs_P[rs_fine] # my_rs_P, my_rs_W = my_direct_interpolation(rs_A_fc, A, rs_W, rs_coarse, rs_fine) # # my_rs_P_sparsity = my_rs_P.copy() # my_rs_P_sparsity.data[:] = 1 # # rs_A_sparsity = A[:, rs_coarse].copy() # rs_A_sparsity.data[:] = 1 # Generate the interpolation matrix that maps from the coarse-grid to the # fine-grid P = truncation_interpolation(A, splitting, l, maxp, theta_a) # P = optimal_interpolation(A, splitting) # P = rs_P # Generate the restriction matrix that maps from the fine-grid to the # coarse-grid R = P.T.tocsr() # Store relevant information for this level if keep: levels[-1].splitting = splitting # C/F splitting levels[-1].P = P # prolongation operator levels[-1].R = R # restriction operator levels.append(multilevel_solver.level()) # Form next level through Galerkin product A = R * A * P levels[-1].A = A
def test_cr(self): A = self.cases[6] # 1d-tests, should be alternating aggregates # (n-1)/2 < = sum <= (n+1)/2. # Test auto thetacs and set thetacs values for i in range(3, 10): A = self.cases[i] h_split_auto = CR(A, method='habituated', thetacr=0.7, thetacs='auto') assert(h_split_auto.sum() <= (h_split_auto.shape[0]+1)/2) assert(h_split_auto.sum() >= (h_split_auto.shape[0]-1)/2) c_split_auto = CR(A, method='concurrent', thetacr=0.7, thetacs='auto') assert(c_split_auto.sum() <= (c_split_auto.shape[0]+1)/2) assert(c_split_auto.sum() >= (c_split_auto.shape[0]-1)/2) h_split = CR(A, method='habituated', thetacr=0.7, thetacs=[0.3, 0.5]) assert(h_split.sum() <= (h_split.shape[0]+1)/2) assert(h_split.sum() >= (h_split.shape[0]-1)/2) c_split = CR(A, method='concurrent', thetacr=0.7, thetacs=[0.3, 0.5]) assert(c_split.sum() <= (c_split.shape[0]+1)/2) assert(c_split.sum() >= (c_split.shape[0]-1)/2) # 2d-tests. CR is a little more picky with parameters and relaxation # type in 2d. Can still bound above by (n+1)/2. # Need looser lower bound, # say (n+1)/4. for i in range(10, 15): A = self.cases[i] h_split_auto = CR(A, method='habituated', thetacr=0.7, thetacs='auto') assert(h_split_auto.sum() <= (h_split_auto.shape[0]+1)/2) assert(h_split_auto.sum() >= (h_split_auto.shape[0]-1)/4) c_split_auto = CR(A, method='concurrent', thetacr=0.7, thetacs='auto') assert(c_split_auto.sum() <= (c_split_auto.shape[0]+1)/2) assert(c_split_auto.sum() >= (c_split_auto.shape[0]-1)/4) h_split = CR(A, method='habituated', thetacr=0.7, thetacs=[0.3, 0.5]) assert(h_split.sum() <= (h_split.shape[0]+1)/2) assert(h_split.sum() >= (h_split.shape[0]-1)/4) c_split = CR(A, method='concurrent', thetacr=0.7, thetacs=[0.3, 0.5]) assert(c_split.sum() <= (c_split.shape[0]+1)/2) assert(c_split.sum() >= (c_split.shape[0]-1)/4)
def extend_hierarchy(levels, strength, CF, keep, prolongation_function): """Extend the multigrid hierarchy.""" def unpack_arg(v): if isinstance(v, tuple): return v[0], v[1] else: return v, {} A = levels[-1].A # Compute the strength-of-connection matrix C, where larger # C[i,j] denote stronger couplings between i and j. fn, kwargs = unpack_arg(strength) if fn == 'symmetric': C = symmetric_strength_of_connection(A, **kwargs) elif fn == 'classical': C = classical_strength_of_connection(A, **kwargs) elif fn == 'distance': C = distance_strength_of_connection(A, **kwargs) elif (fn == 'ode') or (fn == 'evolution'): C = evolution_strength_of_connection(A, **kwargs) elif fn == 'energy_based': C = energy_based_strength_of_connection(A, **kwargs) elif fn == 'algebraic_distance': C = algebraic_distance(A, **kwargs) elif fn == 'affinity': C = affinity_distance(A, **kwargs) elif fn is None: C = A else: raise ValueError('unrecognized strength of connection method: %s' % str(fn)) # Generate the C/F splitting fn, kwargs = unpack_arg(CF) if fn == 'RS': splitting = split.RS(C, **kwargs) elif fn == 'PMIS': splitting = split.PMIS(C, **kwargs) elif fn == 'PMISc': splitting = split.PMISc(C, **kwargs) elif fn == 'CLJP': splitting = split.CLJP(C, **kwargs) elif fn == 'CLJPc': splitting = split.CLJPc(C, **kwargs) elif fn == 'CR': splitting = CR(C, **kwargs) else: raise ValueError('unknown C/F splitting method (%s)' % CF) # Generate the interpolation matrix that maps from the coarse-grid to the # fine-grid baseline_P = direct_interpolation(A, C, splitting) coarse_nodes = np.nonzero(splitting)[0] # Create a prolongation matrix with the same coarse-fine splitting and sparsity pattern # as the baseline P = prolongation_function(A, coarse_nodes, baseline_P, C) # Generate the restriction matrix that maps from the fine-grid to the # coarse-grid R = P.T.tocsr() # Store relevant information for this level if keep: levels[-1].C = C # strength of connection matrix levels[-1].splitting = splitting # C/F splitting levels[-1].P = P # prolongation operator levels[-1].R = R # restriction operator levels.append(multilevel_solver.level()) # Form next level through Galerkin product A = R * A * P levels[-1].A = A
def extend_hierarchy(levels, strength, CF, interp, restrict, filter_operator, coarse_grid_P, coarse_grid_R, keep): """ helper function for local methods """ # Filter operator. Need to keep original matrix on fineest level for # computing residuals if (filter_operator is not None) and (filter_operator[1] != 0): if len(levels) == 1: A = deepcopy(levels[-1].A) else: A = levels[-1].A filter_matrix_rows(A, filter_operator[1], diagonal=True, lump=filter_operator[0]) else: A = levels[-1].A # Check if matrix was filtered to be diagonal --> coarsest grid if A.nnz == A.shape[0]: return 1 # Zero initial complexities for strength, splitting and interpolation levels[-1].complexity['CF'] = 0.0 levels[-1].complexity['strength'] = 0.0 levels[-1].complexity['interpolate'] = 0.0 # Compute the strength-of-connection matrix C, where larger # C[i,j] denote stronger couplings between i and j. fn, kwargs = unpack_arg(strength) if fn == 'symmetric': C = symmetric_strength_of_connection(A, **kwargs) elif fn == 'classical': C = classical_strength_of_connection(A, **kwargs) elif fn == 'distance': C = distance_strength_of_connection(A, **kwargs) elif (fn == 'ode') or (fn == 'evolution'): C = evolution_strength_of_connection(A, **kwargs) elif fn == 'energy_based': C = energy_based_strength_of_connection(A, **kwargs) elif fn == 'algebraic_distance': C = algebraic_distance(A, **kwargs) elif fn == 'affinity': C = affinity_distance(A, **kwargs) elif fn is None: C = A else: raise ValueError('unrecognized strength of connection method: %s' % str(fn)) levels[-1].complexity['strength'] += kwargs['cost'][0] * A.nnz / float( A.nnz) # Generate the C/F splitting fn, kwargs = unpack_arg(CF) if fn == 'RS': splitting = RS(C, **kwargs) elif fn == 'PMIS': splitting = PMIS(C, **kwargs) elif fn == 'PMISc': splitting = PMISc(C, **kwargs) elif fn == 'CLJP': splitting = CLJP(C, **kwargs) elif fn == 'CLJPc': splitting = CLJPc(C, **kwargs) elif fn == 'CR': splitting = CR(C, **kwargs) elif fn == 'weighted_matching': splitting, soc = weighted_matching(C, **kwargs) if soc is not None: C = soc else: raise ValueError('unknown C/F splitting method (%s)' % CF) levels[-1].complexity['CF'] += kwargs['cost'][0] * C.nnz / float(A.nnz) temp = np.sum(splitting) if (temp == len(splitting)) or (temp == 0): return 1 # Generate the interpolation matrix that maps from the coarse-grid to the # fine-grid r_flag = False fn, kwargs = unpack_arg(interp) if fn == 'standard': P = standard_interpolation(A, C, splitting, **kwargs) elif fn == 'distance_two': P = distance_two_interpolation(A, C, splitting, **kwargs) elif fn == 'direct': P = direct_interpolation(A, C, splitting, **kwargs) elif fn == 'one_point': P = one_point_interpolation(A, C, splitting, **kwargs) elif fn == 'inject': P = injection_interpolation(A, splitting, **kwargs) elif fn == 'neumann': P = neumann_ideal_interpolation(A, splitting, **kwargs) elif fn == 'scaledAfc': P = scaled_Afc_interpolation(A, splitting, **kwargs) elif fn == 'air': if isspmatrix_bsr(A): temp_A = bsr_matrix(A.T) P = local_AIR(temp_A, splitting, **kwargs) P = bsr_matrix(P.T) else: temp_A = csr_matrix(A.T) P = local_AIR(temp_A, splitting, **kwargs) P = csr_matrix(P.T) elif fn == 'restrict': r_flag = True else: raise ValueError('unknown interpolation method (%s)' % interp) levels[-1].complexity['interpolate'] += kwargs['cost'][0] * A.nnz / float( A.nnz) # Build restriction operator fn, kwargs = unpack_arg(restrict) if fn is None: R = P.T elif fn == 'air': R = local_AIR(A, splitting, **kwargs) elif fn == 'neumann': R = neumann_AIR(A, splitting, **kwargs) elif fn == 'one_point': # Don't need A^T here temp_C = C.T.tocsr() R = one_point_interpolation(A, temp_C, splitting, **kwargs) if isspmatrix_bsr(A): R = R.T.tobsr() else: R = R.T.tocsr() elif fn == 'inject': # Don't need A^T or C^T here R = injection_interpolation(A, splitting, **kwargs) if isspmatrix_bsr(A): R = R.T.tobsr() else: R = R.T.tocsr() elif fn == 'standard': if isspmatrix_bsr(A): temp_A = A.T.tobsr() temp_C = C.T.tobsr() R = standard_interpolation(temp_A, temp_C, splitting, **kwargs) R = R.T.tobsr() else: temp_A = A.T.tocsr() temp_C = C.T.tocsr() R = standard_interpolation(temp_A, temp_C, splitting, **kwargs) R = R.T.tocsr() elif fn == 'distance_two': if isspmatrix_bsr(A): temp_A = A.T.tobsr() temp_C = C.T.tobsr() R = distance_two_interpolation(temp_A, temp_C, splitting, **kwargs) R = R.T.tobsr() else: temp_A = A.T.tocsr() temp_C = C.T.tocsr() R = distance_two_interpolation(temp_A, temp_C, splitting, **kwargs) R = R.T.tocsr() elif fn == 'direct': if isspmatrix_bsr(A): temp_A = A.T.tobsr() temp_C = C.T.tobsr() R = direct_interpolation(temp_A, temp_C, splitting, **kwargs) R = R.T.tobsr() else: temp_A = A.T.tocsr() temp_C = C.T.tocsr() R = direct_interpolation(temp_A, temp_C, splitting, **kwargs) R = R.T.tocsr() else: raise ValueError('unknown restriction method (%s)' % restrict) # If set P = R^T if r_flag: P = R.T # Optional different interpolation for RAP fn, kwargs = unpack_arg(coarse_grid_P) if fn == 'standard': P_temp = standard_interpolation(A, C, splitting, **kwargs) elif fn == 'distance_two': P_temp = distance_two_interpolation(A, C, splitting, **kwargs) elif fn == 'direct': P_temp = direct_interpolation(A, C, splitting, **kwargs) elif fn == 'one_point': P_temp = one_point_interpolation(A, C, splitting, **kwargs) elif fn == 'inject': P_temp = injection_interpolation(A, splitting, **kwargs) elif fn == 'neumann': P_temp = neumann_ideal_interpolation(A, splitting, **kwargs) elif fn == 'air': if isspmatrix_bsr(A): temp_A = bsr_matrix(A.T) P_temp = local_AIR(temp_A, splitting, **kwargs) P_temp = bsr_matrix(P_temp.T) else: temp_A = csr_matrix(A.T) P_temp = local_AIR(temp_A, splitting, **kwargs) P_temp = csr_matrix(P_temp.T) else: P_temp = P # Optional different restriction for RAP fn, kwargs = unpack_arg(coarse_grid_R) if fn == 'air': R_temp = local_AIR(A, splitting, **kwargs) elif fn == 'neumann': R_temp = neumann_AIR(A, splitting, **kwargs) elif fn == 'one_point': # Don't need A^T here temp_C = C.T.tocsr() R_temp = one_point_interpolation(A, temp_C, splitting, **kwargs) if isspmatrix_bsr(A): R_temp = R_temp.T.tobsr() else: R_temp = R_temp.T.tocsr() elif fn == 'inject': # Don't need A^T or C^T here R_temp = injection_interpolation(A, splitting, **kwargs) if isspmatrix_bsr(A): R_temp = R_temp.T.tobsr() else: R_temp = R_temp.T.tocsr() elif fn == 'standard': if isspmatrix_bsr(A): temp_A = A.T.tobsr() temp_C = C.T.tobsr() R_temp = standard_interpolation(temp_A, temp_C, splitting, **kwargs) R_temp = R_temp.T.tobsr() else: temp_A = A.T.tocsr() temp_C = C.T.tocsr() R_temp = standard_interpolation(temp_A, temp_C, splitting, **kwargs) R_temp = R_temp.T.tocsr() elif fn == 'distance_two': if isspmatrix_bsr(A): temp_A = A.T.tobsr() temp_C = C.T.tobsr() R_temp = distance_two_interpolation(temp_A, temp_C, splitting, **kwargs) R_temp = R_temp.T.tobsr() else: temp_A = A.T.tocsr() temp_C = C.T.tocsr() R_temp = distance_two_interpolation(temp_A, temp_C, splitting, **kwargs) R_temp = R_temp.T.tocsr() elif fn == 'direct': if isspmatrix_bsr(A): temp_A = A.T.tobsr() temp_C = C.T.tobsr() R_temp = direct_interpolation(temp_A, temp_C, splitting, **kwargs) R_temp = R_temp.T.tobsr() else: temp_A = A.T.tocsr() temp_C = C.T.tocsr() R_temp = direct_interpolation(temp_A, temp_C, splitting, **kwargs) R_temp = R_temp.T.tocsr() else: R_temp = R # Store relevant information for this level if keep: levels[-1].C = C # strength of connection matrix levels[-1].P = P # prolongation operator levels[-1].R = R # restriction operator levels[-1].splitting = splitting # C/F splitting # Form coarse grid operator, get complexity #levels[-1].complexity['RAP'] = mat_mat_complexity(R_temp,A) / float(A.nnz) #RA = R_temp * A #levels[-1].complexity['RAP'] += mat_mat_complexity(RA,P_temp) / float(A.nnz) #A = RA * P_temp # RL: RAP = R*(A*P) levels[-1].complexity['RAP'] = mat_mat_complexity(A, P_temp) / float(A.nnz) AP = A * P_temp levels[-1].complexity['RAP'] += mat_mat_complexity(R_temp, AP) / float( A.nnz) A = R_temp * AP # Make sure coarse-grid operator is in correct sparse format if (isspmatrix_csr(P) and (not isspmatrix_csr(A))): A = A.tocsr() elif (isspmatrix_bsr(P) and (not isspmatrix_bsr(A))): A = A.tobsr() A.eliminate_zeros() levels.append(multilevel_solver.level()) levels[-1].A = A return 0
def test_cr(self): A = self.cases[6] splitting = CR(A) # 1d-tests, should be alternating aggregates # (n-1)/2 < = sum <= (n+1)/2. # Test auto thetacs and set thetacs values for i in range(3,10): A = self.cases[i] h_split_auto = CR(A, method='habituated', thetacr=0.7, thetacs='auto') assert(h_split_auto.sum() <= (h_split_auto.shape[0]+1)/2 ) assert(h_split_auto.sum() >= (h_split_auto.shape[0]-1)/2 ) c_split_auto = CR(A, method='concurrent', thetacr=0.7, thetacs='auto') assert(c_split_auto.sum() <= (c_split_auto.shape[0]+1)/2 ) assert(c_split_auto.sum() >= (c_split_auto.shape[0]-1)/2 ) h_split = CR(A, method='habituated', thetacr=0.7, thetacs=[0.3,0.5]) assert(h_split.sum() <= (h_split.shape[0]+1)/2 ) assert(h_split.sum() >= (h_split.shape[0]-1)/2 ) c_split = CR(A, method='concurrent', thetacr=0.7, thetacs=[0.3,0.5]) assert(c_split.sum() <= (c_split.shape[0]+1)/2 ) assert(c_split.sum() >= (c_split.shape[0]-1)/2 ) # 2d-tests. CR is a little more picky with parameters and relaxation # type in 2d. Can still bound above by (n+1)/2. Need looser lower bound, # say (n+1)/4. for i in range(10,15): A = self.cases[i] h_split_auto = CR(A, method='habituated', thetacr=0.7, thetacs='auto') assert(h_split_auto.sum() <= (h_split_auto.shape[0]+1)/2 ) assert(h_split_auto.sum() >= (h_split_auto.shape[0]-1)/4 ) c_split_auto = CR(A, method='concurrent', thetacr=0.7, thetacs='auto') assert(c_split_auto.sum() <= (c_split_auto.shape[0]+1)/2 ) assert(c_split_auto.sum() >= (c_split_auto.shape[0]-1)/4 ) h_split = CR(A, method='habituated', thetacr=0.7, thetacs=[0.3,0.5]) assert(h_split.sum() <= (h_split.shape[0]+1)/2 ) assert(h_split.sum() >= (h_split.shape[0]-1)/4 ) c_split = CR(A, method='concurrent', thetacr=0.7, thetacs=[0.3,0.5]) assert(c_split.sum() <= (c_split.shape[0]+1)/2 ) assert(c_split.sum() >= (c_split.shape[0]-1)/4 )
def test_cr(self): A = self.cases[6] splitting = CR(A) assert (splitting.sum() < splitting.shape[0])
def test_cr(self): A = self.cases[6] splitting = CR(A) assert(splitting.sum() < splitting.shape[0])