differintC 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
File without changes
@@ -0,0 +1,221 @@
1
+ # C++
2
+ ####################################
3
+
4
+ # Prerequisites
5
+ *.d
6
+
7
+ # Compiled Object files
8
+ *.slo
9
+ *.lo
10
+ *.o
11
+ *.obj
12
+
13
+ # Precompiled Headers
14
+ *.gch
15
+ *.pch
16
+
17
+ # Compiled Dynamic libraries
18
+ *.so
19
+ *.dylib
20
+ *.dll
21
+
22
+ # Fortran module files
23
+ *.mod
24
+ *.smod
25
+
26
+ # Compiled Static libraries
27
+ *.lai
28
+ *.la
29
+ *.a
30
+ *.lib
31
+
32
+ # Executables
33
+ *.exe
34
+ *.out
35
+ *.app
36
+
37
+ ####################################
38
+ # Python
39
+ ####################################
40
+
41
+ # Byte-compiled / optimized / DLL files
42
+ __pycache__/
43
+ *.py[cod]
44
+ *$py.class
45
+
46
+ # C extensions
47
+ *.so
48
+
49
+ # Distribution / packaging
50
+ .Python
51
+ build/
52
+ develop-eggs/
53
+ dist/
54
+ downloads/
55
+ eggs/
56
+ .eggs/
57
+ lib/
58
+ lib64/
59
+ parts/
60
+ sdist/
61
+ var/
62
+ wheels/
63
+ share/python-wheels/
64
+ *.egg-info/
65
+ .installed.cfg
66
+ *.egg
67
+ MANIFEST
68
+
69
+ # PyInstaller
70
+ # Usually these files are written by a python script from a template
71
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
72
+ *.manifest
73
+ *.spec
74
+
75
+ # Installer logs
76
+ pip-log.txt
77
+ pip-delete-this-directory.txt
78
+
79
+ # Unit test / coverage reports
80
+ htmlcov/
81
+ .tox/
82
+ .nox/
83
+ .coverage
84
+ .coverage.*
85
+ .cache
86
+ nosetests.xml
87
+ coverage.xml
88
+ *.cover
89
+ *.py,cover
90
+ .hypothesis/
91
+ .pytest_cache/
92
+ cover/
93
+
94
+ # Translations
95
+ *.mo
96
+ *.pot
97
+
98
+ # Django stuff:
99
+ *.log
100
+ local_settings.py
101
+ db.sqlite3
102
+ db.sqlite3-journal
103
+
104
+ # Flask stuff:
105
+ instance/
106
+ .webassets-cache
107
+
108
+ # Scrapy stuff:
109
+ .scrapy
110
+
111
+ # Sphinx documentation
112
+ docs/_build/
113
+
114
+ # PyBuilder
115
+ .pybuilder/
116
+ target/
117
+
118
+ # Jupyter Notebook
119
+ .ipynb_checkpoints
120
+
121
+ # IPython
122
+ profile_default/
123
+ ipython_config.py
124
+
125
+ # pyenv
126
+ # For a library or package, you might want to ignore these files since the code is
127
+ # intended to run in multiple environments; otherwise, check them in:
128
+ # .python-version
129
+
130
+ # pipenv
131
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
132
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
133
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
134
+ # install all needed dependencies.
135
+ #Pipfile.lock
136
+
137
+ # UV
138
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
139
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
140
+ # commonly ignored for libraries.
141
+ #uv.lock
142
+
143
+ # poetry
144
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
145
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
146
+ # commonly ignored for libraries.
147
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
148
+ #poetry.lock
149
+
150
+ # pdm
151
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
152
+ #pdm.lock
153
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
154
+ # in version control.
155
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
156
+ .pdm.toml
157
+ .pdm-python
158
+ .pdm-build/
159
+
160
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
161
+ __pypackages__/
162
+
163
+ # Celery stuff
164
+ celerybeat-schedule
165
+ celerybeat.pid
166
+
167
+ # SageMath parsed files
168
+ *.sage.py
169
+
170
+ # Environments
171
+ .env
172
+ .venv
173
+ env/
174
+ venv/
175
+ ENV/
176
+ env.bak/
177
+ venv.bak/
178
+
179
+ # Spyder project settings
180
+ .spyderproject
181
+ .spyproject
182
+
183
+ # Rope project settings
184
+ .ropeproject
185
+
186
+ # mkdocs documentation
187
+ /site
188
+
189
+ # mypy
190
+ .mypy_cache/
191
+ .dmypy.json
192
+ dmypy.json
193
+
194
+ # Pyre type checker
195
+ .pyre/
196
+
197
+ # pytype static type analyzer
198
+ .pytype/
199
+
200
+ # Cython debug symbols
201
+ cython_debug/
202
+
203
+ # PyCharm
204
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
205
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
206
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
207
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
208
+ #.idea/
209
+
210
+ # Ruff stuff:
211
+ .ruff_cache/
212
+
213
+ # PyPI configuration file
214
+ .pypirc
215
+
216
+ # Cursor
217
+ # Cursor is an AI-powered code editor.`.cursorignore` specifies files/directories to
218
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
219
+ # refer to https://docs.cursor.com/context/ignore-files
220
+ .cursorignore
221
+ .cursorindexingignore
@@ -0,0 +1 @@
1
+ 0.0.1: (6/30/2025) First working Version
@@ -0,0 +1,22 @@
1
+ cmake_minimum_required(VERSION 3.15)
2
+
3
+ project(differintC VERSION 0.1 LANGUAGES CXX)
4
+
5
+ set(CMAKE_CXX_STANDARD 17)
6
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
7
+
8
+ # Pybind11
9
+ include(FetchContent)
10
+ FetchContent_Declare(
11
+ pybind11
12
+ GIT_REPOSITORY https://github.com/pybind/pybind11.git
13
+ GIT_TAG v2.11.0
14
+ )
15
+ FetchContent_MakeAvailable(pybind11)
16
+
17
+ # Core C++ Library
18
+ add_library(differint_core src/differint.cpp)
19
+ target_include_directories(differint_core PUBLIC ${CMAKE_SOURCE_DIR}/include)
20
+
21
+ # Add Python bindings
22
+ add_subdirectory(python)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 parsa roshanak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.2
2
+ Name: differintC
3
+ Version: 0.0.1
4
+ Summary: Fast C++ implementation of fractional calculus operators via pybind11
5
+ Author: Parsa Roshanak
6
+ License: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: C++
17
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
18
+ Classifier: Intended Audience :: Science/Research
19
+ Project-URL: Homepage, https://github.com/iparsw/differintC
20
+ Project-URL: Repository, https://github.com/iparsw/differintC
21
+ Project-URL: Issues, https://github.com/iparsw/differintC/issues
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+
25
+ # differintC
26
+
27
+ `differintC` is a high-performance C++ library with Python bindings for computing fractional differintegrals (derivatives and integrals of arbitrary real order) using numerical methods.
28
+
29
+ This package implements optimized versions of the Riemannโ€“Liouville and Grรผnwaldโ€“Letnikov (GL) fractional differintegral operators, inspired by the original [DifferInt project](https://placeholder-link-to-original-differint-project).
30
+
31
+ > โš™๏ธ Built with modern C++17 and exposed to Python via `pybind11`, this library is significantly faster than pure-Python equivalents, especially for large arrays and high-precision needs.
32
+
33
+ ---
34
+
35
+ ## ๐Ÿ“ฆ Installation
36
+
37
+ ```bash
38
+ pip install differintC
39
+ ````
40
+
41
+ To build from source:
42
+
43
+ ```bash
44
+ git clone https://github.com/your-username/differintC-project.git
45
+ cd differintC-project
46
+ pip install .
47
+ ```
48
+
49
+ ---
50
+
51
+ ## ๐Ÿš€ Usage
52
+
53
+ ```python
54
+ from differintC import RLpoint, RL, GLpoint, GL
55
+
56
+ # Example 1: Riemannโ€“Liouville at a single point
57
+ result = RLpoint(0.5, lambda x: x**2)
58
+ print("RLpoint(0.5, x^2) =", result)
59
+
60
+ # Example 2: RL on a whole domain
61
+ import numpy as np
62
+ x = np.linspace(0, 1, 100)
63
+ f = x**2
64
+ out = RL(0.5, f)
65
+
66
+ # Example 3: Grรผnwaldโ€“Letnikov pointwise
67
+ gl_res = GLpoint(0.5, lambda x: np.sqrt(x))
68
+
69
+ # Example 4: Full array version (fastest)
70
+ gl_array = GL(0.5, lambda x: np.sqrt(x))
71
+ ```
72
+
73
+ All functions support either a NumPy array or a Python callable as the `f_name` argument.
74
+
75
+ ---
76
+
77
+ ## ๐Ÿ“š Implemented Functions
78
+
79
+ | Function | Description |
80
+ | --------- | ------------------------------------------- |
81
+ | `RLpoint` | Riemannโ€“Liouville differintegral at a point |
82
+ | `RL` | RL differintegral over a uniform domain |
83
+ | `GLpoint` | Grรผnwaldโ€“Letnikov at a point (optimized) |
84
+ | `GL` | Vectorized GL differintegral with FFT |
85
+
86
+ ---
87
+
88
+ ## โš–๏ธ License and Credits
89
+
90
+ This package was inspired by and based on the original [`DifferInt`](https://placeholder-link-to-original-differint-project) project. We thank the authors for their foundational work in fractional calculus.
91
+
92
+ Licensed under MIT.
93
+
94
+ ---
95
+
96
+ ## ๐Ÿ›  Development Notes
97
+
98
+ See the [todo list 1](https://github.com/your-username/differintC-project/issues/1) for the development roadmap and planned features. Contributions are welcome.
@@ -0,0 +1,74 @@
1
+ # differintC
2
+
3
+ `differintC` is a high-performance C++ library with Python bindings for computing fractional differintegrals (derivatives and integrals of arbitrary real order) using numerical methods.
4
+
5
+ This package implements optimized versions of the Riemannโ€“Liouville and Grรผnwaldโ€“Letnikov (GL) fractional differintegral operators, inspired by the original [DifferInt project](https://placeholder-link-to-original-differint-project).
6
+
7
+ > โš™๏ธ Built with modern C++17 and exposed to Python via `pybind11`, this library is significantly faster than pure-Python equivalents, especially for large arrays and high-precision needs.
8
+
9
+ ---
10
+
11
+ ## ๐Ÿ“ฆ Installation
12
+
13
+ ```bash
14
+ pip install differintC
15
+ ````
16
+
17
+ To build from source:
18
+
19
+ ```bash
20
+ git clone https://github.com/your-username/differintC-project.git
21
+ cd differintC-project
22
+ pip install .
23
+ ```
24
+
25
+ ---
26
+
27
+ ## ๐Ÿš€ Usage
28
+
29
+ ```python
30
+ from differintC import RLpoint, RL, GLpoint, GL
31
+
32
+ # Example 1: Riemannโ€“Liouville at a single point
33
+ result = RLpoint(0.5, lambda x: x**2)
34
+ print("RLpoint(0.5, x^2) =", result)
35
+
36
+ # Example 2: RL on a whole domain
37
+ import numpy as np
38
+ x = np.linspace(0, 1, 100)
39
+ f = x**2
40
+ out = RL(0.5, f)
41
+
42
+ # Example 3: Grรผnwaldโ€“Letnikov pointwise
43
+ gl_res = GLpoint(0.5, lambda x: np.sqrt(x))
44
+
45
+ # Example 4: Full array version (fastest)
46
+ gl_array = GL(0.5, lambda x: np.sqrt(x))
47
+ ```
48
+
49
+ All functions support either a NumPy array or a Python callable as the `f_name` argument.
50
+
51
+ ---
52
+
53
+ ## ๐Ÿ“š Implemented Functions
54
+
55
+ | Function | Description |
56
+ | --------- | ------------------------------------------- |
57
+ | `RLpoint` | Riemannโ€“Liouville differintegral at a point |
58
+ | `RL` | RL differintegral over a uniform domain |
59
+ | `GLpoint` | Grรผnwaldโ€“Letnikov at a point (optimized) |
60
+ | `GL` | Vectorized GL differintegral with FFT |
61
+
62
+ ---
63
+
64
+ ## โš–๏ธ License and Credits
65
+
66
+ This package was inspired by and based on the original [`DifferInt`](https://placeholder-link-to-original-differint-project) project. We thank the authors for their foundational work in fractional calculus.
67
+
68
+ Licensed under MIT.
69
+
70
+ ---
71
+
72
+ ## ๐Ÿ›  Development Notes
73
+
74
+ See the [todo list 1](https://github.com/your-username/differintC-project/issues/1) for the development roadmap and planned features. Contributions are welcome.
File without changes
File without changes
@@ -0,0 +1,28 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+ #include <cstddef>
5
+
6
+
7
+ namespace differint {
8
+
9
+ // Templated versions
10
+ template <typename T>
11
+ std::vector<T> GL(T alpha, const std::vector<T>& f_vals, T a, T b, std::size_t N);
12
+
13
+ template <typename T>
14
+ std::vector<T> RL(T alpha, const std::vector<T>& f_vals, T a, T b, std::size_t N);
15
+
16
+ template <typename T>
17
+ T GLpoint(T alpha, const std::vector<T>& f_vals, T a, T b, std::size_t N);
18
+
19
+ template <typename T>
20
+ T RLpoint(T alpha, const std::vector<T>& f_vals, T a, T b, std::size_t N);
21
+
22
+ // Concrete declarations for pybind11 linkage
23
+ std::vector<double> GL(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N);
24
+ std::vector<double> RL(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N);
25
+ double GLpoint(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N);
26
+ double RLpoint(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N);
27
+
28
+ }
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = [
3
+ "scikit-build-core>=0.5.1", # or latest known stable
4
+ "pybind11>=2.10",
5
+ "setuptools", # required by many tools
6
+ "wheel" # for building wheels
7
+ ]
8
+ build-backend = "scikit_build_core.build"
9
+
10
+ [project]
11
+ name = "differintC"
12
+ version = "0.0.1"
13
+ description = "Fast C++ implementation of fractional calculus operators via pybind11"
14
+ authors = [{ name = "Parsa Roshanak" }]
15
+ license = { text = "MIT" }
16
+ readme = "README.md"
17
+ requires-python = ">=3.8"
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.8",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: C++",
29
+ "Topic :: Scientific/Engineering :: Mathematics",
30
+ "Intended Audience :: Science/Research"
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/iparsw/differintC"
35
+ Repository = "https://github.com/iparsw/differintC"
36
+ Issues = "https://github.com/iparsw/differintC/issues"
37
+
38
+ [tool.scikit-build]
39
+ wheel.packages = ["python"] # The folder where your .py and .cpp binding is
40
+ build-dir = "build" # Optional: place build here
41
+ cmake.verbose = true # Optional: for easier debugging
42
+ sdist.include = ["src", "include", "python", "README.md", "LICENSE", "CMakeLists.txt"]
43
+ install.components = ["python"] # Only install the pybind11 module, not dev headers
44
+
45
+ # Optional: make version dynamic from a single file (uncomment when ready)
46
+ # [tool.setuptools.dynamic]
47
+ # version = { file = "python/_version.py" }
@@ -0,0 +1,17 @@
1
+ pybind11_add_module(differintC module.cpp ../src/differint.cpp)
2
+
3
+ target_include_directories(differintC
4
+ PRIVATE ${CMAKE_SOURCE_DIR}/include
5
+ )
6
+
7
+ target_link_libraries(differintC
8
+ PRIVATE differint_core
9
+ )
10
+
11
+ set_target_properties(differintC PROPERTIES
12
+ PREFIX ""
13
+ SUFFIX ".pyd"
14
+ )
15
+
16
+ install(TARGETS differintC
17
+ LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/Lib/site-packages)
@@ -0,0 +1,110 @@
1
+ #include <pybind11/stl.h>
2
+ #include <pybind11/pybind11.h>
3
+ #include <pybind11/numpy.h>
4
+ #include <vector>
5
+ #include <stdexcept>
6
+
7
+ namespace py = pybind11;
8
+
9
+ namespace differint {
10
+ std::vector<double> RL(double, const std::vector<double>&, double, double, size_t);
11
+ double RLpoint(double, const std::vector<double>&, double, double, size_t);
12
+ std::vector<double> GL(double, const std::vector<double>&, double, double, size_t);
13
+ double GLpoint(double, const std::vector<double>&, double, double, size_t);
14
+ }
15
+ using namespace differint;
16
+
17
+
18
+
19
+ // Helper to sample a Python callable into a std::vector<double>
20
+ template <typename Func>
21
+ std::vector<double> call_and_sample(Func&& f, double a, double b, size_t n) {
22
+ std::vector<double> vals(n);
23
+ double step = (b - a) / (n - 1);
24
+ for (size_t i = 0; i < n; ++i)
25
+ vals[i] = f(a + step * i);
26
+ return vals;
27
+ }
28
+
29
+ // Overload 1: Input is a NumPy array or list (accept py::array_t<double>)
30
+ std::vector<double> prepare_fvals(py::array_t<double> arr, size_t expected_size) {
31
+ if (arr.size() != expected_size)
32
+ throw std::runtime_error("Input array length must equal num_points");
33
+ // Copy data from NumPy array (you could do zero-copy with caution, but copying is safer here)
34
+ std::vector<double> v(arr.size());
35
+ std::memcpy(v.data(), arr.data(), sizeof(double) * arr.size());
36
+ return v;
37
+ }
38
+
39
+ // Overload 2: Input is a Python callable (py::function)
40
+ std::vector<double> prepare_fvals(py::function func, double a, double b, size_t n) {
41
+ return call_and_sample([&func](double x) {
42
+ return func(x).cast<double>();
43
+ }, a, b, n);
44
+ }
45
+
46
+
47
+
48
+
49
+
50
+ PYBIND11_MODULE(differintC, m) {
51
+ m.doc() = "Fast fractional calculus operators in C++ with Python bindings";
52
+
53
+ // RL (whole array)
54
+ m.def("RL", [](double alpha, py::object f, double domain_start, double domain_end, size_t num_points) {
55
+ // Dispatch based on type
56
+ if (py::isinstance<py::array>(f)) {
57
+ return RL(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
58
+ } else if (py::isinstance<py::function>(f)) {
59
+ return RL(alpha, prepare_fvals(f.cast<py::function>(), domain_start, domain_end, num_points), domain_start, domain_end, num_points);
60
+ } else if (py::isinstance<py::list>(f)) {
61
+ // treat list as array
62
+ return RL(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
63
+ } else {
64
+ throw std::runtime_error("Unsupported input type for function f");
65
+ }
66
+ }, py::arg("alpha"), py::arg("f"), py::arg("domain_start") = 0.0, py::arg("domain_end") = 1.0, py::arg("num_points") = 100);
67
+
68
+ // RLpoint (single point)
69
+ m.def("RLpoint", [](double alpha, py::object f, double domain_start, double domain_end, size_t num_points) {
70
+ if (py::isinstance<py::array>(f)) {
71
+ return RLpoint(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
72
+ } else if (py::isinstance<py::function>(f)) {
73
+ return RLpoint(alpha, prepare_fvals(f.cast<py::function>(), domain_start, domain_end, num_points), domain_start, domain_end, num_points);
74
+ } else if (py::isinstance<py::list>(f)) {
75
+ return RLpoint(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
76
+ } else {
77
+ throw std::runtime_error("Unsupported input type for function f");
78
+ }
79
+ }, py::arg("alpha"), py::arg("f"), py::arg("domain_start") = 0.0, py::arg("domain_end") = 1.0, py::arg("num_points") = 100);
80
+
81
+
82
+
83
+ m.def("GL", [](double alpha, py::object f, double domain_start, double domain_end, size_t num_points) {
84
+ // Dispatch based on type
85
+ if (py::isinstance<py::array>(f)) {
86
+ return GL(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
87
+ } else if (py::isinstance<py::function>(f)) {
88
+ return GL(alpha, prepare_fvals(f.cast<py::function>(), domain_start, domain_end, num_points), domain_start, domain_end, num_points);
89
+ } else if (py::isinstance<py::list>(f)) {
90
+ // treat list as array
91
+ return GL(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
92
+ } else {
93
+ throw std::runtime_error("Unsupported input type for function f");
94
+ }
95
+ }, py::arg("alpha"), py::arg("f"), py::arg("domain_start") = 0.0, py::arg("domain_end") = 1.0, py::arg("num_points") = 100);
96
+
97
+ // GLpoint (single point)
98
+ m.def("GLpoint", [](double alpha, py::object f, double domain_start, double domain_end, size_t num_points) {
99
+ if (py::isinstance<py::array>(f)) {
100
+ return GLpoint(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
101
+ } else if (py::isinstance<py::function>(f)) {
102
+ return GLpoint(alpha, prepare_fvals(f.cast<py::function>(), domain_start, domain_end, num_points), domain_start, domain_end, num_points);
103
+ } else if (py::isinstance<py::list>(f)) {
104
+ return GLpoint(alpha, prepare_fvals(f.cast<py::array_t<double>>(), num_points), domain_start, domain_end, num_points);
105
+ } else {
106
+ throw std::runtime_error("Unsupported input type for function f");
107
+ }
108
+ }, py::arg("alpha"), py::arg("f"), py::arg("domain_start") = 0.0, py::arg("domain_end") = 1.0, py::arg("num_points") = 100);
109
+
110
+ }
@@ -0,0 +1,220 @@
1
+ #include "differint.hpp"
2
+ #include <cmath>
3
+ #include <stdexcept>
4
+ #include <algorithm>
5
+
6
+ namespace differint {
7
+
8
+ template <typename T>
9
+ T RLpoint(T alpha,
10
+ const std::vector<T>& f_vals,
11
+ T domain_start,
12
+ T domain_end,
13
+ std::size_t num_points) {
14
+ if (num_points < 2) {
15
+ throw std::invalid_argument("num_points must be at least 2");
16
+ }
17
+ // Ensure domain ordering
18
+ if (domain_start > domain_end) {
19
+ std::swap(domain_start, domain_end);
20
+ }
21
+ // Check input vector length
22
+ if (f_vals.size() != num_points) {
23
+ throw std::invalid_argument("f_vals size does not match num_points");
24
+ }
25
+ // Compute step size
26
+ T step = (domain_end - domain_start) / static_cast<T>(num_points - 1);
27
+
28
+ std::size_t k = num_points - 1;
29
+ std::vector<T> coeffs(num_points);
30
+
31
+ // Case j == 0
32
+ if (k > 0) {
33
+ coeffs[0] = std::pow(static_cast<T>(k - 1), static_cast<T>(1) - alpha)
34
+ - (static_cast<T>(k) + alpha - static_cast<T>(1))
35
+ * std::pow(static_cast<T>(k), -alpha);
36
+ } else {
37
+ coeffs[0] = T(1);
38
+ }
39
+
40
+ // Case j == k
41
+ coeffs[k] = T(1);
42
+
43
+ // Other indices
44
+ for (std::size_t j = 1; j < k; ++j) {
45
+ T d = static_cast<T>(k - j);
46
+ coeffs[j] = std::pow(d + static_cast<T>(1), static_cast<T>(1) - alpha)
47
+ + std::pow(d - static_cast<T>(1), static_cast<T>(1) - alpha)
48
+ - static_cast<T>(2) * std::pow(d, static_cast<T>(1) - alpha);
49
+ }
50
+
51
+ // Compute normalization constant
52
+ T C = static_cast<T>(1) / std::tgamma(static_cast<T>(2) - alpha);
53
+
54
+ // Dot product
55
+ T result = T(0);
56
+ for (std::size_t i = 0; i < num_points; ++i) {
57
+ result += coeffs[i] * f_vals[i];
58
+ }
59
+
60
+ return C * std::pow(step, -alpha) * result;
61
+ }
62
+
63
+
64
+ // RL entire-grid implementation
65
+ template <typename T>
66
+ std::vector<T> RL(T alpha,
67
+ const std::vector<T>& f_vals,
68
+ T domain_start,
69
+ T domain_end,
70
+ std::size_t num_points) {
71
+ if (num_points < 2) {
72
+ throw std::invalid_argument("num_points must be at least 2");
73
+ }
74
+ if (domain_start > domain_end) {
75
+ std::swap(domain_start, domain_end);
76
+ }
77
+ if (f_vals.size() != num_points) {
78
+ throw std::invalid_argument("f_vals size does not match num_points");
79
+ }
80
+ T step = (domain_end - domain_start) / static_cast<T>(num_points - 1);
81
+
82
+ // Precompute coefficient matrix D
83
+ std::vector<std::vector<T>> D(num_points, std::vector<T>(num_points));
84
+ // Precompute powers v[k] = (k)^(1-alpha)
85
+ std::vector<T> v(num_points + 1);
86
+ for (std::size_t k = 0; k <= num_points; ++k) {
87
+ v[k] = std::pow(static_cast<T>(k), static_cast<T>(1) - alpha);
88
+ }
89
+
90
+ // Fill D
91
+ for (std::size_t i = 0; i < num_points; ++i) {
92
+ for (std::size_t j = 0; j < num_points; ++j) {
93
+ if (j == i) {
94
+ D[i][j] = T(1);
95
+ } else if (j == 0 && i > 0) {
96
+ T k = static_cast<T>(i);
97
+ D[i][0] = v[i - 1] - (k + alpha - static_cast<T>(1)) * std::pow(k, -alpha);
98
+ } else if (j < i) {
99
+ std::size_t k = i - j;
100
+ D[i][j] = v[k + 1] + v[k - 1] - static_cast<T>(2) * v[k];
101
+ } else {
102
+ D[i][j] = T(0);
103
+ }
104
+ }
105
+ }
106
+
107
+ // Normalize by Gamma
108
+ T C = static_cast<T>(1) / std::tgamma(static_cast<T>(2) - alpha);
109
+
110
+ // Multiply D @ f_vals
111
+ std::vector<T> result(num_points, T(0));
112
+ for (std::size_t i = 0; i < num_points; ++i) {
113
+ T acc = T(0);
114
+ for (std::size_t j = 0; j < num_points; ++j) {
115
+ acc += D[i][j] * f_vals[j];
116
+ }
117
+ result[i] = C * std::pow(step, -alpha) * acc;
118
+ }
119
+ return result;
120
+ }
121
+
122
+
123
+
124
+
125
+ // Compute GL coefficients up to order n
126
+ template <typename T>
127
+ std::vector<T> GLcoeffs(T alpha, std::size_t n) {
128
+ // b[0] = 1
129
+ std::vector<T> b(n + 1, T(1));
130
+ for (std::size_t j = 1; j <= n; ++j) {
131
+ b[j] = b[j - 1] * (static_cast<T>(-alpha) + static_cast<T>(j - 1))
132
+ / static_cast<T>(j);
133
+ }
134
+ return b;
135
+ }
136
+
137
+
138
+ // GL at a single point (endpoint)
139
+ template <typename T>
140
+ T GLpoint(T alpha,
141
+ const std::vector<T>& f_vals,
142
+ T domain_start,
143
+ T domain_end,
144
+ std::size_t num_points) {
145
+ if (num_points < 1) {
146
+ throw std::invalid_argument("num_points must be at least 1");
147
+ }
148
+ if (domain_start > domain_end) {
149
+ std::swap(domain_start, domain_end);
150
+ }
151
+ if (f_vals.size() != num_points) {
152
+ throw std::invalid_argument("f_vals size must equal num_points");
153
+ }
154
+ T step = (domain_end - domain_start) / static_cast<T>(num_points - 1);
155
+ // Compute coefficients for k = num_points - 1
156
+ std::size_t k = num_points - 1;
157
+ auto b = GLcoeffs(alpha, k);
158
+ T acc = T(0);
159
+ for (std::size_t j = 0; j <= k; ++j) {
160
+ acc += b[j] * f_vals[k - j];
161
+ }
162
+ return std::pow(step, -alpha) * acc;
163
+ }
164
+
165
+ // GL over entire grid
166
+ template <typename T>
167
+ std::vector<T> GL(T alpha,
168
+ const std::vector<T>& f_vals,
169
+ T domain_start,
170
+ T domain_end,
171
+ std::size_t num_points) {
172
+ if (num_points < 1) {
173
+ throw std::invalid_argument("num_points must be at least 1");
174
+ }
175
+ if (domain_start > domain_end) {
176
+ std::swap(domain_start, domain_end);
177
+ }
178
+ if (f_vals.size() != num_points) {
179
+ throw std::invalid_argument("f_vals size must equal num_points");
180
+ }
181
+ T step = (domain_end - domain_start) / static_cast<T>(num_points - 1);
182
+ auto b = GLcoeffs(alpha, num_points - 1);
183
+ std::vector<T> result(num_points, T(0));
184
+ for (std::size_t i = 0; i < num_points; ++i) {
185
+ T acc = T(0);
186
+ // convolution-like sum
187
+ for (std::size_t j = 0; j <= i; ++j) {
188
+ acc += b[j] * f_vals[i - j];
189
+ }
190
+ result[i] = std::pow(step, -alpha) * acc;
191
+ }
192
+ return result;
193
+ }
194
+
195
+
196
+ } // namespace differint
197
+
198
+ // Explicit instantiations for double
199
+ template std::vector<double> differint::GL<double>(double, const std::vector<double>&, double, double, std::size_t);
200
+ template std::vector<double> differint::RL<double>(double, const std::vector<double>&, double, double, std::size_t);
201
+ template double differint::GLpoint<double>(double, const std::vector<double>&, double, double, std::size_t);
202
+ template double differint::RLpoint<double>(double, const std::vector<double>&, double, double, std::size_t);
203
+ template std::vector<double> differint::GLcoeffs<double>(double, std::size_t);
204
+
205
+
206
+ // Expose concrete symbols
207
+ namespace differint {
208
+ std::vector<double> GL(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N) {
209
+ return GL<double>(alpha, f_vals, a, b, N);
210
+ }
211
+ std::vector<double> RL(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N) {
212
+ return RL<double>(alpha, f_vals, a, b, N);
213
+ }
214
+ double GLpoint(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N) {
215
+ return GLpoint<double>(alpha, f_vals, a, b, N);
216
+ }
217
+ double RLpoint(double alpha, const std::vector<double>& f_vals, double a, double b, std::size_t N) {
218
+ return RLpoint<double>(alpha, f_vals, a, b, N);
219
+ }
220
+ }
File without changes
File without changes
@@ -0,0 +1,84 @@
1
+ # Todo List 1 (6/30/2025) (AI Generated)
2
+
3
+ ---
4
+
5
+ ### โœ… Immediate TODOs (essential for adding new functions)
6
+
7
+ These are required for each additional fractional differintegral method you want to port:
8
+
9
+ #### For each new C++ function:
10
+
11
+ 1. **`include/differint/differint.hpp`**
12
+
13
+ * Add the `template <typename T> T|std::vector<T> FunctionName(...)` declaration.
14
+
15
+ 2. **`src/differint/differint.cpp`**
16
+
17
+ * Implement the function.
18
+ * Add `template` instantiation at the bottom:
19
+ `template double FunctionName<double>(...);`
20
+
21
+ 3. **`python/module.cpp`**
22
+
23
+ * Bind the function to Python using `m.def(...)`.
24
+
25
+ 4. **Optional: `src/differint/sanity.cpp`**
26
+
27
+ * Add a manual C++ test to verify numeric accuracy.
28
+
29
+ ---
30
+
31
+ ### ๐Ÿ“ฆ Packaging & Distribution
32
+
33
+ * ~~**Add `README.md` and `LICENSE` files** in the root for PyPI display.~~
34
+ * [ ] **Set versioning strategy** (e.g., `semver`, calendar versioning).
35
+ * ~~**Add a `setup.cfg` or more advanced `pyproject.toml`** with classifiers, long description from `README.md`, etc.~~
36
+
37
+ ---
38
+
39
+ ### ๐Ÿงช Usability Improvements
40
+
41
+ * [ ] **Support `Callable` Python functions directly** via `py::function` overloads.
42
+
43
+ * This will let users call C++ methods with `lambda x: ...` directly.
44
+ * Requires defining Python overloads (already mostly done).
45
+
46
+ * [ ] **Add NumPy array support directly via `py::array_t<double>`**:
47
+
48
+ * Improves interop and reduces unnecessary Python โ†’ C++ copies.
49
+
50
+ ---
51
+
52
+ ### ๐Ÿงน Code Quality & Developer Experience
53
+
54
+ * [ ] **Add CMake options to toggle building:**
55
+
56
+ * `DIFFERINT_BUILD_SANITY`
57
+ * `DIFFERINT_BUILD_PYTHON`
58
+ * Cleaner, configurable builds.
59
+
60
+ * [ ] **Write a test script in Python**:
61
+
62
+ * `tests/test_rl.py` with assertions
63
+ * Could use `pytest` later, but start with simple scripts
64
+
65
+ * [ ] **Add Doxygen-style comments** to your headers
66
+
67
+ * Enables future documentation generation.
68
+
69
+ ---
70
+
71
+ ### ๐Ÿ“˜ Longer-Term / Optional
72
+
73
+ * [ ] **Benchmarking tools** for RL vs GL methods.
74
+ * [ ] **CI/CD automation** (GitHub Actions or similar for testing + PyPI deploy).
75
+ * [ ] **Optional GUI or CLI** interface for experimentation.
76
+ * [ ] **Add support for complex-valued functions** if useful.
77
+ * [ ] **Support mixed precision or `float`, `long double`**, if needed.
78
+
79
+ ---
80
+
81
+ Would you like to continue by:
82
+
83
+ * Implementing the next function (e.g., `GLpoint`)
84
+ * Or tackling one of the improvements from above (e.g., better Python interop)?