alice/topology/
manifold.rs1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use crate::core::scalar::Scalar;
4
5pub trait Dim: Copy + Eq + core::fmt::Debug {
6 fn value(&self) -> usize;
7}
8
9#[derive(Clone, Copy, PartialEq, Eq, Debug)]
10pub struct Const<const N: usize>;
11
12#[derive(Clone, Copy, PartialEq, Eq, Debug)]
13pub struct Dynamic(usize);
14
15impl<const N: usize> Dim for Const<N> {
16 fn value(&self) -> usize {
17 N
18 }
19}
20
21impl Dynamic {
22 pub fn new(n: usize) -> Self {
23 Self(n)
24 }
25}
26
27impl Dim for Dynamic {
28 fn value(&self) -> usize {
29 self.0
30 }
31}
32
33pub struct Point<S: Scalar> {
34 coords: Vec<S>,
35}
36
37impl<S: Scalar> Point<S> {
38 pub fn new(coords: Vec<S>) -> Self {
39 Self { coords }
40 }
41
42 pub fn dim(&self) -> usize {
43 self.coords.len()
44 }
45
46 pub fn coords(&self) -> &[S] {
47 &self.coords
48 }
49
50 pub fn get(&self, i: usize) -> Option<&S> {
51 self.coords.get(i)
52 }
53}
54
55impl<S: Scalar + PartialEq> PartialEq for Point<S> {
56 fn eq(&self, other: &Self) -> bool {
57 self.coords == other.coords
58 }
59}
60
61impl<S: Scalar + Eq> Eq for Point<S> {}
62
63impl<S: Scalar + Clone> Clone for Point<S> {
64 fn clone(&self) -> Self {
65 Self {
66 coords: self.coords.clone(),
67 }
68 }
69}
70
71pub struct TangentVector<S: Scalar> {
72 components: Vec<S>,
73}
74
75impl<S: Scalar> TangentVector<S> {
76 pub fn new(components: Vec<S>) -> Self {
77 Self { components }
78 }
79
80 pub fn dim(&self) -> usize {
81 self.components.len()
82 }
83
84 pub fn components(&self) -> &[S] {
85 &self.components
86 }
87}
88
89impl<S: Scalar + Clone> Clone for TangentVector<S> {
90 fn clone(&self) -> Self {
91 Self {
92 components: self.components.clone(),
93 }
94 }
95}
96
97pub struct Chart<S: Scalar> {
98 dim: usize,
99 to_euclidean: Box<dyn Fn(&Point<S>) -> Point<S> + Send + Sync>,
100 from_euclidean: Box<dyn Fn(&Point<S>) -> Point<S> + Send + Sync>,
101 domain_check: Box<dyn Fn(&Point<S>) -> bool + Send + Sync>,
102}
103
104impl<S: Scalar> Chart<S> {
105 pub fn new<F, G, D>(dim: usize, to_euclidean: F, from_euclidean: G, domain_check: D) -> Self
106 where
107 F: Fn(&Point<S>) -> Point<S> + Send + Sync + 'static,
108 G: Fn(&Point<S>) -> Point<S> + Send + Sync + 'static,
109 D: Fn(&Point<S>) -> bool + Send + Sync + 'static,
110 {
111 Self {
112 dim,
113 to_euclidean: Box::new(to_euclidean),
114 from_euclidean: Box::new(from_euclidean),
115 domain_check: Box::new(domain_check),
116 }
117 }
118
119 pub fn dim(&self) -> usize {
120 self.dim
121 }
122
123 pub fn contains(&self, p: &Point<S>) -> bool {
124 (self.domain_check)(p)
125 }
126
127 pub fn to_euclidean(&self, p: &Point<S>) -> Point<S> {
128 (self.to_euclidean)(p)
129 }
130
131 pub fn from_euclidean(&self, p: &Point<S>) -> Point<S> {
132 (self.from_euclidean)(p)
133 }
134}
135
136pub struct Atlas<S: Scalar> {
137 charts: Vec<Chart<S>>,
138 dim: usize,
139}
140
141impl<S: Scalar> Atlas<S> {
142 pub fn new(dim: usize) -> Self {
143 Self {
144 charts: Vec::new(),
145 dim,
146 }
147 }
148
149 pub fn add_chart(&mut self, chart: Chart<S>) {
150 assert_eq!(
151 chart.dim(),
152 self.dim,
153 "chart dimension must match atlas dimension"
154 );
155 self.charts.push(chart);
156 }
157
158 pub fn dim(&self) -> usize {
159 self.dim
160 }
161
162 pub fn covers(&self, p: &Point<S>) -> bool {
163 self.charts.iter().any(|c| c.contains(p))
164 }
165
166 pub fn chart_for(&self, p: &Point<S>) -> Option<&Chart<S>> {
167 self.charts.iter().find(|c| c.contains(p))
168 }
169
170 pub fn charts(&self) -> &[Chart<S>] {
171 &self.charts
172 }
173}
174
175pub trait Manifold {
176 type Scalar: Scalar;
177 fn dim(&self) -> usize;
178 fn atlas(&self) -> &Atlas<Self::Scalar>;
179 fn tangent_space_dim(&self) -> usize {
180 self.dim()
181 }
182 fn contains(&self, p: &Point<Self::Scalar>) -> bool {
183 self.atlas().covers(p)
184 }
185 fn chart_for(&self, p: &Point<Self::Scalar>) -> Option<&Chart<Self::Scalar>> {
186 self.atlas().chart_for(p)
187 }
188}