def sparseScalarProductOfDot(A, B, C, out=None):
    """
    Returns A * np.dot(B, C), however it does so keeping in  mind 
    the sparsity of A, calculating values only where required.
     
    Params
    A         - a sparse CSR matrix
    B         - a dense matrix
    C         - a dense matrix
    out       - if specified, must be a sparse CSR matrix with identical
                non-zero pattern to A (i.e. same indices and indptr)
    
    Returns
    out_data, though note that this is the same parameter passed in and overwitten.
    """
    assert ssp.isspmatrix_csr(A), "A matrix is not a CSR matrix"
    assert not np.isfortran(B), "B matrix is not stored in row-major form"
    assert not np.isfortran(C), "C matrix is not stored in row-major form"

    if out is None:
        out = A.copy()
    if A.dtype == np.float64:
        compiled.sparseScalarQuotientOfDot_f8(A.data, A.indices, A.indptr, B, C, out.data)
    elif A.dtype == np.float32:
        compiled.sparseScalarQuotientOfDot_f4(A.data, A.indices, A.indptr, B, C, out.data)
    else:
        _sparseScalarQuotientOfDot_py(A, B, C, out)
    return out
def sparseScalarQuotientOfDot (A, B, C, out=None, start=None, end=None):
    '''
    Returns A / np.dot(B, C), however it does so keeping in  mind 
    the sparsity of A, calculating values only where required.
     
    Params
    A         - a sparse CSR matrix
    B         - a dense matrix
    C         - a dense matrix
    out       - if specified, must be a sparse CSR matrix with identical
                non-zero pattern to A (i.e. same indices and indptr)
    start     - where to start indexing A
    end       - where to stop indexing A
    
    Returns
    out_data, though note that this is the same parameter passed in and overwitten.
    '''
    assert ssp.isspmatrix_csr(A), "A matrix is not a CSR matrix"
    assert not np.isfortran(B), "B matrix is not stored in row-major form"
    assert not np.isfortran(C), "C matrix is not stored in row-major form"

    if start is None:
        start = 0
    if end is None:
        end = A.shape[0]
    if out is None:
        out = A[start:end,:].copy()
        
    if A.dtype == np.float64:
        compiled.sparseScalarQuotientOfDot_f8(A.data, A.indices, A.indptr, B, C, out.data, start, end)
    elif A.dtype == np.float32:
        compiled.sparseScalarQuotientOfDot_f4(A.data, A.indices, A.indptr, B, C, out.data, start, end)
    else:
        raise ValueError ("No native Cython implementation for dtype " + str(A.dtype))
        _sparseScalarQuotientOfDot_py(A,B,C, out)
    return out