Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
bcf4f21
Create CHANGELOG.md
VoxleOne May 14, 2025
8353ccc
Create ph.py
VoxleOne May 14, 2025
91d0f5d
Add files via upload
VoxleOne May 14, 2025
8d70b53
Delete spinstep/utils/ph.py
VoxleOne May 14, 2025
8025844
Update discrete.py
VoxleOne May 14, 2025
86b0387
Update discrete.py
VoxleOne May 14, 2025
dc3563a
Update __init.py__
VoxleOne May 14, 2025
f6cd07a
Update demo.py
VoxleOne May 14, 2025
7cea844
Update demo1_tree_traversal.py
VoxleOne May 14, 2025
3753073
Update demo2_full_depth_traversal.py
VoxleOne May 14, 2025
482540a
Update demo3_spatial_traversal.py
VoxleOne May 14, 2025
ddf88a6
Update demo4_discrete_traversal.py
VoxleOne May 14, 2025
0a9862f
Update discrete_iterator.py
VoxleOne May 14, 2025
eb27c57
Update node.py
VoxleOne May 14, 2025
cdc8846
Update quaternion_utils.py
VoxleOne May 14, 2025
3837829
Update node.py
VoxleOne May 14, 2025
39ecfd6
Update traversal.py
VoxleOne May 14, 2025
a4c98fa
Update test.py
VoxleOne May 14, 2025
3d2ed58
Add files via upload
VoxleOne May 15, 2025
b051c23
Rename docs_07_troubleshooting_Version2.md to 07_troubleshooting.md
VoxleOne May 15, 2025
09ef68d
Add files via upload
VoxleOne May 15, 2025
0948c95
Rename docs_api_Version2.md to 08_API_Reference.md
VoxleOne May 15, 2025
079acbb
Update README.md
VoxleOne May 15, 2025
a6723c4
Create ph
VoxleOne May 15, 2025
86078c4
Add files via upload
VoxleOne May 15, 2025
83e71a2
Delete examples/ph
VoxleOne May 15, 2025
d85413d
Rename docs_08_cuda_support_Version2.md to 10_cuda_support.md
VoxleOne May 15, 2025
757fc1c
Delete examples/10_cuda_support.md
VoxleOne May 15, 2025
6e553ae
Add files via upload
VoxleOne May 15, 2025
9d5ca69
Rename 08_API_Reference.md to 09_API_Reference.md
VoxleOne May 15, 2025
098b09e
Rename docs_08_cuda_support_Version2.md to 09_cuda_support.md
VoxleOne May 15, 2025
315f582
Rename 09_cuda_support.md to 08_cuda_support.md
VoxleOne May 15, 2025
f03b345
Rename 08_cuda_support.md to 07_cuda_support.md
VoxleOne May 15, 2025
715007f
Rename 07_troubleshooting.md to 08_troubleshooting.md
VoxleOne May 15, 2025
9ad6c88
Update index.md
VoxleOne May 15, 2025
f046552
Update README.md
VoxleOne May 15, 2025
1fded87
Update README.md
VoxleOne May 15, 2025
befa98c
Update README.md
VoxleOne May 15, 2025
5e1cbb7
Create gpu_orientation_matching.py
VoxleOne May 15, 2025
2af674d
Update gpu_orientation_matching.py
VoxleOne May 15, 2025
3588bba
Update and rename test.py to test_spinstep.py
VoxleOne May 15, 2025
064af29
Create ci.yml
VoxleOne May 15, 2025
1fa5d7f
Update pyproject.toml
VoxleOne May 15, 2025
f9735b1
Update pyproject.toml
VoxleOne May 15, 2025
5f2c877
Update pyproject.toml
VoxleOne May 15, 2025
d2b7325
Update pyproject.toml
VoxleOne May 15, 2025
b098fa0
Update pyproject.toml
VoxleOne May 15, 2025
ec2d775
Delete pyproject.toml
VoxleOne May 15, 2025
2caad9c
Update pyproject.toml
VoxleOne May 15, 2025
8008ae8
Update pyproject.toml
VoxleOne May 15, 2025
1709612
Update pyproject.toml
VoxleOne May 15, 2025
74a19ad
Update pyproject.toml
VoxleOne May 15, 2025
bfa638a
Update pyproject.toml
VoxleOne May 15, 2025
fd0c038
Update pyproject.toml
VoxleOne May 15, 2025
b5dd4f4
Update ci.yml
VoxleOne May 15, 2025
b7b0c9e
Update pyproject.toml
VoxleOne May 15, 2025
f24d795
Update pyproject.toml
VoxleOne May 15, 2025
81718f7
Update pyproject.toml
VoxleOne May 15, 2025
46ab34d
Update pyproject.toml
VoxleOne May 15, 2025
6f47bb8
Update pyproject.toml
VoxleOne May 15, 2025
b2c083c
Update pyproject.toml
VoxleOne May 15, 2025
51e1cf3
Delete pyproject.toml
VoxleOne May 15, 2025
f58e1b9
Add files via upload
VoxleOne May 16, 2025
74d43bf
Rename test_discrete_traversal_Version2.py to test_discrete_traversal.py
VoxleOne May 16, 2025
b50be23
Merge pull request #1 from VoxLeone/features/cuda
VoxleOne May 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: SpinStep CI

on:
push:
branches: [main, dev, 'features/cuda']
pull_request:
branches: [main, dev]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .[dev]

- name: Lint with flake8
run: |
pip install flake8
flake8 spinstep --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 spinstep --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

- name: Test with pytest
run: |
pip install pytest
pytest tests/
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Changelog

All notable changes to this project are documented in this file.

This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and uses [Semantic Versioning](https://semver.org/).

---

## [Unreleased]

### Added
- MIT license/authorship headers to all `.py` files ([features/cuda])
- CUDA feature branch for GPU support

### Changed
- Restructured branch strategy: `main`, `dev`, `features/cuda`
- Clarified setup instructions in `README.md`

---

## [0.1.0] – 2025-05-14

### Added
- Initial codebase and Git setup
- Created branches: `main`, `dev`, and `feature/cuda`
- Basic Python project scaffold
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SpinStep
# SpinStep - [Read the Docs](https://github.com/VoxLeone/SpinStep/tree/dev/docs/index.md)

**SpinStep** is a proof-of-concept quaternion-driven traversal framework for trees and orientation-based data structures.

Expand Down
31 changes: 31 additions & 0 deletions docs/07_cuda_support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# CUDA (GPU) Support in SpinStep

SpinStep supports optional GPU acceleration for batch orientation math using [CuPy](https://cupy.dev/).

## Usage

```python
from spinstep.discrete import DiscreteOrientationSet
set_gpu = DiscreteOrientationSet(orientations, use_cuda=True)
```

If CuPy or a compatible GPU is not found, SpinStep will fall back to CPU (NumPy) and print a warning.

## Requirements

- [CuPy](https://cupy.dev/) (`pip install cupy`)
- NVIDIA GPU with CUDA drivers

## Accelerated Features

- Batch orientation storage and math
- Fast angular distance computations for large orientation sets

## Limitations

- Tree traversal logic remains on CPU (Python object graph)
- Only orientation math is GPU-accelerated

## Example

See [`examples/gpu_orientation_matching.py`](../examples/gpu_orientation_matching.py)
20 changes: 20 additions & 0 deletions docs/08_troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Troubleshooting & FAQ

## Why is my traversal slow?
- Check the size of your DiscreteOrientationSet. Very fine grids may result in millions of steps.
- Try reducing the number of points or increasing `angle_threshold`.
- For large sets, consider spatial pruning or batching.

## I got a ValueError about quaternions?
- All quaternions must be normalized and non-zero. Use the provided utilities or `scipy.spatial.transform.Rotation` to generate valid quaternions.

## What if my node doesn't have `.orientation` or `.children`?
- All nodes must implement both attributes. If you use custom node types, subclass or adapt as needed.

## Can I use Euler angles or axis-angle?
- Yes! Convert to quaternions using `scipy.spatial.transform.Rotation`.

## What is a "closure property" test?
- For symmetry groups, applying all group elements in sequence should bring you (numerically) back to a group element—verifying group structure.

---
137 changes: 137 additions & 0 deletions docs/09_API_Reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# SpinStep API Reference

This document details the main public API of the SpinStep library.
For usage examples, see the [Examples & Tutorials](examples.md).

---

## Table of Contents

- [spinstep.node.Node](#spinstepnodenode)
- [spinstep.discrete.DiscreteOrientationSet](#spinstepdiscretediscreteorientationset)
- [spinstep.discrete_iterator.DiscreteQuaternionIterator](#spinstepdiscrete_iteratordiscretequaternioniterator)
- [spinstep.continuous.QuaternionDepthIterator](#spinstepcontinuousquaterniondepthiterator)
- [Exceptions](#exceptions)

---

## spinstep.node.Node

```python
class Node:
def __init__(self, name: str, orientation: Sequence[float], children: Optional[Iterable["Node"]] = None)
```

- **name** (`str`): Node identifier (any string).
- **orientation** (`[x, y, z, w]`): Quaternion representing the orientation. Automatically normalized.
- **children** (`Iterable[Node]`, optional): List or iterable of child nodes.

#### Attributes

- **name**: Node name.
- **orientation**: Normalized quaternion (`numpy.ndarray`, shape `(4,)`).
- **children**: List of child nodes.

---

## spinstep.discrete.DiscreteOrientationSet

A container for a set of discrete orientations (quaternions).

```python
class DiscreteOrientationSet:
def __init__(self, orientations: Sequence[Sequence[float]])
```

#### Constructor

- **orientations**: List or array of normalized quaternions (`[x, y, z, w]`).

#### Class Methods

- `from_cube()`: Returns a set of cube group orientations (24 elements).
- `from_icosahedron()`: Returns a set of icosahedral group orientations (60 elements).
- `from_custom(orientations)`: Create from user-specified list of quaternions.
- `from_sphere_grid(N: int)`: Approximate a uniform grid of `N` orientations on the sphere.

#### Methods

- `query_within_angle(quat: Sequence[float], angle: float) -> np.ndarray`:
Returns indices of orientations within `angle` (radians) of `quat`.

#### Attributes

- **orientations**: Array of normalized quaternions (shape `(n,4)`).

---

## spinstep.discrete_iterator.DiscreteQuaternionIterator

Depth-first traversal over a tree of Nodes using a discrete orientation set.

```python
class DiscreteQuaternionIterator:
def __init__(
self,
start_node: Node,
orientation_set: DiscreteOrientationSet,
angle_threshold: float = np.pi/8,
max_depth: int = 100
)
```

- **start_node**: The root `Node` to start traversal from.
- **orientation_set**: Instance of `DiscreteOrientationSet`.
- **angle_threshold**: Maximum allowed angular distance (in radians) to consider two orientations "matching."
- **max_depth**: Maximum recursion depth.

#### Usage

```python
it = DiscreteQuaternionIterator(root_node, orientation_set, angle_threshold=0.2)
for node in it:
print(node.name)
```

---

## spinstep.continuous.QuaternionDepthIterator

Depth-first traversal for continuous (non-discrete) orientation search.

```python
class QuaternionDepthIterator:
def __init__(
self,
start_node: Node,
angle_threshold: float = np.pi/8,
max_depth: int = 100
)
```

- **start_node**: The root `Node`.
- **angle_threshold**: Maximum allowed angular distance (in radians) for matching.
- **max_depth**: Maximum recursion depth.

#### Usage

```python
it = QuaternionDepthIterator(root_node, angle_threshold=0.1)
for node in it:
print(node.name)
```

---

## Exceptions

- **ValueError**: Raised for invalid or non-normalized quaternions, or malformed orientation sets.
- **AttributeError**: Raised if a node lacks required `.orientation` or `.children` attributes.

---

## See Also

- [Orientation Sets](05_orientation_sets.md)
- [Discrete Traversal Guide](06_discrete_traversal.md)
- [Troubleshooting & FAQ](07_troubleshooting.md)
4 changes: 3 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ This documentation provides insight into the motivation, technology, and future
4. [Use Cases](04_use_cases.md)
5. [Visualization](05_visualization.md)
6. [Discrete Traversal](06_discrete_traversal.md)
7. [API Reference](api_reference.md)
7. [CUDA Support](07_cuda_support.md)
8. [Troubleshooting & FAQ](08_troubleshooting.md)
9. [API Reference](09_API_reference.md)

+ [CONTRIBUTING](CONTRIBUTING.md)

Expand Down
13 changes: 13 additions & 0 deletions examples/gpu_orientation_matching.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import numpy as np
from spinstep.discrete import DiscreteOrientationSet
from spinstep.utils.quaternion_math import batch_quaternion_angle

N = 100_000
orientations = np.random.randn(N, 4)
orientation_set = DiscreteOrientationSet(orientations, use_cuda=True)

query = np.array([[0, 0, 0, 1]])
xp = orientation_set.xp
angles = batch_quaternion_angle(xp.array(query), orientation_set.orientations, xp)
close_inds = xp.where(angles[0] < 0.1)[0]
print(f"Found {close_inds.size} close orientations (on GPU)")
19 changes: 0 additions & 19 deletions pyproject.toml

This file was deleted.

4 changes: 4 additions & 0 deletions spinstep/__init.py__
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# __init__.py — MIT License
# Author: Eraldo B. Marques <eraldo.bernardo@gmail.com> — Created: 2025-05-14
# See LICENSE.txt for full terms. This header must be retained in redistributions.

from .node import Node
from .traversal import QuaternionDepthIterator
from .discrete import DiscreteOrientationSet
Expand Down
6 changes: 4 additions & 2 deletions spinstep/demo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# demo.py — MIT License
# Author: Eraldo Marques <eraldo.bernardo@gmail.com> — Created: 2025-05-14
# See LICENSE.txt for full terms. This header must be retained in redistributions.

from spinstep.node import Node
from spinstep.traversal import QuaternionDepthIterator
from spinstep.quaternion_utils import quaternion_from_euler
Expand All @@ -7,8 +11,6 @@
# .Applies a quaternion-based depth-first traversal.
# .Only visits nodes that lie within a given angular threshold (like aiming a "cone" of rotation).

Only visits nodes that lie within a given angular threshold (like aiming a "cone" of rotation).

def build_demo_tree():
"""Build a small tree with varied 3D orientations (yaw, pitch, roll)."""
root = Node("root", [0, 0, 0, 1], [
Expand Down
4 changes: 4 additions & 0 deletions spinstep/demo1_tree_traversal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# demo1_tree_traversal.py — MIT License
# Author: Eraldo Marques <eraldo.bernardo@gmail.com> — Created: 2025-05-14
# See LICENSE.txt for full terms. This header must be retained in redistributions.

import numpy as np
from scipy.spatial.transform import Rotation as R

Expand Down
4 changes: 4 additions & 0 deletions spinstep/demo2_full_depth_traversal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# demo2_full_depth_traversal.py — MIT License
# Author: Eraldo Marques <eraldo.bernardo@gmail.com> — Created: 2025-05-14
# See LICENSE.txt for full terms. This header must be retained in redistributions.

import numpy as np
from scipy.spatial.transform import Rotation as R

Expand Down
4 changes: 4 additions & 0 deletions spinstep/demo3_spatial_traversal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# demo3_spatial_traversal.py — MIT License
# Author: Eraldo Marques <eraldo.bernardo@gmail.com> — Created: 2025-05-14
# See LICENSE.txt for full terms. This header must be retained in redistributions.

import numpy as np
from scipy.spatial.transform import Rotation as R

Expand Down
6 changes: 5 additions & 1 deletion spinstep/demo4_discrete_traversal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# demo4_discrete_traversal.py — MIT License
# Author: Eraldo Marques <eraldo.bernardo@gmail.com> — Created: 2025-05-14
# See LICENSE.txt for full terms. This header must be retained in redistributions.

import numpy as np
from scipy.spatial.transform import Rotation as R
from spinstep.node import Node
Expand Down Expand Up @@ -25,4 +29,4 @@
visited_nodes = []
for node in iterator:
visited_nodes.append(node.name)
print("Visited:", node.name)
print("Visited:", node.name)
Loading
Loading