Skip to content

Commit 43a01bb

Browse files
authored
feat: add main feat (#11)
1 parent f697e12 commit 43a01bb

File tree

13 files changed

+1250
-1028
lines changed

13 files changed

+1250
-1028
lines changed

.codespellrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[codespell]
2-
ignore-words-list = socio-economic
2+
ignore-words-list = socio-economic, numer

.github/workflows/ci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ jobs:
3636
fail-fast: false
3737
matrix:
3838
python-version:
39-
- "3.10"
40-
- "3.11"
4139
- "3.12"
4240
- "3.13"
4341
- "3.14"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,4 @@ cython_debug/
173173

174174
# PyPI configuration file
175175
.pypirc
176+
*.png

README.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,66 @@ Monte-Carlo Nystrom method in NumPy / PyTorch
4444

4545
Install this via pip (or your favourite package manager):
4646

47-
`pip install montecarlo-nystrom`
47+
```shell
48+
pip install montecarlo-nystrom
49+
```
50+
51+
## Usage
52+
53+
Solve integral equations of the second kind of the following form.
54+
55+
$\forall d \in \mathbb{N}.$
56+
$\forall \Omega \in \mathbb{R}^d [\Omega \text{ is bounded Lipschitz}].$
57+
$`\forall p \in L^\infty(\Omega, {\mathbb{R}}_{\geq 0}) [\int_\Omega p(y) dy = 1].`$
58+
$\forall f, z \in L^2(\Omega,\mathbb{C}).$
59+
$\forall k \in L^2(\Omega,L^2(\Omega,\mathbb{C}))$
60+
$[z(y) + \int_\Omega k(y, y') z(y') p(y') dy' = f(y)].$
61+
62+
Let $N \in \mathbb{N}$, $(y_i)_{i=1}^N$ be i.i.d. samples drawn from $p$.
63+
64+
Let $(z_{N,i})_{i=1}^N$ be the solution of the linear system
65+
66+
$$
67+
z_{N,i} + \frac{1}{N} \sum_{j=1}^N k(y_i, y_j) z_{N,j} = f(y_i)
68+
\quad i \in \{1, \ldots, N\}
69+
$$
70+
71+
and
72+
73+
$$
74+
z_N(y) := f(y) - \frac{1}{N} \sum_{i=1}^N k(y, y_i) z_{N,i}
75+
\quad y \in \Omega
76+
$$
77+
78+
Then $z_N$ would approximate $z$ as $N \to \infty$.
79+
80+
The below example solves the case where $d = 1$, $\Omega = [0, 1]$, $p$ (`random_samples`) is the uniform distribution on $[0, 1]$, $k(x, y) = \|x - y\|^{-0.4}$ (`kernel`), and $f(x) = 1$ (`rhs`), and evaluates the solution at $x = (0.5,)$.
81+
82+
```python
83+
>>> import numpy as np
84+
>>> from montecarlo_nystrom import montecarlo_nystrom
85+
>>> rng = np.random.default_rng(0)
86+
>>> def random_samples(n):
87+
... return rng.uniform(0, 1, size=(n, 1))
88+
>>> def kernel(x, y):
89+
... return np.linalg.vector_norm(x - y, axis=-1) ** -0.4
90+
>>> def rhs(x):
91+
... x0 = x[..., 0]
92+
... return np.ones_like(x0)
93+
>>> z_N = montecarlo_nystrom(
94+
... random_samples=random_samples,
95+
... kernel=kernel,
96+
... rhs=rhs,
97+
... n=100,
98+
... n_mean=10,
99+
... )
100+
>>> np.round(z_N(np.asarray((0.5,))), 6) # Evaluate at x=0.5
101+
np.float64(0.272957)
102+
```
103+
104+
## References
105+
106+
- Feppon, F., & Ammari, H. (2022). Analysis of a Monte-Carlo Nystrom Method. SIAM J. Numer. Anal. Retrieved from https://epubs.siam.org/doi/10.1137/21M1432338
48107

49108
## Contributors ✨
50109

conftest.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from sybil import Sybil
2+
from sybil.evaluators.doctest import NUMBER
3+
from sybil.parsers.myst import DocTestDirectiveParser as MarkdownDocTestParser
4+
from sybil.parsers.myst import PythonCodeBlockParser as MarkdownPythonCodeBlockParser
5+
from sybil.parsers.myst import SkipParser as MarkdownSkipParser
6+
from sybil.parsers.rest import DocTestParser as ReSTDocTestParser
7+
from sybil.parsers.rest import PythonCodeBlockParser as ReSTPythonCodeBlockParser
8+
from sybil.parsers.rest import SkipParser as ReSTSkipParser
9+
10+
markdown_examples = Sybil(
11+
parsers=[
12+
MarkdownDocTestParser(NUMBER),
13+
MarkdownPythonCodeBlockParser(doctest_optionflags=NUMBER),
14+
MarkdownSkipParser(),
15+
],
16+
patterns=["*.md"],
17+
)
18+
19+
rest_examples = Sybil(
20+
parsers=[
21+
ReSTDocTestParser(NUMBER),
22+
ReSTPythonCodeBlockParser(),
23+
ReSTSkipParser(),
24+
],
25+
patterns=["*.py", "*.rst"],
26+
)
27+
28+
pytest_collect_file = (markdown_examples + rest_examples).pytest()

docs/conf.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@
2525
# ones.
2626
extensions = [
2727
"myst_parser",
28-
"sphinx.ext.napoleon",
28+
"sphinx.ext.duration",
2929
"sphinx.ext.autodoc",
3030
"sphinx.ext.viewcode",
31+
"sphinx.ext.mathjax",
32+
"sphinx.ext.napoleon",
33+
"sphinx_math_dollar",
34+
]
35+
myst_enable_extensions = [
36+
"amsmath",
37+
"dollarmath",
3138
]
32-
napoleon_google_docstring = False
3339

3440
# The suffix of source filenames.
3541
source_suffix = [

flake.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
description = "A flake providing a dev shell for Numba with CUDA without installing Numba via nix. Also supports PyTorch yet being minimal for Numba with CUDA.";
3+
4+
inputs = {
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6+
};
7+
8+
outputs =
9+
{ self, nixpkgs }:
10+
let
11+
system = "x86_64-linux"; # Adjust if needed
12+
pkgs = import nixpkgs {
13+
system = system;
14+
config.allowUnfree = true;
15+
};
16+
cudatookit-with-cudart-to-lib64 = pkgs.symlinkJoin {
17+
name = "cudatoolkit";
18+
paths = with pkgs.cudaPackages; [
19+
cudatoolkit
20+
(pkgs.lib.getStatic cuda_cudart)
21+
];
22+
postBuild = ''
23+
ln -s $out/lib $out/lib64
24+
'';
25+
};
26+
in
27+
{
28+
devShells.${system}.default = pkgs.mkShell {
29+
shellHook = ''
30+
# Required for both PyTorch and Numba to find CUDA
31+
export CUDA_PATH=${cudatookit-with-cudart-to-lib64}
32+
33+
# Required for numba-cuda Python package
34+
export NUMBA_CUDA_INCLUDE_PATH=${cudatookit-with-cudart-to-lib64}/include
35+
36+
# cuda.bindings.nvjitlink.nvJitLinkError: ERROR_INTERNAL (6)
37+
# Linker error log: ERROR 4 in nvvmAddNVVMContainerToProgram, may need newer version of nvJitLink library
38+
export NUMBA_CUDA_USE_NVIDIA_BINDING=0
39+
40+
# Required for both PyTorch and Numba, adds necessary paths for dynamic linking
41+
export LD_LIBRARY_PATH=${
42+
pkgs.lib.makeLibraryPath [
43+
"/run/opengl-driver" # Needed to find libGL.so, required by both PyTorch and Numba
44+
]
45+
}:$LD_LIBRARY_PATH
46+
'';
47+
};
48+
};
49+
}

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ license = "MIT"
1111
authors = [
1212
{ name = "ultrasphere-dev", email = "34j.95a2p@simplelogin.com" },
1313
]
14-
requires-python = ">=3.10"
14+
requires-python = ">=3.12"
1515
classifiers = [
1616
"Development Status :: 2 - Pre-Alpha",
1717
"Intended Audience :: Developers",
@@ -27,10 +27,12 @@ classifiers = [
2727

2828
dependencies = [
2929
"array-api-compat>=1.12.0",
30+
"array-api-extra>=0.9.0",
3031
"cyclopts>=3.24.0",
3132
"matplotlib>=3.10.7",
3233
"numpy>=2.2.6",
3334
"types-array-api>=1.1.4",
35+
"ultrasphere>=2.0.4",
3436
]
3537
urls."Bug Tracker" = "https://github.com/ultrasphere-dev/montecarlo-nystrom/issues"
3638
urls.Changelog = "https://github.com/ultrasphere-dev/montecarlo-nystrom/blob/main/CHANGELOG.md"
@@ -43,12 +45,14 @@ dev = [
4345
"coverage",
4446
"pytest>=9,<10",
4547
"pytest-cov>=7,<8",
48+
"sybil>=9.3.0",
4649
]
4750
docs = [
4851
"furo>=2023.5.20; python_version>='3.11'",
4952
"myst-parser>=0.16; python_version>='3.11'",
5053
"sphinx>=4; python_version>='3.11'",
5154
"sphinx-autobuild>=2025,<2026; python_version>='3.11'",
55+
"sphinx-math-dollar>=1.2.1",
5256
]
5357

5458
[tool.ruff]

src/montecarlo_nystrom/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
__version__ = "1.0.0"
2+
from ._main import montecarlo_nystrom
3+
4+
__all__ = ["montecarlo_nystrom"]

0 commit comments

Comments
 (0)