Example #1
0
def rips_chain_complex(simplices):
    """Construct the boundary operators for the Rips complex 

    Constructs the boundary operators for the Rips complex for
    a given a list of simplex arrays.

    Parameters
    ----------
    simplices : list of arrays
        List of length D, where simplices[i] is the simplex
        array representing the i-dimensional simplices.

    Returns
    -------
    Bs : list of sparse matrices
        List of length D + 1 where Bs[i] is the boundary operator
        for the i-dimensional simplices.

    Examples
    --------
    TODO

    """
    Bs = []

    dtype = 'float32'

    simplices = [asarray(x) for x in simplices]

    B0 = csc_matrix( (1, len(simplices[0]) ), dtype=dtype )
    Bs.append( B0 )
    
    if len(simplices) == 1:
        B1 = csc_matrix( (len(simplices[0]), 1), dtype=dtype )
        Bs.append(B1)
        return Bs

    B1 = empty( 2*len(simplices[1]), dtype=dtype )
    B1[0::2] = -1
    B1[1::2] =  1
    B1 = csc_matrix( ( B1, simplices[1].ravel(), arange(0, 2*(len(simplices[1]) + 1), 2)), \
            shape=(len(simplices[0]), len(simplices[1])) )
    Bs.append( B1 )

    for f,s in zip(simplices[1:-1],simplices[2:]):
        k = f.shape[1]

        faces = empty(( len(s), (k+1), k),dtype=s.dtype)
        for i in range(k+1):
            faces[:,i,:i] = s[:,   : i ]
            faces[:,i,i:] = s[:,i+1:  ]

        indptr  = arange(0, (k+1)*(len(s) + 1), k+1)
        indices = simplex_array_searchsorted(f, faces.reshape(-1,k) )
        data    = empty( faces.shape[:-1], dtype=dtype )
        for i in range(k+1):
            data[:,i] = (-1)**i
        data = data.ravel()

        Bs.append( csc_matrix( (data,indices,indptr), shape=(len(f),len(s)) ) )

    return Bs
    def __init__(self, simplices):
        """Construct an abstract simplicial complex

        Parameters
        ----------
        simplices : list of arrays
            Maximal simplices of each dimension
            TODO

        Examples
        --------
        >>> from pydec.dec import abstract_simplicial_complex
        >>> from numpy import array
        >>> simplices = [array([[4]]), array([[0,3]])]
        >>> asc = abstract_simplicial_complex(simplices)

        TODO

        >>> print rc.simplices[0]
        >>> print rc.simplices[1]

        Notes
        -----

        TODO explain input handling

        """

        # convert array-like objects to arrays
        simplices = [atleast_2d(s) for s in simplices]

        # find top simplex dimension
        D = max([s.shape[1] for s in simplices]) - 1
         
        # convert simplices list to canonical simplex_array list representation
        old_simplices = simplices
        simplices = [None] * (D + 1)
        for s in old_simplices:
            simplices[s.shape[1] - 1] = s
       

        # top most simplex array
        s = simplices[-1].copy()

        parity = simplex_array_parity(s)
        s.sort()

        chain_complex = [None] * (D + 1)

        for d in range(D - 1, -1, -1):
            s,B = simplex_array_boundary(s,parity)

            if simplices[d] is not None:
                old_s = s

                # sort columns to ensure user-defined faces are in canonical format
                simplices[d].sort()

                # merge user-defined faces with boundary faces
                s = vstack((s,simplices[d]))
                
                # sort rows to bring equivalent elements together
                s = s[lexsort(s.T[::-1])]

                # find unique simplices
                mask = -hstack((array([False]),alltrue(s[1:] == s[:-1],axis=1)))
                s = s[mask]

                # indices of the boundary faces in the full face array
                remap = simplex_array_searchsorted(s, old_s)
                
                # remap indices of boundary operator
                B = B.tocoo(copy=False)
                B = sparse.coo_matrix((B.data, (remap[B.row], B.col)), (s.shape[0], B.shape[1]))
                B = B.tocsr()
            
            # faces are already in canonical format, so parity is even
            parity = zeros(s.shape[0],dtype=s.dtype)
            
            simplices[d]       = s
            chain_complex[d+1] = B

        # compute 0-simplices and boundary operator
        simplices[0]     = arange(simplices[0].max() + 1).reshape(-1,1)
        chain_complex[0] = sparse.csr_matrix( (1,len(s)), dtype='uint8')

        # store the cochain complex
        Bn = chain_complex[-1]
        cochain_complex  = [ B.T for B in chain_complex[1:] ]
        cochain_complex += [ sparse.csc_matrix( (1, Bn.shape[1]), dtype=Bn.dtype) ] 

        # store the data members
        self.simplices = simplices
        self._chain_complex   = chain_complex
        self._cochain_complex = cochain_complex