<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def fit_candidates(AggOp, B, tol=1e-10):
 """Fit near-nullspace candidates to form the tentative prolongator. Parameters AggOp : csr_matrix Describes the sparsity pattern of the tentative prolongator. Has dimension (#blocks, #aggregates) B : array The near-nullspace candidates stored in column-wise fashion. Has dimension (#blocks * blocksize, #candidates) tol : scalar Threshold for eliminating local basis functions. If after orthogonalization a local basis function Q[:, j] is small, i.e. ||Q[:, j]|| < tol, then Q[:, j] is set to zero. Returns ------- (Q, R) : (bsr_matrix, array) The tentative prolongator Q is a sparse block matrix with dimensions (#blocks * blocksize, #aggregates * #candidates) formed by dense blocks of size (blocksize, #candidates). The coarse level candidates are stored in R which has dimensions (#aggregates * #candidates, #candidates). See Also -------- amg_core.fit_candidates Notes ----- Assuming that each row of AggOp contains exactly one non-zero entry, i.e. all unknowns belong to an aggregate, then Q and R satisfy the relationship B = Q*R. In other words, the near-nullspace candidates are represented exactly by the tentative prolongator. If AggOp contains rows with no non-zero entries, then the range of the tentative prolongator will not include those degrees of freedom. This situation is illustrated in the examples below. References .. [1] Vanek, P. and Mandel, J. and Brezina, M., "Algebraic Multigrid by Smoothed Aggregation for Second and Fourth Order Elliptic Problems", Computing, vol. 56, no. 3, pp. 179--196, 1996. http://citeseer.ist.psu.edu/vanek96algebraic.html Examples -------- matrix([[ 0.70710678, 0. ], [ 0.70710678, 0. ], [ 0. , 0.70710678], [ 0. , 0.70710678]]) array([[ 1.41421356], [ 1.41421356]]) matrix([[ 0.70710678, -0.70710678, 0. , 0. ], [ 0.70710678, 0.70710678, 0. , 0. ], [ 0. , 0. , 0.70710678, -0.70710678], [ 0. , 0. , 0.70710678, 0.70710678]]) array([[ 1.41421356, 0.70710678], [ 0. , 0.70710678], [ 1.41421356, 3.53553391], [ 0. , 0.70710678]]) matrix([[ 0.70710678, 0. ], [ 0.70710678, 0. ], [ 0. , 0. ], [ 0. , 1. ]]) array([[ 1.41421356], [ 1. ]]) """

    if not isspmatrix_csr(AggOp):
        raise TypeError('expected csr_matrix for argument AggOp')

    B = np.asarray(B)
    if B.dtype not in ['float32', 'float64', 'complex64', 'complex128']:
        B = np.asarray(B, dtype='float64')

    if len(B.shape) != 2:
        raise ValueError('expected 2d array for argument B')

    if B.shape[0] % AggOp.shape[0] != 0:
        raise ValueError('dimensions of AggOp %s and B %s are \
                          incompatible' % (AggOp.shape, B.shape))

    N_fine, N_coarse = AggOp.shape

    K1 = int(B.shape[0] / N_fine)  # dof per supernode (e.g. 3 for 3d vectors)
    K2 = B.shape[1]                # candidates

    # the first two dimensions of R and Qx are collapsed later
    R = np.empty((N_coarse, K2, K2), dtype=B.dtype)    # coarse candidates
    Qx = np.empty((AggOp.nnz, K1, K2), dtype=B.dtype)  # BSR data array

    AggOp_csc = AggOp.tocsc()

    fn = amg_core.fit_candidates
    fn(N_fine, N_coarse, K1, K2,
       AggOp_csc.indptr, AggOp_csc.indices, Qx.ravel(),
       B.ravel(), R.ravel(), tol)

    Q = bsr_matrix((Qx.swapaxes(1, 2).copy(), AggOp_csc.indices,
                    AggOp_csc.indptr), shape=(K2*N_coarse, K1*N_fine))
    Q = Q.T.tobsr()
    R = R.reshape(-1, K2)

    return Q, R