def ta_inverse_gasf(df: Typing.PatchedPandas):
    if has_indexed_columns(df):
        # todo implement recursion
        pass

    def gaf_decode(x):
        values = x._.values
        values = values.reshape(values.shape[1:])
        return _np.sqrt(((_np.diag(values) + 1) / 2)).tolist()

    return df.to_frame().apply(gaf_decode, axis=1, result_type='expand')
def ta_z_norm(df: Typing.PatchedPandas, period=200, ddof=1, demean=True, lag=0):
    if has_indexed_columns(df):
        return pd.DataFrame(
            {col: ta_z_norm(df[col], period, ddof, demean) for col in df.columns},
            index=df.index
        )

    # (value - mean) / std
    s = df.rolling(period).std(ddof=ddof)
    a = (df - df.rolling(period).mean().shift(lag)) if demean else df
    return (a / s / 4).rename(df.name)
def ta_ncdf_compress(df: Typing.PatchedPandas, period=200, lower_percentile=25, upper_percentile=75) -> Typing.PatchedPandas:
    if has_indexed_columns(df):
        return pd.DataFrame(
            {col: ta_ncdf_compress(df[col], period, lower_percentile, upper_percentile) for col in df.columns},
            index=df.index
        )

    f50 = df.rolling(period).mean().rename("f50")
    fup = df.rolling(period).apply(lambda x: np.percentile(x, upper_percentile)).rename("fup")
    flo = df.rolling(period).apply(lambda x: np.percentile(x, lower_percentile)).rename("flo")

    return pd.Series(norm.cdf(0.5 * (df - f50) / (fup - flo)) - 0.5, index=df.index, name=df.name)
def ta_inverse_gasf(df: Typing.PatchedPandas):
    if has_indexed_columns(df):
        res = _pd.DataFrame({}, index=df.index)
        for col in df.columns:
            sdf = ta_inverse_gasf(df[col])
            sdf.columns = _pd.MultiIndex.from_product([[col], sdf.columns])
            res = res.join(sdf)

        return res

    inv = np_inverse_gaf(df._.values)
    if inv.ndim == 2:
        return _pd.DataFrame(inv, index=df.index)
    else:
        if inv.shape[1] == 1:
            return _pd.DataFrame(inv[:, 0, :], index=df.index)
        else:
            raise ValueError("should never get here ..")