Skip to content

Commit 6791764

Browse files
feat: add main feat (#53)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent e7ac1c8 commit 6791764

30 files changed

+3270
-392
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ jobs:
3636
fail-fast: false
3737
matrix:
3838
python-version:
39-
- "3.9"
40-
- "3.10"
41-
- "3.11"
39+
# - "3.9"
40+
# - "3.10"
41+
# - "3.11"
4242
- "3.12"
4343
- "3.13"
4444
os:

.pre-commit-config.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,13 @@ repos:
4444
rev: v0.12.10
4545
hooks:
4646
- id: ruff
47-
args: [--fix, --exit-non-zero-on-fix]
47+
args: [--fix, --exit-non-zero-on-fix, --unsafe-fixes]
4848
- id: ruff-format
49+
- id: ruff-format
50+
types_or: [markdown, rst]
51+
require_serial: true
52+
entry: doccmd --language python --no-pad-file --command "ruff format"
53+
additional_dependencies: ["doccmd"]
4954
- repo: https://github.com/codespell-project/codespell
5055
rev: v2.4.1
5156
hooks:
@@ -54,4 +59,8 @@ repos:
5459
rev: v1.17.1
5560
hooks:
5661
- id: mypy
57-
additional_dependencies: []
62+
additional_dependencies: [strenum, attrs]
63+
- repo: https://github.com/NixOS/nixfmt
64+
rev: v1.0.0
65+
hooks:
66+
- id: nixfmt

README.md

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,118 @@
3838

3939
---
4040

41-
hyperspherical coordinates and spherical harmonics
41+
Hyperspherical coordinates in NumPy / PyTorch / JAX.
4242

4343
## Installation
4444

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

47-
`pip install ultrasphere`
47+
```shell
48+
pip install ultrasphere
49+
```
50+
51+
## Usage
52+
53+
### Spherical Coordinates ↔ Cartesian Coordinates
54+
55+
```python
56+
import ultrasphere as us
57+
import torch
58+
59+
# 1. specify the structure of spherical coordinates
60+
c = us.c_spherical()
61+
62+
# 2. get spherical coordinates from euclidean coordinates
63+
spherical = c.from_euclidean(torch.asarray([1.0, 2.0, 3.0]))
64+
print(spherical)
65+
# {'r': tensor(3.7417), 'phi': tensor(1.1071), 'theta': tensor(0.6405)}
66+
67+
# 3. get euclidean coordinates from spherical coordinates
68+
euclidean = c.to_euclidean(spherical)
69+
print(euclidean)
70+
# {0: tensor(1.), 1: tensor(2.0000), 2: tensor(3.)}
71+
```
72+
73+
### Using various spherical coordinates
74+
75+
```python
76+
c = us.polar() # polar coordinates
77+
c = us.c_spherical() # spherical coordinates
78+
c = us.standard(3) # bba coordinates
79+
c = us.standard_prime(4) # b'b'b'a coordinates
80+
c = us.hopf(3) # ccaacaa coordinates
81+
c = us.from_branching_types("cbab'a")
82+
c = us.random(10)
83+
84+
# get the branching types expression
85+
print(c.branching_types_expression_str)
86+
# ccabbab'b'ba
87+
```
88+
89+
### Drawing spherical coordinates using rooted trees (Vilenkin's method of trees)
90+
91+
#### Python
92+
93+
```python
94+
import ultrasphere as us
95+
96+
# 1. specify the structure of spherical coordinates
97+
c = us.random(10)
98+
99+
# 2. draw the rooted tree
100+
us.draw(c)
101+
```
102+
103+
#### CLI
104+
105+
```shell
106+
ultrasphere "ccabbab'b'ba"
107+
```
108+
109+
Output:
110+
111+
![ccabbab'b'ba](https://raw.githubusercontent.com/34j/ultrasphere/main/coordinates.png)
112+
113+
### Integration over sphere using spherical coordinates
114+
115+
```python
116+
import ultrasphere as us
117+
import numpy as np
118+
119+
# 1. specify the structure of spherical coordinates
120+
c = us.c_spherical()
121+
122+
# 2. integrate a function over the sphere
123+
integral = us.integrate(
124+
c, lambda spherical: spherical["theta"] ** 2 * spherical["phi"], False, 10, xp=np
125+
)
126+
print(integral)
127+
# 110.02620812972036
128+
```
129+
130+
### Random sampling
131+
132+
```python
133+
import ultrasphere as us
134+
import numpy as np
135+
136+
# 1. specify the structure of spherical coordinates
137+
c = us.c_spherical()
138+
139+
# 2. sample random points uniformly from the ball
140+
points_ball = us.random_ball(c, shape=(), xp=np)
141+
print(points_ball, np.linalg.vector_norm(points_ball))
142+
# [ 0.83999061 0.02552206 -0.29185517] 0.8896151114371893
143+
144+
# 3. sample random points uniformly from the sphere
145+
points_sphere = us.random_ball(c, shape=(), xp=np, surface=True)
146+
print(points_sphere, np.linalg.vector_norm(points_sphere))
147+
# [-0.68194186 0.71310149 -0.16260864] 1.0
148+
```
149+
150+
#### References
151+
152+
- Barthe, F., Guedon, O., Mendelson, S., & Naor, A. (2005). A probabilistic approach to the geometry of the \ell_p^n-ball. arXiv, math/0503650. Retrieved from https://arxiv.org/abs/math/0503650v1
48153

49154
## Contributors ✨
50155

coordinates.jpg

27.5 KB
Loading

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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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 both PyTorch and Numba, adds necessary paths for dynamic linking
34+
export LD_LIBRARY_PATH=${
35+
pkgs.lib.makeLibraryPath [
36+
"/run/opengl-driver" # Needed to find libGL.so, required by both PyTorch and Numba
37+
]
38+
}:$LD_LIBRARY_PATH
39+
40+
export LIBRARY_PATH=${
41+
pkgs.lib.makeLibraryPath [
42+
pkgs.graphviz
43+
]
44+
}:$LIBRARY_PATH
45+
46+
export C_INCLUDE_PATH=${
47+
pkgs.lib.makeIncludePath [
48+
pkgs.graphviz
49+
]
50+
}:$C_INCLUDE_PATH
51+
'';
52+
};
53+
};
54+
}

pyproject.toml

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ requires = [ "setuptools" ]
55
[project]
66
name = "ultrasphere"
77
version = "1.0.0"
8-
description = "hyperspherical coordinates and spherical harmonics"
8+
description = "Hyperspherical coordinates in NumPy / PyTorch / JAX."
99
readme = "README.md"
1010
license = { text = "MIT" }
1111
authors = [
1212
{ name = "34j", email = "34j.95a2p@simplelogin.com" },
1313
]
14-
requires-python = ">=3.9"
14+
requires-python = ">=3.12"
1515
classifiers = [
1616
"Development Status :: 2 - Pre-Alpha",
1717
"Intended Audience :: Developers",
@@ -26,19 +26,34 @@ classifiers = [
2626
]
2727

2828
dependencies = [
29+
"aquarel>=0.0.7",
30+
"array-api-compat>=1.12.0",
31+
"array-api-extra>=0.8.0",
32+
"matplotlib>=3.10.3",
33+
"networkx>=3.5",
2934
"rich>=10",
35+
"scipy>=1.15.3",
36+
"strenum>=0.4.15",
3037
"typer>=0.15,<1",
38+
"types-array-api>=1.1.4",
3139
]
3240
urls."Bug Tracker" = "https://github.com/34j/ultrasphere/issues"
3341
urls.Changelog = "https://github.com/34j/ultrasphere/blob/main/CHANGELOG.md"
3442
urls.documentation = "https://ultrasphere.readthedocs.io"
3543
urls.repository = "https://github.com/34j/ultrasphere"
3644
scripts.ultrasphere = "ultrasphere.cli:app"
3745

46+
[project.optional-dependencies]
47+
plot = [
48+
"pydot>=4.0.1",
49+
"pygraphviz>=1.14",
50+
]
51+
3852
[dependency-groups]
3953
dev = [
4054
"pytest>=8,<9",
4155
"pytest-cov>=6,<7",
56+
"torch>=2.7.1",
4257
]
4358
docs = [
4459
"furo>=2023.5.20; python_version>='3.11'",
@@ -51,7 +66,7 @@ docs = [
5166
line-length = 88
5267
lint.select = [
5368
"B", # flake8-bugbear
54-
"D", # flake8-docstrings
69+
# "D", # flake8-docstrings
5570
"C4", # flake8-comprehensions
5671
"S", # flake8-bandit
5772
"F", # pyflake
@@ -60,14 +75,19 @@ lint.select = [
6075
"UP", # pyupgrade
6176
"I", # isort
6277
"RUF", # ruff specific
78+
# "TID"
6379
]
6480
lint.ignore = [
6581
"D203", # 1 blank line required before class docstring
82+
"D205",
6683
"D212", # Multi-line docstring summary should start at the first line
6784
"D100", # Missing docstring in public module
6885
"D104", # Missing docstring in public package
6986
"D107", # Missing docstring in `__init__`
7087
"D401", # First line of docstring should be in imperative mood
88+
"E741",
89+
"D200",
90+
"E501"
7191
]
7292
lint.per-file-ignores."conftest.py" = [ "D100" ]
7393
lint.per-file-ignores."docs/conf.py" = [ "D100" ]

src/ultrasphere/__init__.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,48 @@
11
__version__ = "1.0.0"
2+
from ._coordinates import SphericalCoordinates
3+
from ._creation import (
4+
c_spherical,
5+
from_branching_types,
6+
hopf,
7+
polar,
8+
random,
9+
standard,
10+
standard_prime,
11+
)
12+
from ._draw import draw
13+
from ._integral import integrate, roots
14+
from ._random import random_ball
15+
from .special import (
16+
fundamental_solution,
17+
lgamma,
18+
potential_coef,
19+
shn1,
20+
shn2,
21+
sjv,
22+
syv,
23+
szv,
24+
)
25+
26+
__all__ = [
27+
"SphericalCoordinates",
28+
"c_spherical",
29+
"draw",
30+
"from_branching_types",
31+
"fundamental_solution",
32+
"hopf",
33+
"integrate",
34+
"lgamma",
35+
"polar",
36+
"potential_coef",
37+
"random",
38+
"random",
39+
"random_ball",
40+
"roots",
41+
"shn1",
42+
"shn2",
43+
"sjv",
44+
"standard",
45+
"standard_prime",
46+
"syv",
47+
"szv",
48+
]

src/ultrasphere/__main__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""Make the CLI runnable using python -m ultrasphere."""
2-
31
from .cli import app
42

53
app(prog_name="ultrasphere")

0 commit comments

Comments
 (0)