def get_smamin_rearrangement(N,PrP,Mc,Bc):
	from smamin_utils import col_columns_atend
	from scipy.io import loadmat, savemat

	# get the indices of the B2-part
	B2Inds = get_B2_bubbleinds(N, PrP.V, PrP.mesh)
	# the B2 inds wrt to inner nodes
	# this gives a masked array of boolean type
	B2BoolInv = np.in1d(np.arange(PrP.V.dim())[PrP.invinds], B2Inds)
	# this as indices
	B2BI = np.arange(len(B2BoolInv), dtype=np.int32)[B2BoolInv]

	dname = '%sSmeMcBc' % N

	try: SmDic = loadmat(dname)

	except IOError:
		print 'Computing the B2 indices...'
		# get the indices of the B2-part
		B2Inds = get_B2_bubbleinds(N, PrP.V, PrP.mesh)
		# the B2 inds wrt to inner nodes
		# this gives a masked array of boolean type
		B2BoolInv = np.in1d(np.arange(PrP.V.dim())[PrP.invinds], B2Inds)
		# this as indices
		B2BI = np.arange(len(B2BoolInv), dtype=np.int32)[B2BoolInv]
		# Reorder the matrices for smart min ext...
		# ...the columns
		print 'Rearranging the matrices...'
		# Reorder the matrices for smart min ext...
		# ...the columns
		MSmeC = col_columns_atend(Mc, B2BI)
		BSme = col_columns_atend(Bc, B2BI)
		# ...and the lines
		MSmeCL = col_columns_atend(MSmeC.T, B2BI)
		print 'done'

		savemat(dname, { 'MSmeCL': MSmeCL, 'BSme':BSme, 
			'B2Inds':B2Inds, 'B2BoolInv':B2BoolInv, 'B2BI':B2BI} )
	
	SmDic = loadmat(dname)

	MSmeCL = SmDic['MSmeCL']
	BSme = SmDic['BSme']
	B2Inds = SmDic['B2Inds']
	B2BoolInv = SmDic['B2BoolInv']>0
	B2BoolInv = B2BoolInv.flatten()
	B2BI = SmDic['B2BI']

	return MSmeCL, BSme, B2Inds, B2BoolInv, B2BI 
    def test_collectB2(self):

        from smamin_utils import col_columns_atend

        N = 100
        n = 7

        col = np.arange(0, N, n).astype(int)

        v = np.arange(N)
        v = np.append(v, 0*col)

        colI = np.in1d(range(len(v)), col)

        mat = sps.spdiags(v, [0], N, N + len(col))
        MatRa = col_columns_atend(mat, col)

        vra = np.r_[v[~colI], v[col]]

        self.assertTrue(np.allclose(MatRa*vra, mat*v))
    def test_rearrange_matrices(self):
        """check the algorithm rearranging for B2, solve the

        rearranged system and sort back the solution vector
        The rearr. is done by swapping columns in the coeff matrix,
        thus the resort is done by swapping the entries of the solution
        vector"""

        import dolfin
        import prob_defs as tts
        import dolfin_to_nparrays as dtn
        from smamin_utils import col_columns_atend, revert_sort_tob2
        import smamin_thcr_mesh

        N = 32
        mesh = smamin_thcr_mesh.getmake_mesh(N)

        V = dolfin.VectorFunctionSpace(mesh, "CG", 2)
        Q = dolfin.FunctionSpace(mesh, "CG", 1)

        velbcs = tts.setget_velbcs_zerosq(mesh, V)

        bcinds = []
        for bc in velbcs:
            bcdict = bc.get_boundary_values()
            bcinds.extend(bcdict.keys())

        # indices of the inner velocity nodes
        invinds = np.setdiff1d(range(V.dim()), bcinds)

        Ma, Aa, BTa, Ba, MPa = dtn.get_sysNSmats(V, Q)

        Mc = Ma[invinds, :][:, invinds]
        Bc = Ba[:, invinds]
        BTc = BTa[invinds, :]

        B2BubInds, _ = smamin_thcr_mesh.get_B2_bubbleinds(N, V, mesh)
        # we need the B2Bub indices in the reduced setting vc
        # this gives a masked array of boolean type
        B2BubBool = np.in1d(np.arange(V.dim())[invinds], B2BubInds)
        # B2BubInds = np.arange(len(B2BubIndsBool

        Nv = len(invinds)
        Np = Q.dim()
        dt = 1.0 / N

        # the complement of the bubble index in the inner nodes
        BubIndC = ~B2BubBool  # np.setdiff1d(np.arange(Nv),B2BubBool)
        # the bubbles as indices
        B2BI = np.arange(len(B2BubBool))[B2BubBool]

        # Reorder the matrices for smart min ext
        MSme = col_columns_atend(Mc, B2BI)
        BSme = col_columns_atend(Bc, B2BI)

        B1Sme = BSme[:, :Nv - (Np - 1)]
        B2Sme = BSme[:, Nv - (Np - 1):]

        M1Sme = MSme[:, :Nv - (Np - 1)]
        M2Sme = MSme[:, Nv - (Np - 1):]

        IterA1 = sps.hstack(
            [sps.hstack([M1Sme, dt*M2Sme]), -dt*BTc[:, 1:]])

        IterA2 = sps.hstack([sps.hstack([B1Sme[1:, :], dt*B2Sme[1:, :]]),
                             sps.csr_matrix((Np - 1, (Np - 1)))])
        # The rearranged coefficient matrix
        IterARa = sps.vstack([IterA1, IterA2])

        IterAqq = sps.hstack([Mc, -dt*BTc[:, 1:]])
        IterAp = sps.hstack([Bc[1:, :], sps.csr_matrix((Np-1, Np-1))])
        # The actual coefficient matrix
        IterA = sps.vstack([IterAqq, IterAp])

        rhs = np.random.random((Nv + Np - 1, 1))

        SolActu = spsla.spsolve(IterA, rhs)
        SolRa = spsla.spsolve(IterARa, rhs)

        # Sort it back
        # manually
        SortBack = np.zeros((Nv + Np - 1, 1))
        # q1
        SortBack[BubIndC, 0] = SolRa[:Nv - (Np - 1)]
        # tq2
        SortBack[B2BI, 0] = dt*SolRa[Nv - (Np - 1):Nv]
        SortBack[Nv:, 0] = SolRa[Nv:]

        SolRa = np.atleast_2d(SolRa).T

        # and by function
        SolRa[Nv - (Np - 1):Nv, 0] = dt*SolRa[Nv - (Np - 1):Nv, 0]
        SB2 = revert_sort_tob2(SolRa[:Nv, ], B2BI)
        SB2 = np.vstack([SB2, SolRa[Nv:, ]])
        # SB2v = np.atleast_2d(SB2)

        SolActu = np.atleast_2d(SolActu)
        SortBack = np.atleast_2d(SortBack).T

        self.assertTrue(np.allclose(SolActu, SortBack, atol=1e-6))
        self.assertTrue(np.allclose(SolActu, SB2.T, atol=1e-6))
def get_smamin_rearrangement(N, PrP, V=None, Q=None, invinds=None, nu=None,
                             Pdof=None, M=None, A=None, B=None, mesh=None,
                             addnedgeat=None,
                             scheme='TH', fullB=None, crinicell=None):
    from smamin_utils import col_columns_atend
    from scipy.io import loadmat, savemat
    """ rearrange `B` and `M` for smart minimal extension

    and return the indices of the ext. nodes

    Parameters
    ----------
    scheme : {'TH', 'CR'}
        toggle the scheme

         * 'TH' : Taylor-Hood
         * 'CR' : Crouzeix-Raviart

    crinicell : int, optional
        the starting cell for the 'CR' scheme, defaults to `0`
    addnedge : int, optional
        whether to add a Neumann edge in the CR scheme, defaults to `None`

    Returns
    -------
    MSmeCL : (N,N) sparse matrix
        the rearranged mass matrix (columns and lines swapped)
    BSme : (K, N) sparse matrix
        the rearranged divergence matrix (columns swapped)
    B2Inds : (K, ) array
        indices of the nodes corresponding to the minimal extension
        w.r.t all nodes of the velocity space
    B2BoolInv : (N, ) boolean array
        mask of the ext. nodes w.r.t. the inner nodes in V,
        e.g. `v2 = v[B2BoolInv]`
    B2BI : (K, ) int array
        indices of the ext. nodes w.r.t the inner nodes in V
    """
    Q = PrP.Q if Q is None else Q
    V = PrP.V if V is None else V
    invinds = PrP.invinds if invinds is None else invinds
    nu = PrP.nu if nu is None else nu
    mesh = PrP.mesh if mesh is None else mesh
    Pdof = PrP.Pdof if Pdof is None and PrP is not None else Pdof

    if scheme == 'TH':
        print 'solving index 1 -- with TH scheme'
        dname = 'mats/SmeMcBc_N{0}nu{1}_TH'.format(N, nu)
        get_b2inds_rtn = get_B2_bubbleinds
        args = dict(N=N, V=V, mesh=mesh)
    elif scheme == 'CR':
        print 'solving index 1 -- with CR scheme'
        dname = 'mats/SmeMcBc_N{0}nu{1}_CR'.format(N, nu)
        # pressure-DoF of B_matrix NOT removed yet!
        get_b2inds_rtn = get_B2_CRinds
        args = dict(N=N, V=V, mesh=mesh, Q=Q, inicell=crinicell,
                    B_matrix=B, invinds=invinds)

    try:
        SmDic = loadmat(dname)
        pdoflist = loadmat(dname+'pdoflist')  # TODO enable saving again

    except IOError:
        print 'Computing the B2 indices...'
        # get the indices of the B2-part
        B2Inds, pdoflist = get_b2inds_rtn(**args)
        if addnedgeat is not None:
            # TODO: hard coded filtering of the needed V bas func
            # list of columns that have a nnz at cell #addnedge
            potcols = fullB[addnedgeat, :].indices
            for col in potcols:
                # TODO here we need B
                if fullB[:, col].nnz == 1:
                    coltoadd = col
                    break
            B2Inds = np.r_[coltoadd, B2Inds]
            # end TODO

        # the B2 inds wrt to inner nodes
        # this gives a masked array of boolean type
        B2BoolInv = np.in1d(np.arange(V.dim())[invinds], B2Inds)
        # this as indices
        B2BI = np.arange(len(B2BoolInv), dtype=np.int32)[B2BoolInv]
        # Reorder the matrices for smart min ext...
        # ...the columns
        print 'Rearranging the matrices...'
        # Reorder the matrices for smart min ext...
        # ...the columns
        MSmeC = col_columns_atend(M, B2BI)
        BSme = col_columns_atend(B, B2BI)
        # ...and the lines
        MSmeCL = col_columns_atend(MSmeC.T, B2BI)
        if A is not None:
            ASmeC = col_columns_atend(A, B2BI)
            ASmeCL = (col_columns_atend(ASmeC.T, B2BI)).T

        print 'done'

        savemat(dname, {'MSmeCL': MSmeCL,
                        'ASmeCL': ASmeCL,
                        'BSme': BSme,
                        'B2Inds': B2Inds,
                        'B2BoolInv': B2BoolInv,
                        'B2BI': B2BI})
        if scheme == 'CR':
            savemat(dname+'pdoflist', {'pdoflist': pdoflist})

    SmDic = loadmat(dname)

    MSmeCL = SmDic['MSmeCL']
    ASmeCL = SmDic['ASmeCL']
    BSme = SmDic['BSme']
    B2Inds = SmDic['B2Inds']
    B2BoolInv = SmDic['B2BoolInv'] > 0
    B2BoolInv = B2BoolInv.flatten()
    B2BI = SmDic['B2BI']
    if scheme == 'CR':
        pdoflist = loadmat(dname+'pdoflist')['pdoflist']
    else:
        pdoflist = None
    only_check_cond = False
    if only_check_cond:
        print 'Scheme is ', scheme
        import matplotlib.pylab as pl
        if Pdof is None:
            B2 = BSme[:, :][:, -B2Inds.size:]
            B2res = fullB[pdoflist.flatten(), :][:, B2Inds.flatten()]
            print 'condition number is ', npla.cond(B2res.todense())
            # B2res = BSme[pdoflist.flatten(), :][:, -B2Inds.size:]
            pl.figure(2)
            pl.spy(B2res)  # [:100, :][:, :100])
        elif Pdof == 0:
            B2 = BSme[1:, :][:, -B2Inds.size:]
            print 'condition number is ', npla.cond(B2.todense())
        else:
            raise NotImplementedError()
        print 'N is ', N
        print 'B2 shape is ', B2.shape
        pl.figure(1)
        pl.spy(B2)
        pl.show(block=False)
        import sys
        sys.exit('done')

    if fullB is not None and only_check_cond:
        fbsme = col_columns_atend(fullB, B2Inds.flatten())
        import matplotlib.pylab as pl
        pl.figure(2)
        pl.spy(fbsme)
        pl.show(block=False)
        fbsmec = fbsme[0:, :][:, -B2Inds.size:]
        pl.figure(3)
        pl.spy(fbsmec)
        pl.show(block=False)
        if pdoflist is not None:
            linelist = []
            for pdof in pdoflist.flatten().tolist()[1:]:
                linelist.append(fbsmec[pdof, :])
            fbsmecr = sps.vstack(linelist)
        pl.figure(4)
        pl.spy(fbsmecr)
        pl.show(block=False)

        print 'condition number is ', npla.cond(fbsmecr.T.todense())
        print 'N is ', N

    if A is None:
        return MSmeCL, BSme, B2Inds, B2BoolInv, B2BI
    else:
        return MSmeCL, ASmeCL, BSme, B2Inds, B2BoolInv, B2BI