# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_arr.ipynb.

# %% auto 0
__all__ = ['chain', 'nparray', 'detach', 'clone', 'cpu', 'numpy', 'todense', 'tolist', 'toarray', 'arrchain', 'try2arr',
           'trc2arr', 'mtx2arr', 'spr2arr', 'dns2arr', 'ann2arr', 'mth2arr', 'asarr']

# %% ../nbs/00_arr.ipynb 6
#| export


# %% ../nbs/00_arr.ipynb 8
from typing import Any, Union, TypeAlias, ParamSpec

# %% ../nbs/00_arr.ipynb 10
import numpy as np

# %% ../nbs/00_arr.ipynb 12
from atyp import StrQ, IntQ, NPArray, NPMatrix, Tensor, AnnData
from atyp import SPArray, SPMatrix, Index, Series, DataFrame

from chck import isad, isarr, ismtx, istens, issparse, istrc, isnone, notnone, isnpmatrix
from nlit import CPU, TOARRAY, TODENSE, TOLIST, DETACH, CLONE, NUMPY
from xtr.call import attrfunc, applyfns
from ain import ain

# %% ../nbs/00_arr.ipynb 14
#| export


# %% ../nbs/00_arr.ipynb 16
class chain(ain): ...

@chain.able
def nparray(a): return np.array(a)

@chain.able
@attrfunc(DETACH)
def detach(x): '''try: x.detach() except: x'''

@chain.able
@attrfunc(CLONE)
def clone(x): '''try: x.clone() except: x'''

@chain.able
@attrfunc(CPU)
def cpu(x): '''try: x.cpu() except: x'''

@chain.able
@attrfunc(NUMPY)
def numpy(x): '''try: x.numpy() except: x'''

@chain.able
@attrfunc(TODENSE)
def todense(x): '''try: x.todense() except: x'''

@chain.able
@attrfunc(TOLIST)
def tolist(x): '''try: x.tolist() except: x'''

@chain.able
@attrfunc(TOARRAY)
def toarray(x): '''try: x.toarray() except: x'''

# %% ../nbs/00_arr.ipynb 17
def arrchain(x, funcs, *args, **kwargs): 
    return applyfns(x, funcs, isarr, *args, **kwargs)

def try2arr(a) -> NPArray:
    try: return a if isarr(a) else np.array(a)
    except: return a

def trc2arr(a: Tensor) -> NPArray:
    '''from torch.tensor --> np.array e.g.
    `torch.tensor([...]).detach().clone().cpu().numpy()`'''
    if isarr(a) or not istrc(a): return a
    return arrchain(a, (detach, clone, cpu, numpy, ))

def mtx2arr(a: NPMatrix) -> NPArray:
    '''from np.matrix --> np.array e.g. 
    `np.array(np.matrix([...]).tolist())`'''
    if isarr(a) or not isnpmatrix(a): return a
    return arrchain(a, (tolist, nparray))

def spr2arr(a: Union[SPMatrix, SPArray]) -> NPArray:
    '''from scipy.sparse --> np.array e.g. 
    `scipy.sparse.csr_matrix([...]).toarray()`'''
    if isarr(a) or not issparse(a): return a
    return arrchain(a, (toarray, ))

def dns2arr(a: Union[SPMatrix, SPArray]) -> NPArray:
    '''from scipy.sparse --> np.array e.g. 
    `np.array(scipy.sparse.csr_matrix([...]).todense().tolist())`'''
    if isarr(a) or not issparse(a): return a
    return arrchain(a, (todense, tolist, nparray, ))

def ann2arr(a: AnnData, layer: StrQ = None) -> NPArray:
    if isarr(a) or not isad(a): return a
    arr = a.layers.get(layer, a.X)
    return arrchain(arr, (toarray, ))

def mth2arr(a, *args, **kwargs) -> NPArray:    
    if isarr(a): return a
    return arrchain(a, (
            spr2arr, # `scipy.sparse.csr_matrix([...]).toarray()`
            trc2arr, # `torch.tensor([...]).detach().clone().cpu().numpy()`
            dns2arr, # `np.array(scipy.sparse.csr_matrix([...]).todense().tolist())`
            mtx2arr, # `np.array(np.matrix([...]).tolist())`
            ann2arr, # `AnnData([...]).layers.get(layer, a.X).toarray()`
            try2arr, # `np.array`
        ), *args, **kwargs
    )

def asarr(a, *args, **kwargs) -> NPArray: return mth2arr(a, *args, **kwargs)

