<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def find_connected_sites(bonds, am, flatten=True, logic='or'):
 r""" Given an adjacency matrix, finds which sites are connected to the input bonds. Parameters am : scipy.sparse matrix The adjacency matrix of the network. Must be symmetrical such that if sites *i* and *j* are connected, the matrix contains non-zero values at locations (i, j) and (j, i). flatten : boolean (default is ``True``) Indicates whether the returned result is a compressed array of all neighbors, or a list of lists with each sub-list containing the neighbors for each input site. Note that an *unflattened* list might be slow to generate since it is a Python ``list`` rather than a Numpy array. logic : string Specifies logic to filter the resulting list. Options are: **'or'** : (default) All neighbors of the input bonds. This is also known as the 'union' in set theory or (sometimes) 'any' in boolean logic. Both keywords are accepted and treated as 'or'. **'xor'** : Only neighbors of one and only one input bond. This is useful for finding the sites that are not shared by any of the input bonds. 'exclusive_or' is also accepted. **'xnor'** : Neighbors that are shared by two or more input bonds. This is equivalent to finding all neighbors with 'or', minus those found with 'xor', and is useful for finding neighbors that the inputs have in common. 'nxor' is also accepted. **'and'** : Only neighbors shared by all input bonds. This is also known as 'intersection' in set theory and (somtimes) as 'all' in boolean logic. Both keywords are accepted and treated as 'and'. Returns ------- An array containing the connected sites, filtered by the given logic. If ``flatten`` is ``False`` then the result is a list of lists containing the neighbors of each given input bond. In this latter case, sites that have been removed by the given logic are indicated by ``nans``, thus the array is of type ``float`` and is not suitable for indexing. See Also -------- find_complement """

    if am.format != 'coo':
        raise Exception('Adjacency matrix must be in COO format')
    bonds = sp.array(bonds, ndmin=1)
    if len(bonds) == 0:
        return []
    neighbors = sp.hstack((am.row[bonds], am.col[bonds])).astype(sp.int64)
    if neighbors.size:
        n_sites = sp.amax(neighbors)
    if logic in ['or', 'union', 'any']:
        neighbors = sp.unique(neighbors)
    elif logic in ['xor', 'exclusive_or']:
        neighbors = sp.unique(sp.where(sp.bincount(neighbors) == 1)[0])
    elif logic in ['xnor']:
        neighbors = sp.unique(sp.where(sp.bincount(neighbors) > 1)[0])
    elif logic in ['and', 'all', 'intersection']:
        temp = sp.vstack((am.row[bonds], am.col[bonds])).T.tolist()
        temp = [set(pair) for pair in temp]
        neighbors = temp[0]
        [neighbors.intersection_update(pair) for pair in temp[1:]]
        neighbors = sp.array(list(neighbors), dtype=sp.int64, ndmin=1)
    else:
        raise Exception('Specified logic is not implemented')
    if flatten is False:
        if neighbors.size:
            mask = sp.zeros(shape=n_sites+1, dtype=bool)
            mask[neighbors] = True
            temp = sp.hstack((am.row[bonds], am.col[bonds])).astype(sp.int64)
            temp[~mask[temp]] = -1
            inds = sp.where(temp == -1)[0]
            if len(inds):
                temp = temp.astype(float)
                temp[inds] = sp.nan
            temp = sp.reshape(a=temp, newshape=[len(bonds), 2], order='F')
            neighbors = temp
        else:
            neighbors = [sp.array([], dtype=sp.int64) for i in range(len(bonds))]
    return neighbors