From d582789fcbc12869998dcde6873290bfe1ef07f6 Mon Sep 17 00:00:00 2001 From: William Setterberg Date: Wed, 31 Dec 2025 11:37:26 -0600 Subject: [PATCH 1/3] gitignore --- .gitignore | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f171fe2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,224 @@ +# Auto-generated code +dcca.c +dfa.c +ht.c +mfdcca.c +mfdfa.c + +# generic Python gitignore +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml From bb7cfa76078251607fce15b704ed69a156285524 Mon Sep 17 00:00:00 2001 From: William Setterberg Date: Wed, 31 Dec 2025 11:37:40 -0600 Subject: [PATCH 2/3] update pyx types to not depend on numpy --- fathon/dcca.pyx | 30 ++++++++++++++++-------------- fathon/dfa.pyx | 12 +++++++----- fathon/ht.pyx | 9 +++++---- fathon/mfdcca.pyx | 12 ++++++------ fathon/mfdfa.pyx | 13 +++++++------ 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/fathon/dcca.pyx b/fathon/dcca.pyx index a2991a0..32f84ed 100755 --- a/fathon/dcca.pyx +++ b/fathon/dcca.pyx @@ -16,6 +16,8 @@ #cython: language_level=3 +from libc.stdint cimport int64_t + import numpy as np cimport numpy as np cimport cython @@ -98,10 +100,10 @@ cdef class DCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cdef cy_flucCompute(self, np.ndarray[np.float64_t, ndim=1, mode='c'] vects1, np.ndarray[np.float64_t, ndim=1, mode='c'] vects2, np.ndarray[int, ndim=1, mode='c'] vecn, np.ndarray[np.float64_t, ndim=1, mode='c'] vecf, int polOrd, bint absVals, bint overlap, bint revSeg): + cdef cy_flucCompute(self, np.ndarray[double, ndim=1, mode='c'] vects1, np.ndarray[double, ndim=1, mode='c'] vects2, np.ndarray[int, ndim=1, mode='c'] vecn, np.ndarray[double, ndim=1, mode='c'] vecf, int polOrd, bint absVals, bint overlap, bint revSeg): cdef int nLen, tsLen cdef Py_ssize_t i, j - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] t + cdef np.ndarray[double, ndim=1, mode='c'] t nLen = len(vecn) tsLen = len(vects1) @@ -131,7 +133,7 @@ cdef class DCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cpdef computeFlucVec(self, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, int polOrd=1, bint absVals=True, bint overlap=False, bint revSeg=False): + cpdef computeFlucVec(self, np.ndarray[int64_t, ndim=1, mode='c'] winSizes, int polOrd=1, bint absVals=True, bint overlap=False, bint revSeg=False): """Computation of the fluctuations in each window. Parameters @@ -179,12 +181,12 @@ cdef class DCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cdef computeFlucVecSameTs(self, np.ndarray[np.float64_t, ndim=1, mode='c'] vec, np.ndarray[int, ndim=1, mode='c'] wins, int polOrd, bint overlap, bint revSeg): + cdef computeFlucVecSameTs(self, np.ndarray[double, ndim=1, mode='c'] vec, np.ndarray[int, ndim=1, mode='c'] wins, int polOrd, bint overlap, bint revSeg): cdef int nLen, tsLen = len(vec) cdef Py_ssize_t i, j - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] F_same + cdef np.ndarray[double, ndim=1, mode='c'] F_same cdef np.ndarray[int, ndim=1, mode='c'] vecn - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] t + cdef np.ndarray[double, ndim=1, mode='c'] t vecn = np.array(wins, dtype=ctypes.c_int) nLen = len(vecn) @@ -229,7 +231,7 @@ cdef class DCCA: Intercept of the fit. """ cdef int start, end - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] log_fit + cdef np.ndarray[double, ndim=1, mode='c'] log_fit if len(self.n) > 1: if self.isComputed: @@ -261,7 +263,7 @@ cdef class DCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cpdef multiFitFlucVec(self, np.ndarray[np.int_t, ndim=2, mode='c'] limitsList, float logBase=np.e, bint verbose=False): + cpdef multiFitFlucVec(self, np.ndarray[long, ndim=2, mode='c'] limitsList, float logBase=np.e, bint verbose=False): """Fit of the fluctuations values in different intervals at the same time. Parameters @@ -282,7 +284,7 @@ cdef class DCCA: """ cdef Py_ssize_t i cdef int limLen = len(limitsList) - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] list_H_intercept, list_H + cdef np.ndarray[double, ndim=1, mode='c'] list_H_intercept, list_H if self.isComputed: list_H = np.zeros((limLen, ), dtype=float) @@ -304,7 +306,7 @@ cdef class DCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cpdef computeRho(self, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, int polOrd=1, bint verbose=False, bint overlap=False, bint revSeg=False): + cpdef computeRho(self, np.ndarray[int64_t, ndim=1, mode='c'] winSizes, int polOrd=1, bint verbose=False, bint overlap=False, bint revSeg=False): """Computation of the cross-correlation index in each window. Parameters @@ -330,7 +332,7 @@ cdef class DCCA: """ cdef Py_ssize_t i cdef int nLen, tsLen = len(self.tsVec1) - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] Fxy, Fxx, Fyy + cdef np.ndarray[double, ndim=1, mode='c'] Fxy, Fxx, Fyy if polOrd < 1: raise ValueError('Error: Polynomial order must be greater than 0.') @@ -368,7 +370,7 @@ cdef class DCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cpdef rhoThresholds(self, int L, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, int nSim, double confLvl, int polOrd=1, bint verbose=False): + cpdef rhoThresholds(self, int L, np.ndarray[int64_t, ndim=1, mode='c'] winSizes, int nSim, double confLvl, int polOrd=1, bint verbose=False): """Computation of the cross-correlation index's confidence levels in each window. Parameters @@ -396,8 +398,8 @@ cdef class DCCA: numpy ndarray Array containing the second confidence interval. """ - cdef np.ndarray[np.float64_t, ndim=2, mode='c'] rho_all - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] ran1, ran2, vecfx, vecfy, vecfxy + cdef np.ndarray[double, ndim=2, mode='c'] rho_all + cdef np.ndarray[double, ndim=1, mode='c'] ran1, ran2, vecfx, vecfy, vecfxy cdef int nLen if polOrd < 1: diff --git a/fathon/dfa.pyx b/fathon/dfa.pyx index 5fa055c..7d909af 100755 --- a/fathon/dfa.pyx +++ b/fathon/dfa.pyx @@ -16,6 +16,8 @@ #cython: language_level=3 +from libc.stdint cimport int64_t + import numpy as np cimport numpy as np cimport cython @@ -72,10 +74,10 @@ cdef class DFA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cdef cy_flucCompute(self, np.ndarray[np.float64_t, ndim=1, mode='c'] vects, np.ndarray[int, ndim=1, mode='c'] vecn, np.ndarray[np.float64_t, ndim=1, mode='c'] vecf, int polOrd, bint revSeg, bint unbiased): + cdef cy_flucCompute(self, np.ndarray[double, ndim=1, mode='c'] vects, np.ndarray[int, ndim=1, mode='c'] vecn, np.ndarray[double, ndim=1, mode='c'] vecf, int polOrd, bint revSeg, bint unbiased): cdef int nLen, tsLen cdef Py_ssize_t i, j - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] t + cdef np.ndarray[double, ndim=1, mode='c'] t nLen = len(vecn) tsLen = len(vects) @@ -160,7 +162,7 @@ cdef class DFA: Intercept of the fit. """ cdef int start, end - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] log_fit + cdef np.ndarray[double, ndim=1, mode='c'] log_fit if len(self.n) > 1: if self.isComputed: @@ -192,7 +194,7 @@ cdef class DFA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cpdef multiFitFlucVec(self, np.ndarray[np.int_t, ndim=2, mode='c'] limitsList, float logBase=np.e, bint verbose=False): + cpdef multiFitFlucVec(self, np.ndarray[int64_t, ndim=2, mode='c'] limitsList, float logBase=np.e, bint verbose=False): """Fit of the fluctuations values in different intervals at the same time. Parameters @@ -213,7 +215,7 @@ cdef class DFA: """ cdef Py_ssize_t i cdef int limLen = len(limitsList) - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] list_H, list_H_intercept + cdef np.ndarray[double, ndim=1, mode='c'] list_H, list_H_intercept if self.isComputed: list_H = np.zeros((limLen, ), dtype=float) diff --git a/fathon/ht.pyx b/fathon/ht.pyx index 058170c..987d113 100755 --- a/fathon/ht.pyx +++ b/fathon/ht.pyx @@ -62,12 +62,12 @@ cdef class HT: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cdef cy_computeHt(self, np.ndarray[int, ndim=1, mode='c'] scales, int polOrd, int mfdfaPolOrd, np.ndarray[np.float64_t, ndim=1, mode='c'] q0Fit, bint verbose): + cdef cy_computeHt(self, np.ndarray[int, ndim=1, mode='c'] scales, int polOrd, int mfdfaPolOrd, np.ndarray[double, ndim=1, mode='c'] q0Fit, bint verbose): cdef int htRowLen, tsLen, scale cdef Py_ssize_t i, j cdef double H0, H0_intercept - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] vects, vecht - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] t + cdef np.ndarray[double, ndim=1, mode='c'] vects, vecht + cdef np.ndarray[double, ndim=1, mode='c'] t tsLen = len(self.tsVec) htRowLen = tsLen - min(scales) + 1 @@ -78,7 +78,8 @@ cdef class HT: pymfdfa = mfdfa.MFDFA(self.tsVec) _, _ = pymfdfa.computeFlucVec(fu.linRangeByCount(10, int(tsLen / 4), count=20), 0.0, revSeg=True, polOrd=mfdfaPolOrd) - H0, H0_intercept = pymfdfa.fitFlucVec(verbose=verbose) + ret = pymfdfa.fitFlucVec(verbose=verbose) + H0, H0_intercept = ret[0][0], ret[1][0] else: if verbose: print('Variable q0Fit assigned, variable mfdfaPolOrd will be ignored.') diff --git a/fathon/mfdcca.pyx b/fathon/mfdcca.pyx index 0a12a76..794746b 100755 --- a/fathon/mfdcca.pyx +++ b/fathon/mfdcca.pyx @@ -90,12 +90,12 @@ cdef class MFDCCA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cdef cy_computeFlucVec(self, int tsLen, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, np.ndarray[np.float64_t, ndim=1, mode='c'] q_list, int polOrd, bint revSeg): + cdef cy_computeFlucVec(self, int tsLen, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, np.ndarray[double, ndim=1, mode='c'] q_list, int polOrd, bint revSeg): cdef Py_ssize_t j cdef int nLen, q_list_len - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] mtxf, vects1, vects2 + cdef np.ndarray[double, ndim=1, mode='c'] mtxf, vects1, vects2 cdef np.ndarray[int, ndim=1, mode='c'] vecn - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] t + cdef np.ndarray[double, ndim=1, mode='c'] t self.qList = q_list vecn = np.array(winSizes, dtype=ctypes.c_int) @@ -189,7 +189,7 @@ cdef class MFDCCA: """ cdef int start, end, qLen cdef Py_ssize_t i - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] log_fit, list_H_intercept + cdef np.ndarray[double, ndim=1, mode='c'] log_fit, list_H_intercept if len(self.n) > 1: if self.isComputed: @@ -236,7 +236,7 @@ cdef class MFDCCA: numpy ndarray Mass exponents. """ - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] tau + cdef np.ndarray[double, ndim=1, mode='c'] tau if self.isComputed: tau = self.listH * self.qList - 1 @@ -257,7 +257,7 @@ cdef class MFDCCA: numpy ndarray Multifractal spectrum. """ - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] tau, alpha, mfSpect + cdef np.ndarray[double, ndim=1, mode='c'] tau, alpha, mfSpect if self.isComputed: if len(self.qList) > 1: diff --git a/fathon/mfdfa.pyx b/fathon/mfdfa.pyx index 268bf92..2340901 100755 --- a/fathon/mfdfa.pyx +++ b/fathon/mfdfa.pyx @@ -77,12 +77,12 @@ cdef class MFDFA: @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) - cdef cy_computeFlucVec(self, int tsLen, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, np.ndarray[np.float64_t, ndim=1, mode='c'] q_list, int polOrd, bint revSeg): + cdef cy_computeFlucVec(self, int tsLen, np.ndarray[np.int64_t, ndim=1, mode='c'] winSizes, np.ndarray[double, ndim=1, mode='c'] q_list, int polOrd, bint revSeg): cdef Py_ssize_t j cdef int nLen, q_list_len - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] mtxf, vects + cdef np.ndarray[double, ndim=1, mode='c'] mtxf, vects cdef np.ndarray[int, ndim=1, mode='c'] vecn - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] t + cdef np.ndarray[double, ndim=1, mode='c'] t self.qList = q_list vecn = np.array(winSizes, dtype=ctypes.c_int) @@ -175,7 +175,7 @@ cdef class MFDFA: """ cdef int start, end, qLen cdef Py_ssize_t i - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] log_fit, list_H_intercept + cdef np.ndarray[double, ndim=1, mode='c'] log_fit, list_H_intercept if len(self.n) > 1: if self.isComputed: @@ -205,6 +205,7 @@ cdef class MFDFA: if verbose: print('Fit result for q = {:.2f}: H intercept = {:.2f}, H = {:.2f}'.format(self.qList[i], list_H_intercept[i], self.listH[i])) + print(self.listH, list_H_intercept) return self.listH, list_H_intercept else: print('Nothing to fit, fluctuations vector has not been computed yet.') @@ -222,7 +223,7 @@ cdef class MFDFA: numpy ndarray Mass exponents. """ - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] tau + cdef np.ndarray[double, ndim=1, mode='c'] tau if self.isComputed: tau = self.listH * self.qList - 1 @@ -243,7 +244,7 @@ cdef class MFDFA: numpy ndarray Multifractal spectrum. """ - cdef np.ndarray[np.float64_t, ndim=1, mode='c'] tau, alpha, mfSpect + cdef np.ndarray[double, ndim=1, mode='c'] tau, alpha, mfSpect if self.isComputed: if len(self.qList) > 1: From 592002ae55d3f500f54dad8759ad00edf4678c5f Mon Sep 17 00:00:00 2001 From: William Setterberg Date: Wed, 31 Dec 2025 11:39:00 -0600 Subject: [PATCH 3/3] ht example: fix subplot --- examples/ht_example.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/ht_example.py b/examples/ht_example.py index 24e45a7..b788875 100755 --- a/examples/ht_example.py +++ b/examples/ht_example.py @@ -3,7 +3,7 @@ import fathon from fathon import fathonUtils as fu -print('This is fathon v{}'.format(fathon.__version__)) +print("This is fathon v{}".format(fathon.__version__)) a = np.random.randn(10000) b = np.random.randn(10000) @@ -17,18 +17,22 @@ mfdfaPolOrd = 1 polOrd = 1 -ht = pyht.computeHt(scales, mfdfaPolOrd=mfdfaPolOrd, polOrd=polOrd) +ht = pyht.computeHt(scales, mfdfaPolOrd=mfdfaPolOrd, polOrd=polOrd, verbose=True) -plt.rc('font', size=14) +plt.rc("font", size=14) plt.figure(figsize=(10, 6)) -w = 3 if len(scales) >= 3 else len(scales) -h = np.ceil(len(scales)/3) +w = int(3 if len(scales) >= 3 else len(scales)) +h = int(np.ceil(len(scales) / 3)) for i, scale in enumerate(scales): - plt.subplot(h, w, i+1) - plt.plot(np.arange(1, len(ht[i, 0:len(a)-scale+1])+1), ht[i, 0:len(a)-scale+1], - 'r-', label='scale = {}'.format(scale)) - plt.xlabel('window number', fontsize=14) - plt.ylabel('$h_t$', fontsize=14) + plt.subplot(h, w, i + 1) + plt.plot( + np.arange(1, len(ht[i, 0 : len(a) - scale + 1]) + 1), + ht[i, 0 : len(a) - scale + 1], + "r-", + label="scale = {}".format(scale), + ) + plt.xlabel("window number", fontsize=14) + plt.ylabel("$h_t$", fontsize=14) plt.legend(loc=0, fontsize=14) plt.subplots_adjust(hspace=0.6, wspace=0.3) plt.show()