geomflow 0.1.0__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.
- geomflow-0.1.0/.DS_Store +0 -0
- geomflow-0.1.0/.github/workflows/ci.yml +88 -0
- geomflow-0.1.0/.gitignore +90 -0
- geomflow-0.1.0/CMakeLists.txt +47 -0
- geomflow-0.1.0/LICENSE +21 -0
- geomflow-0.1.0/PKG-INFO +264 -0
- geomflow-0.1.0/README.md +248 -0
- geomflow-0.1.0/examples/cpp/CMakeLists.txt +17 -0
- geomflow-0.1.0/examples/cpp/infer_cnf.cpp +299 -0
- geomflow-0.1.0/examples/cpp/manifolds/sphere.h +112 -0
- geomflow-0.1.0/examples/cpp/manifolds/torus.h +117 -0
- geomflow-0.1.0/examples/cpp/train_cnf.cpp +348 -0
- geomflow-0.1.0/examples/python/.DS_Store +0 -0
- geomflow-0.1.0/examples/python/infer.py +661 -0
- geomflow-0.1.0/examples/python/manifolds/sphere.py +57 -0
- geomflow-0.1.0/examples/python/manifolds/torus.py +59 -0
- geomflow-0.1.0/examples/python/model.py +23 -0
- geomflow-0.1.0/examples/python/pv_cpp_vis.py +401 -0
- geomflow-0.1.0/examples/python/requirements.txt +5 -0
- geomflow-0.1.0/examples/python/scripts/run_sphere.sh +46 -0
- geomflow-0.1.0/examples/python/scripts/run_torus.sh +47 -0
- geomflow-0.1.0/examples/python/test_smoke.py +46 -0
- geomflow-0.1.0/examples/python/train.py +279 -0
- geomflow-0.1.0/include/geomflow/adjoint.h +161 -0
- geomflow-0.1.0/include/geomflow/connection.h +88 -0
- geomflow-0.1.0/include/geomflow/covariant.h +63 -0
- geomflow-0.1.0/include/geomflow/divergence.h +53 -0
- geomflow-0.1.0/include/geomflow/gradient.h +52 -0
- geomflow-0.1.0/include/geomflow/integrator.h +98 -0
- geomflow-0.1.0/include/geomflow/manifold.h +40 -0
- geomflow-0.1.0/include/geomflow/metric.h +76 -0
- geomflow-0.1.0/include/geomflow/objects.h +18 -0
- geomflow-0.1.0/include/geomflow/tangent.h +114 -0
- geomflow-0.1.0/include/geomflow/vector_field.h +40 -0
- geomflow-0.1.0/include/geomflow.h +13 -0
- geomflow-0.1.0/pyproject.toml +32 -0
- geomflow-0.1.0/python/bindings.cpp +167 -0
- geomflow-0.1.0/python/geomflow/__init__.py +133 -0
- geomflow-0.1.0/python/geomflow/_preprocess.py +54 -0
- geomflow-0.1.0/python/geomflow/_vector_field.py +62 -0
- geomflow-0.1.0/python/geomflow/torch/__init__.py +64 -0
- geomflow-0.1.0/python/geomflow/torch/_utils.py +30 -0
- geomflow-0.1.0/python/geomflow/torch/adjoint.py +132 -0
- geomflow-0.1.0/python/geomflow/torch/analytic_metric.py +112 -0
- geomflow-0.1.0/python/geomflow/torch/atlas.py +155 -0
- geomflow-0.1.0/python/geomflow/torch/fitter.py +259 -0
- geomflow-0.1.0/python/geomflow/torch/integrator.py +140 -0
- geomflow-0.1.0/python/geomflow/torch/manifolds.py +169 -0
- geomflow-0.1.0/python/geomflow/torch/multichart.py +97 -0
- geomflow-0.1.0/python/geomflow/torch/multichart_integrator.py +197 -0
- geomflow-0.1.0/python/geomflow/torch/operators.py +152 -0
- geomflow-0.1.0/python/geomflow/torch/transforms.py +82 -0
- geomflow-0.1.0/python/geomflow/torch/vector_field.py +97 -0
- geomflow-0.1.0/scripts/compile_cpp.sh +16 -0
- geomflow-0.1.0/scripts/visualize.py +263 -0
- geomflow-0.1.0/tests/CMakeLists.txt +26 -0
- geomflow-0.1.0/tests/test_adjoint.cpp +130 -0
- geomflow-0.1.0/tests/test_adjoint.py +50 -0
- geomflow-0.1.0/tests/test_cnf.cpp +159 -0
- geomflow-0.1.0/tests/test_fitter.py +105 -0
- geomflow-0.1.0/tests/test_flow.py +274 -0
- geomflow-0.1.0/tests/test_geometry.cpp +148 -0
- geomflow-0.1.0/tests/test_multichart_sphere.py +201 -0
- geomflow-0.1.0/tests/test_torch.py +176 -0
geomflow-0.1.0/.DS_Store
ADDED
|
Binary file
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build-test:
|
|
11
|
+
name: ${{ matrix.os }} / ${{ matrix.compiler }}
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-24.04, macos-14]
|
|
17
|
+
compiler: [gcc, clang]
|
|
18
|
+
include:
|
|
19
|
+
- os: ubuntu-24.04
|
|
20
|
+
compiler: gcc
|
|
21
|
+
cc: gcc
|
|
22
|
+
cxx: g++
|
|
23
|
+
- os: ubuntu-24.04
|
|
24
|
+
compiler: clang
|
|
25
|
+
cc: clang
|
|
26
|
+
cxx: clang++
|
|
27
|
+
- os: macos-14
|
|
28
|
+
compiler: gcc
|
|
29
|
+
cc: gcc-14
|
|
30
|
+
cxx: g++-14
|
|
31
|
+
- os: macos-14
|
|
32
|
+
compiler: clang
|
|
33
|
+
cc: clang
|
|
34
|
+
cxx: clang++
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies (Linux)
|
|
40
|
+
if: runner.os == 'Linux'
|
|
41
|
+
run: |
|
|
42
|
+
sudo apt-get update
|
|
43
|
+
sudo apt-get install -y cmake build-essential
|
|
44
|
+
|
|
45
|
+
- name: Install dependencies (macOS)
|
|
46
|
+
if: runner.os == 'macOS'
|
|
47
|
+
run: brew install cmake clang-format
|
|
48
|
+
|
|
49
|
+
- name: Configure
|
|
50
|
+
run: |
|
|
51
|
+
CC=${{ matrix.cc }} CXX=${{ matrix.cxx }} \
|
|
52
|
+
cmake -B build -DBUILD_TESTING=ON
|
|
53
|
+
|
|
54
|
+
- name: Build
|
|
55
|
+
run: cmake --build build --target geomflow_tests -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu)
|
|
56
|
+
|
|
57
|
+
- name: Run tests
|
|
58
|
+
run: ./build/tests/geomflow_tests
|
|
59
|
+
|
|
60
|
+
python-bindings:
|
|
61
|
+
name: Python bindings
|
|
62
|
+
runs-on: ubuntu-24.04
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@v4
|
|
65
|
+
|
|
66
|
+
- uses: actions/setup-python@v5
|
|
67
|
+
with:
|
|
68
|
+
python-version: '3.12'
|
|
69
|
+
|
|
70
|
+
- name: Install system deps
|
|
71
|
+
run: |
|
|
72
|
+
sudo apt-get update
|
|
73
|
+
sudo apt-get install -y cmake build-essential
|
|
74
|
+
|
|
75
|
+
- name: Install key modules
|
|
76
|
+
run: pip install pybind11 numpy torch
|
|
77
|
+
|
|
78
|
+
- name: Get pybind11 CMake dir
|
|
79
|
+
run: echo "PYBIND11_DIR=$(python -c 'import pybind11; print(pybind11.get_cmake_dir())')" >> $GITHUB_ENV
|
|
80
|
+
|
|
81
|
+
- name: Configure
|
|
82
|
+
run: cmake -B build -DBUILD_PYTHON=ON -Dpybind11_DIR=${{ env.PYBIND11_DIR }}
|
|
83
|
+
|
|
84
|
+
- name: Build
|
|
85
|
+
run: cmake --build build -j $(nproc)
|
|
86
|
+
|
|
87
|
+
- name: Import test
|
|
88
|
+
run: PYTHONPATH=python python -c "import geomflow; print(geomflow.EuclideanMetric3D())"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
gitignore
|
|
2
|
+
|
|
3
|
+
# Prerequisites
|
|
4
|
+
*.d
|
|
5
|
+
|
|
6
|
+
# Compiled Object files
|
|
7
|
+
*.slo
|
|
8
|
+
*.lo
|
|
9
|
+
*.o
|
|
10
|
+
*.obj
|
|
11
|
+
|
|
12
|
+
# Precompiled Headers
|
|
13
|
+
*.gch
|
|
14
|
+
*.pch
|
|
15
|
+
|
|
16
|
+
# Linker files
|
|
17
|
+
*.ilk
|
|
18
|
+
|
|
19
|
+
# Debugger Files
|
|
20
|
+
*.pdb
|
|
21
|
+
|
|
22
|
+
# Compiled Dynamic libraries
|
|
23
|
+
*.so
|
|
24
|
+
*.dylib
|
|
25
|
+
*.dll
|
|
26
|
+
*.so.*
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Fortran module files
|
|
30
|
+
*.mod
|
|
31
|
+
*.smod
|
|
32
|
+
|
|
33
|
+
# Compiled Static libraries
|
|
34
|
+
*.lai
|
|
35
|
+
*.la
|
|
36
|
+
*.a
|
|
37
|
+
*.lib
|
|
38
|
+
|
|
39
|
+
# Executables
|
|
40
|
+
*.exe
|
|
41
|
+
*.out
|
|
42
|
+
*.app
|
|
43
|
+
|
|
44
|
+
# Build directories
|
|
45
|
+
build/
|
|
46
|
+
Build/
|
|
47
|
+
build-*/
|
|
48
|
+
|
|
49
|
+
# CMake generated files
|
|
50
|
+
CMakeFiles/
|
|
51
|
+
CMakeCache.txt
|
|
52
|
+
cmake_install.cmake
|
|
53
|
+
Makefile
|
|
54
|
+
install_manifest.txt
|
|
55
|
+
compile_commands.json
|
|
56
|
+
|
|
57
|
+
# Temporary files
|
|
58
|
+
*.tmp
|
|
59
|
+
*.log
|
|
60
|
+
*.bak
|
|
61
|
+
*.swp
|
|
62
|
+
|
|
63
|
+
# vcpkg
|
|
64
|
+
vcpkg_installed/
|
|
65
|
+
|
|
66
|
+
# debug information files
|
|
67
|
+
*.dwo
|
|
68
|
+
|
|
69
|
+
# test output & cache
|
|
70
|
+
Testing/
|
|
71
|
+
.cache/
|
|
72
|
+
|
|
73
|
+
# Formatting & linter
|
|
74
|
+
.clangd
|
|
75
|
+
.aider*
|
|
76
|
+
|
|
77
|
+
# misc
|
|
78
|
+
.venv/
|
|
79
|
+
.clang-format
|
|
80
|
+
AGENTS.md
|
|
81
|
+
papers/
|
|
82
|
+
auth
|
|
83
|
+
login
|
|
84
|
+
opencode.json
|
|
85
|
+
uv.lock
|
|
86
|
+
*__pycache__/
|
|
87
|
+
*.pt
|
|
88
|
+
*.gif
|
|
89
|
+
*.pdf
|
|
90
|
+
TODO.md
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.18)
|
|
2
|
+
project(geomflow LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
5
|
+
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
6
|
+
|
|
7
|
+
# --- Header-only C++ library ---
|
|
8
|
+
add_library(geomflow_headers INTERFACE)
|
|
9
|
+
target_include_directories(geomflow_headers INTERFACE
|
|
10
|
+
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# --- C++ tests (Catch2) ---
|
|
14
|
+
option(BUILD_TESTS "Build C++ unit tests" ON)
|
|
15
|
+
if(BUILD_TESTS)
|
|
16
|
+
add_subdirectory(tests)
|
|
17
|
+
endif()
|
|
18
|
+
|
|
19
|
+
# --- C++ examples ---
|
|
20
|
+
option(BUILD_EXAMPLES "Build C++ example applications" ON)
|
|
21
|
+
if(BUILD_EXAMPLES)
|
|
22
|
+
add_subdirectory(examples/cpp)
|
|
23
|
+
endif()
|
|
24
|
+
|
|
25
|
+
# --- Python module (pybind11) ---
|
|
26
|
+
option(BUILD_PYTHON "Build Python pybind11 module" OFF)
|
|
27
|
+
if(BUILD_PYTHON)
|
|
28
|
+
find_package(Python COMPONENTS Interpreter Development REQUIRED)
|
|
29
|
+
find_package(pybind11 REQUIRED)
|
|
30
|
+
|
|
31
|
+
pybind11_add_module(_geomflow
|
|
32
|
+
python/bindings.cpp
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
target_link_libraries(_geomflow PRIVATE
|
|
36
|
+
pybind11::module
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
target_include_directories(_geomflow PRIVATE
|
|
40
|
+
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
41
|
+
${Python_INCLUDE_DIRS}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
set_target_properties(_geomflow PROPERTIES
|
|
45
|
+
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/python/geomflow"
|
|
46
|
+
)
|
|
47
|
+
endif()
|
geomflow-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Liiban Mohamud
|
|
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.
|
geomflow-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: geomflow
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Intrinsic Riemannian Manifold Continuous Normalizing Flow Library
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: torch>=2.0
|
|
8
|
+
Requires-Dist: numpy>=1.24
|
|
9
|
+
Requires-Dist: scipy>=1.10
|
|
10
|
+
Requires-Dist: matplotlib>=3.7
|
|
11
|
+
Requires-Dist: imageio>=2.31
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: torchdiffeq>=0.2; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# geomflow
|
|
18
|
+
|
|
19
|
+
**General Manifold-Constraint Continuous Normalizing Flows using Intrinsic Riemannian Geometry**
|
|
20
|
+
|
|
21
|
+
`geomflow` is a high-performance, header-only C++20 library and PyTorch framework for Continuous Normalizing Flows (CNFs) on Riemannian manifolds. Built directly on the purely intrinsic manifold formulation I formulated, `geomflow` requires **no ambient space embedding** (such as Whitney's embedding theorem) to evaluate density, integrate flows, or compute adjoint gradients.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Key Features
|
|
26
|
+
|
|
27
|
+
- **Purely Intrinsic Geometry**: All operations—metric tensor $g_{ij}$, Levi-Civita connection $\Gamma_{ij}^k$, divergence $\text{div}_g$, and adjoint gradients—are computed directly on intrinsic coordinate charts.
|
|
28
|
+
- **The Intrinsic Adjoint ODE (Theorem 3.7)**: Memory-efficient backward adjoint ODE solver derived entirely from intrinsic manifold quantities:
|
|
29
|
+
$$\dot{\lambda}(t) + \langle \lambda(t), \nabla f_\theta \rangle = \nabla (\text{div}_g f_\theta)$$
|
|
30
|
+
- **High-Level PyTorch Fitter (`geomflow.torch.ManifoldCNF`)**: Intuitive, scikit-learn-style API with `.fit(data)`, `.log_prob(x)`, and `.sample(n)`.
|
|
31
|
+
- **Multi-Chart Atlas Support**: Seamless dynamic chart-switching during flow integration across coordinate patches with overlap consistency loss.
|
|
32
|
+
- **Built-in Manifold Presets**:
|
|
33
|
+
- **Sphere $S^d$**: Stereographic multi-chart atlas & single-chart metrics.
|
|
34
|
+
- **Torus $T^2$**: Flat periodic angle coordinate metrics.
|
|
35
|
+
- **Hyperbolic Space $\mathbb{H}^d$**: Poincaré disk model metric.
|
|
36
|
+
- **Euclidean Space $\mathbb{R}^d$**: Standard flat space.
|
|
37
|
+
- **Induced Submanifold Metrics**: Automatic pullback metrics $G(x) = J_\phi(x)^T J_\phi(x)$ for arbitrary immersions $\phi: U \subset \mathbb{R}^d \to \mathbb{R}^N$.
|
|
38
|
+
- **C++20 Header-Only Core**: Zero-dependency C++ template headers for embedding into native C++ graphics, physics, or simulation pipelines.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### Python (PyTorch)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/LiibanMo/geomflow.git
|
|
48
|
+
cd geomflow
|
|
49
|
+
pip install -e .
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Requirements: `torch >= 2.0`, `numpy`, `scipy`.
|
|
53
|
+
|
|
54
|
+
### C++20 Header-Only Library
|
|
55
|
+
|
|
56
|
+
Simply add `include/` to your project's include paths, or integrate via CMake:
|
|
57
|
+
|
|
58
|
+
```cmake
|
|
59
|
+
add_subdirectory(geomflow)
|
|
60
|
+
target_link_libraries(your_target PRIVATE geomflow_headers)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Build C++ tests and examples:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cmake -B build -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON
|
|
67
|
+
cmake --build build
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Python Usage & Examples
|
|
73
|
+
|
|
74
|
+
### 1. High-Level Manifold CNF Fitting (`ManifoldCNF`)
|
|
75
|
+
|
|
76
|
+
Fit a density model on a manifold using built-in presets in just a few lines:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import torch
|
|
80
|
+
from geomflow import ManifoldCNF, Sphere2DAtlas, Torus2D, PoincareDisk
|
|
81
|
+
|
|
82
|
+
# 1. Select geometry: 2-chart stereographic sphere atlas
|
|
83
|
+
manifold = Sphere2DAtlas(n_samples=500)
|
|
84
|
+
|
|
85
|
+
# 2. Instantiate high-level ManifoldCNF
|
|
86
|
+
cnf = ManifoldCNF(manifold, hidden_dim=64, dt=0.05)
|
|
87
|
+
|
|
88
|
+
# 3. Create target data on manifold
|
|
89
|
+
data = torch.randn(256, 2) * 0.2 + torch.tensor([1.0, 1.0])
|
|
90
|
+
|
|
91
|
+
# 4. Fit density with Adam optimizer & overlap consistency
|
|
92
|
+
loss_history = cnf.fit(data, epochs=50, batch_size=32, lr=0.01)
|
|
93
|
+
|
|
94
|
+
# 5. Evaluate exact Riemannian log-likelihood log p(x)
|
|
95
|
+
log_p = cnf.log_prob(data[:5])
|
|
96
|
+
print("Sample Log Probabilities:", log_p)
|
|
97
|
+
|
|
98
|
+
# 6. Draw new samples from the fitted CNF on the manifold
|
|
99
|
+
samples, final_chart = cnf.sample(n_samples=100)
|
|
100
|
+
print("Generated Samples Shape:", samples.shape)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### 2. Custom Manifolds via Induced Submanifold Metric
|
|
106
|
+
|
|
107
|
+
Define custom manifolds by providing an explicit embedding map $\phi: U \subset \mathbb{R}^d \to \mathbb{R}^N$:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
import torch
|
|
111
|
+
from geomflow import ManifoldCNF, InducedMetric
|
|
112
|
+
|
|
113
|
+
# Define surface z = x^2 + y^2 embedded in R^3
|
|
114
|
+
def paraboloid_immersion(x: torch.Tensor) -> torch.Tensor:
|
|
115
|
+
z = (x * x).sum(dim=-1, keepdim=True)
|
|
116
|
+
return torch.cat([x, z], dim=-1)
|
|
117
|
+
|
|
118
|
+
# Automatically derives metric G(x) = J_phi(x)^T * J_phi(x)
|
|
119
|
+
metric = InducedMetric(dim=2, immersion_fn=paraboloid_immersion)
|
|
120
|
+
|
|
121
|
+
cnf = ManifoldCNF(metric, hidden_dim=32)
|
|
122
|
+
data = torch.randn(128, 2) * 0.5
|
|
123
|
+
cnf.fit(data, epochs=20)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### 3. Custom Closed-Form Metric & Operators
|
|
129
|
+
|
|
130
|
+
Define custom analytic metrics $g_{ij}(x)$ directly and execute intrinsic operators:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
import torch
|
|
134
|
+
from geomflow import AnalyticMetric, christoffel, divergence, gradient
|
|
135
|
+
|
|
136
|
+
# Custom metric function G(x)
|
|
137
|
+
def custom_metric_fn(x: torch.Tensor) -> torch.Tensor:
|
|
138
|
+
# Example: scaled metric g_ij = (1 + ||x||^2) * delta_ij
|
|
139
|
+
scale = 1.0 + (x * x).sum(dim=-1, keepdim=True)
|
|
140
|
+
eye = torch.eye(2, device=x.device, dtype=x.dtype)
|
|
141
|
+
return scale.unsqueeze(-1) * eye
|
|
142
|
+
|
|
143
|
+
metric = AnalyticMetric(dim=2, metric_fn=custom_metric_fn)
|
|
144
|
+
|
|
145
|
+
x = torch.randn(4, 2, requires_grad=True)
|
|
146
|
+
|
|
147
|
+
# Intrinsic Christoffel symbols Gamma^k_ij
|
|
148
|
+
Gamma = christoffel(metric, x) # (4, 2, 2, 2)
|
|
149
|
+
|
|
150
|
+
# Intrinsic vector field divergence div_g(f)
|
|
151
|
+
vf = lambda x_: 0.5 * x_
|
|
152
|
+
div_val = divergence(vf, x, metric) # (4,)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### 4. The Intrinsic Adjoint ODE (Theorem 3.7)
|
|
158
|
+
|
|
159
|
+
For memory-efficient backpropagation without saving intermediate ODE trajectory states:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
import torch
|
|
163
|
+
from geomflow import EuclideanSpace, ManifoldVectorField, IntrinsicAdjointFunction
|
|
164
|
+
|
|
165
|
+
metric = EuclideanSpace(dim=2)
|
|
166
|
+
vf = ManifoldVectorField(dim=2, hidden_dim=32)
|
|
167
|
+
data = torch.randn(16, 2, requires_grad=True)
|
|
168
|
+
|
|
169
|
+
# Compute loss and gradients using Theorem 3.7 intrinsic adjoint ODE
|
|
170
|
+
loss = IntrinsicAdjointFunction.apply(data, vf, metric, 0.05, 0.0, 1.0)
|
|
171
|
+
loss.backward()
|
|
172
|
+
|
|
173
|
+
print("Gradients w.r.t. input data:", data.grad.shape)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## C++20 Usage & Examples
|
|
179
|
+
|
|
180
|
+
`geomflow` provides a header-only C++20 library under `include/geomflow/`.
|
|
181
|
+
|
|
182
|
+
```cpp
|
|
183
|
+
#include <iostream>
|
|
184
|
+
#include <geomflow/geomflow.h>
|
|
185
|
+
|
|
186
|
+
int main() {
|
|
187
|
+
using Traits = geomflow::ManifoldTraits<3>;
|
|
188
|
+
using Metric = geomflow::EuclideanMetric<Traits>;
|
|
189
|
+
using Tangent = geomflow::TangentVector<Traits>;
|
|
190
|
+
|
|
191
|
+
Metric metric;
|
|
192
|
+
|
|
193
|
+
// Time-dependent vector field f_theta(t, x)
|
|
194
|
+
auto field_fn = [](double t, const auto &x, const auto &theta) {
|
|
195
|
+
(void)t; (void)x;
|
|
196
|
+
return Tangent({theta[0], theta[1], theta[2]});
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
geomflow::ParametrizedVectorField<Traits, Metric> field(metric, field_fn);
|
|
200
|
+
field.set_params({0.5, -0.2, 1.0});
|
|
201
|
+
|
|
202
|
+
// Integrated flow from t0 = 0 to t1 = 1
|
|
203
|
+
geomflow::FlowIntegrator<Traits, Metric, decltype(field)> integrator(metric, field);
|
|
204
|
+
auto result = integrator.integrate({0.0, 0.0, 0.0}, 0.0, 1.0, 0.01);
|
|
205
|
+
|
|
206
|
+
std::cout << "Final position x(1): ["
|
|
207
|
+
<< result.x_final[0] << ", "
|
|
208
|
+
<< result.x_final[1] << ", "
|
|
209
|
+
<< result.x_final[2] << "]\n";
|
|
210
|
+
std::cout << "Integrated log-det-Jacobian: " << result.log_det << "\n";
|
|
211
|
+
|
|
212
|
+
// Adjoint solver for parameter gradients (Theorem 3.7)
|
|
213
|
+
geomflow::CotangentVector<Traits> initial_adj({result.x_final[0], result.x_final[1], result.x_final[2]});
|
|
214
|
+
geomflow::AdjointSolver<Traits, Metric, decltype(field)> adjoint(metric, field);
|
|
215
|
+
auto grad = adjoint.compute_gradient({0.0, 0.0, 0.0}, 0.0, 1.0, 0.01, initial_adj);
|
|
216
|
+
|
|
217
|
+
std::cout << "Gradient dL/d_theta: ["
|
|
218
|
+
<< grad[0] << ", " << grad[1] << ", " << grad[2] << "]\n";
|
|
219
|
+
|
|
220
|
+
return 0;
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Repository Structure
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
geomflow/
|
|
230
|
+
├── include/
|
|
231
|
+
│ └── geomflow/ — C++20 header-only core
|
|
232
|
+
│ ├── adjoint.h — Intrinsic adjoint ODE solver (Theorem 3.7)
|
|
233
|
+
│ ├── connection.h — Levi-Civita connection & Christoffel symbols
|
|
234
|
+
│ ├── covariant.h — Covariant derivative tensor
|
|
235
|
+
│ ├── divergence.h — Intrinsic divergence operator
|
|
236
|
+
│ ├── integrator.h — Flow integrator with log-det Jacobian
|
|
237
|
+
│ ├── metric.h — Riemannian metric protocol & Euclidean metric
|
|
238
|
+
│ └── vector_field.h — Parameterized vector fields
|
|
239
|
+
├── python/
|
|
240
|
+
│ └── geomflow/
|
|
241
|
+
│ └── torch/ — PyTorch framework (geomflow.torch)
|
|
242
|
+
│ ├── analytic_metric.py — Analytic metric protocol
|
|
243
|
+
│ ├── atlas.py — Multi-chart atlas & validity balls
|
|
244
|
+
│ ├── fitter.py — High-level ManifoldCNF fitter API
|
|
245
|
+
│ ├── manifolds.py — Presets (Sphere, Torus, Hyperbolic, Induced)
|
|
246
|
+
│ ├── multichart.py — Multi-chart vector fields & overlap loss
|
|
247
|
+
│ ├── multichart_integrator.py — Dynamic chart-switching RK4 solver
|
|
248
|
+
│ ├── operators.py — Intrinsic geometric differential operators
|
|
249
|
+
│ └── adjoint.py — Mohamud intrinsic adjoint autograd Function
|
|
250
|
+
└── tests/ — Comprehensive test suite
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## References
|
|
256
|
+
|
|
257
|
+
1. **Mohamud, L.** — *The Derivation of the Dynamic Chart Manifold Neural ODE Solver*.
|
|
258
|
+
2. **Lou, A., Lim, D., Isola, P., & Sra, S.** — *Neural Manifold ODEs*. Advances in Neural Information Processing Systems (NeurIPS 2020), arXiv:2006.10254.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT License.
|