1use super::*;
2use algebraeon_rings::linear::matrix::{Matrix, MatrixStructure};
3use simplexes::{OrientedHyperplane, OrientedSimplex, Simplex};
4
5#[derive(Debug, Clone)]
6pub struct EmbeddedAffineSubspace<
7 FS: OrderedRingStructure + FieldStructure,
8 SP: Borrow<AffineSpace<FS>> + Clone,
9 ESP: Borrow<AffineSpace<FS>> + Clone,
10> {
11 ambient_space: SP,
13 embedded_space: ESP,
14 embedding_points: Vec<Vector<FS, SP>>,
22}
23
24impl<
25 FS: OrderedRingStructure + FieldStructure,
26 SP: Borrow<AffineSpace<FS>> + Clone,
27 ESP: Borrow<AffineSpace<FS>> + From<AffineSpace<FS>> + Clone,
28> EmbeddedAffineSubspace<FS, SP, ESP>
29{
30 pub fn new_affine_span(
31 ambient_space: SP,
32 points: Vec<Vector<FS, SP>>,
33 ) -> Result<(Self, Vec<Vector<FS, ESP>>), &'static str> {
34 for point in &points {
35 debug_assert_eq!(point.ambient_space().borrow(), ambient_space.borrow());
36 }
37 if !ambient_space
38 .borrow()
39 .are_points_affine_independent(points.iter().collect())
40 {
41 return Err("Affine embedding points must be affine independent");
42 }
43 let ordered_field = ambient_space.borrow().ordered_field();
44 let embedded_space: ESP =
45 AffineSpace::new_affine(ordered_field.clone(), points.len()).into();
46 let n = points.len();
47 let embedded_pts = (0..n)
48 .map(|i| {
49 Vector::construct(embedded_space.clone(), |j| {
50 if i == 0 {
51 ordered_field.zero()
52 } else {
53 match i == j + 1 {
54 true => ordered_field.one(),
55 false => ordered_field.zero(),
56 }
57 }
58 })
59 })
60 .collect();
61 Ok((
62 Self {
63 ambient_space,
64 embedded_space,
65 embedding_points: points,
66 },
67 embedded_pts,
68 ))
69 }
70
71 pub fn new_empty(ambient_space: SP) -> Self {
72 Self::new_affine_span(ambient_space, vec![]).unwrap().0
73 }
74}
75
76impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone>
77 EmbeddedAffineSubspace<FS, SP, AffineSpace<FS>>
78{
79 pub fn new(
80 ambient_space: SP,
81 root: Vector<FS, SP>,
82 span: Vec<Vector<FS, SP>>,
83 ) -> Result<(Self, Vec<Vector<FS, AffineSpace<FS>>>), &'static str> {
84 let mut points = vec![root.clone()];
85 points.extend(span.iter().map(|vec| &root + vec));
86 Self::new_affine_span(ambient_space, points)
87 }
88
89 pub fn new_affine_span_linearly_dependent(
90 ambient_space: SP,
91 points: Vec<&Vector<FS, SP>>,
92 ) -> Self {
93 if points.is_empty() {
94 Self::new_empty(ambient_space)
95 } else {
96 let dim = ambient_space.borrow().linear_dimension().unwrap();
97 let ordered_field = ambient_space.borrow().ordered_field();
98 let mut points = points.into_iter();
99 let root = points.next().unwrap();
100 let span = points.map(|pt| pt - root).collect::<Vec<_>>();
101 let mat = Matrix::construct(dim, span.len(), |r, c| span[c].coordinate(r).clone());
103 let (_, _, _, pivs) =
104 MatrixStructure::new(ordered_field.clone()).row_hermite_algorithm(mat);
105 Self::new(
106 ambient_space,
107 root.clone(),
108 pivs.into_iter().map(|i| span[i].clone()).collect(),
109 )
110 .unwrap()
111 .0
112 }
113 }
114}
115
116impl<
117 FS: OrderedRingStructure + FieldStructure,
118 SP: Borrow<AffineSpace<FS>> + Clone,
119 ESP: Borrow<AffineSpace<FS>> + Clone,
120> EmbeddedAffineSubspace<FS, SP, ESP>
121{
122 pub fn ordered_field(&self) -> &FS {
123 self.ambient_space.borrow().ordered_field()
124 }
125
126 pub fn ambient_space(&self) -> SP {
127 self.ambient_space.clone()
128 }
129
130 pub fn embedded_space(&self) -> ESP {
131 self.embedded_space.clone()
132 }
133
134 pub fn extend_dimension_by_point_unsafe(
141 &self,
142 pt: Vector<FS, SP>,
143 ) -> (
144 EmbeddedAffineSubspace<FS, AffineSpace<FS>, ESP>,
145 EmbeddedAffineSubspace<FS, SP, AffineSpace<FS>>,
146 Vector<FS, AffineSpace<FS>>,
147 ) {
148 debug_assert_eq!(self.ambient_space.borrow(), pt.ambient_space().borrow());
149 debug_assert!(self.unembed_point(&pt).is_none());
150 let ordered_field = self.ordered_field();
151
152 let n = self.embedded_space.borrow().affine_dimension();
153 let extended_embedded_space = AffineSpace::new_affine(ordered_field.clone(), n + 1);
154
155 (
156 EmbeddedAffineSubspace {
157 ambient_space: extended_embedded_space.clone(),
158 embedded_space: self.embedded_space.clone(),
159 embedding_points: {
161 (0..n)
162 .map(|k| {
163 Vector::construct(extended_embedded_space.clone(), |i| {
164 if k == 0 {
165 ordered_field.zero()
166 } else {
167 let j = k - 1;
168 match i == j {
169 true => ordered_field.one(),
170 false => ordered_field.zero(),
171 }
172 }
173 })
174 })
175 .collect()
176 },
177 },
178 EmbeddedAffineSubspace {
179 ambient_space: self.ambient_space.clone(),
180 embedded_space: extended_embedded_space.clone(),
181 embedding_points: {
182 let mut pts = self.embedding_points.clone();
183 pts.push(pt);
184 pts
185 },
186 },
187 Vector::construct(extended_embedded_space.clone(), |i| match i + 1 == n {
188 true => ordered_field.one(),
189 false => ordered_field.zero(),
190 }),
191 )
192 }
193
194 pub fn get_root_and_span(&self) -> Option<(Vector<FS, SP>, Vec<Vector<FS, SP>>)> {
195 let mut points = self.embedding_points.iter();
196 let root = points.next()?;
197 let span = points.map(|pt| pt - root).collect::<Vec<_>>();
198 Some((root.clone(), span))
199 }
200
201 pub fn get_embedding_points(&self) -> &Vec<Vector<FS, SP>> {
202 &self.embedding_points
203 }
204
205 pub fn embed_point(&self, pt: &Vector<FS, ESP>) -> Vector<FS, SP> {
206 assert_eq!(pt.ambient_space().borrow(), self.embedded_space.borrow());
207 let (root, span) = self.get_root_and_span().unwrap(); let mut total = root.clone();
209 for (i, vec) in span.iter().enumerate() {
210 total += &vec.scalar_mul(pt.coordinate(i));
211 }
212 total
213 }
214
215 pub fn embed_simplex(&self, spx: &Simplex<FS, ESP>) -> Simplex<FS, SP> {
216 Simplex::new(
217 self.ambient_space(),
218 spx.points()
219 .into_iter()
220 .map(|p| self.embed_point(p))
221 .collect(),
222 )
223 .unwrap()
224 }
225
226 pub fn unembed_point(&self, pt: &Vector<FS, SP>) -> Option<Vector<FS, ESP>> {
227 assert_eq!(pt.ambient_space().borrow(), self.ambient_space.borrow());
228 match self.get_root_and_span() {
229 Some((root, span)) => {
230 let y = (pt - &root).into_col();
232 let basis_matrix = self
233 .ambient_space
234 .borrow()
235 .cols_from_vectors(span.iter().collect());
236 let x = MatrixStructure::new(self.ambient_space.borrow().ordered_field().clone())
237 .col_solve(&basis_matrix, y);
238 Some(vector_from_col(self.embedded_space(), &x?))
239 }
240 None => None,
241 }
242 }
243
244 pub fn unembed_simplex(&self, spx: &Simplex<FS, SP>) -> Option<Simplex<FS, ESP>> {
245 let mut pts = vec![];
246 for embedded_pt in spx.points() {
247 match self.unembed_point(embedded_pt) {
248 Some(pt) => {
249 pts.push(pt);
250 }
251 None => {
252 return None;
253 }
254 }
255 }
256 Some(Simplex::new(self.embedded_space(), pts).unwrap())
257 }
258
259 pub fn as_hyperplane_intersection(&self) -> Option<Vec<OrientedHyperplane<FS, SP>>> {
260 let ambient_space = self.ambient_space();
261 let ordered_field = ambient_space.borrow().ordered_field();
262 match self.get_root_and_span() {
263 Some((root, span)) => {
264 let dim_amb = ambient_space.borrow().linear_dimension().unwrap();
265 let dim_ss = span.len();
266 let mat = Matrix::construct(dim_amb, dim_ss + dim_amb, |r, c| {
269 if c < dim_ss {
270 span[c].coordinate(r).clone()
271 } else {
272 let c = c - dim_ss;
273 match r == c {
274 false => ordered_field.zero(),
275 true => ordered_field.one(),
276 }
277 }
278 });
279 let (_, _, _, pivs) =
280 MatrixStructure::new(ordered_field.clone()).row_hermite_algorithm(mat);
281 debug_assert_eq!(pivs.len(), dim_amb);
282 for i in 0..dim_ss {
283 debug_assert_eq!(pivs[i], i); }
285 let extension_elementary_basis_vectors = (dim_ss..dim_amb)
286 .map(|i| pivs[i] - dim_ss)
287 .collect::<Vec<_>>();
288
289 let hyperplanes = (0..extension_elementary_basis_vectors.len())
291 .map(|i| {
292 let ref_point = {
293 let k = extension_elementary_basis_vectors[i];
295 Vector::construct(ambient_space.clone(), |l| {
296 ordered_field.add(
297 root.coordinate(l),
298 &match l == k {
299 false => ordered_field.zero(),
300 true => ordered_field.one(),
301 },
302 )
303 })
304 };
305 OrientedSimplex::new_with_positive_point(
306 ambient_space.clone(),
307 {
308 let mut points = vec![root.clone()];
309 for s in &span {
310 points.push(&root + s);
311 }
312 for j in 0..extension_elementary_basis_vectors.len() {
313 if i != j {
314 let k = extension_elementary_basis_vectors[j];
315 points.push(Vector::construct(ambient_space.clone(), |l| {
317 ordered_field.add(root.coordinate(l), &{
318 match l == k {
319 false => ordered_field.zero(),
320 true => ordered_field.one(),
321 }
322 })
323 }))
324 }
325 }
326 points
327 },
328 &ref_point,
329 )
330 .unwrap()
331 .into_oriented_hyperplane()
332 })
333 .collect::<Vec<_>>();
334 debug_assert_eq!(hyperplanes.len(), dim_amb - dim_ss);
335 Some(hyperplanes)
336 }
337 None => None,
338 }
339 }
340}
341
342pub fn compose_affine_embeddings<
343 FS: OrderedRingStructure + FieldStructure,
344 SPA: Borrow<AffineSpace<FS>> + Clone,
345 SPB: Borrow<AffineSpace<FS>> + Clone,
346 SPC: Borrow<AffineSpace<FS>> + Clone,
347>(
348 _a_to_b: EmbeddedAffineSubspace<FS, SPB, SPA>,
349 _b_to_c: EmbeddedAffineSubspace<FS, SPC, SPB>,
350) -> EmbeddedAffineSubspace<FS, SPC, SPA> {
351 todo!() }
353
354#[cfg(test)]
355mod tests {
356 use algebraeon_nzq::Rational;
357 use algebraeon_sets::structure::*;
358
359 use super::*;
360
361 #[test]
362 fn make_affine_subspace() {
363 let space = AffineSpace::new_linear(Rational::structure(), 3);
364 let v1 = Vector::new(
365 &space,
366 vec![Rational::from(1), Rational::from(1), Rational::from(1)],
367 );
368 let v2 = Vector::new(
369 &space,
370 vec![Rational::from(1), Rational::from(0), Rational::from(0)],
371 );
372 let v3 = Vector::new(
373 &space,
374 vec![Rational::from(0), Rational::from(1), Rational::from(0)],
375 );
376 let s = EmbeddedAffineSubspace::new(&space, v1, vec![v2, v3]);
377 s.unwrap();
378
379 let space = AffineSpace::new_linear(Rational::structure(), 3);
380 let v1 = Vector::new(
381 &space,
382 vec![Rational::from(1), Rational::from(1), Rational::from(1)],
383 );
384 let v2 = Vector::new(
385 &space,
386 vec![Rational::from(1), Rational::from(2), Rational::from(0)],
387 );
388 let v3 = Vector::new(
389 &space,
390 vec![Rational::from(-2), Rational::from(-4), Rational::from(0)],
391 );
392 let s = EmbeddedAffineSubspace::new(&space, v1, vec![v2, v3]);
393 assert!(s.is_err());
394 }
395
396 #[test]
397 fn affine_subspace_embed_and_unembed() {
398 {
400 let plane = AffineSpace::new_linear(Rational::structure(), 2);
401 let (line, _) = EmbeddedAffineSubspace::new(
403 &plane,
404 Vector::new(&plane, vec![Rational::from(1), Rational::from(1)]),
405 vec![Vector::new(
406 &plane,
407 vec![Rational::from(1), Rational::from(-1)],
408 )],
409 )
410 .unwrap();
411
412 assert_eq!(
413 line.embed_point(&Vector::new(
414 line.embedded_space(),
415 vec![Rational::from(-3)],
416 )),
417 Vector::new(&plane, vec![Rational::from(-2), Rational::from(4)])
418 );
419
420 assert_eq!(
421 line.unembed_point(&Vector::new(
422 &plane,
423 vec![Rational::from(-1), Rational::from(3)],
424 )),
425 Some(Vector::new(line.embedded_space(), vec![Rational::from(-2)],))
426 );
427
428 assert_eq!(
429 line.unembed_point(&Vector::new(
430 &plane,
431 vec![Rational::from(1), Rational::from(2)],
432 )),
433 None
434 );
435 }
436
437 {
439 let space = AffineSpace::new_linear(Rational::structure(), 3);
440 let (plane, _) = EmbeddedAffineSubspace::new(
441 &space,
442 Vector::new(
443 &space,
444 vec![Rational::from(3), Rational::from(1), Rational::from(2)],
445 ),
446 vec![
447 Vector::new(
448 &space,
449 vec![Rational::from(4), Rational::from(2), Rational::from(1)],
450 ),
451 Vector::new(
452 &space,
453 vec![Rational::from(1), Rational::from(-1), Rational::from(2)],
454 ),
455 ],
456 )
457 .unwrap();
458
459 assert_eq!(
460 plane.embed_point(&Vector::new(
461 plane.embedded_space(),
462 vec![Rational::from(-3), Rational::from(2)],
463 )),
464 Vector::new(
465 &space,
466 vec![Rational::from(-7), Rational::from(-7), Rational::from(3)]
467 )
468 );
469
470 assert_eq!(
471 plane.unembed_point(&Vector::new(
472 &space,
473 vec![Rational::from(0), Rational::from(-2), Rational::from(3)],
474 )),
475 Some(Vector::new(
476 plane.embedded_space(),
477 vec![Rational::from(-1), Rational::from(1)],
478 ))
479 );
480
481 assert_eq!(
482 plane.unembed_point(&Vector::new(
483 &space,
484 vec![Rational::from(1), Rational::from(2), Rational::from(2)],
485 )),
486 None
487 );
488 }
489 }
490
491 #[test]
492 fn extend_by_point_embedding_composition() {
493 let space = AffineSpace::new_linear(Rational::structure(), 4);
494 let v1 = Vector::new(
495 &space,
496 vec![
497 Rational::from(1),
498 Rational::from(2),
499 Rational::from(1),
500 Rational::from(1),
501 ],
502 );
503 let v2 = Vector::new(
504 &space,
505 vec![
506 Rational::from(1),
507 Rational::from(-2),
508 Rational::from(2),
509 Rational::from(0),
510 ],
511 );
512 let v3 = Vector::new(
513 &space,
514 vec![
515 Rational::from(2),
516 Rational::from(1),
517 Rational::from(0),
518 Rational::from(2),
519 ],
520 );
521 let (h, _) = EmbeddedAffineSubspace::new(&space, v1, vec![v2, v3]).unwrap();
522 let v4 = Vector::new(
523 &space,
524 vec![
525 Rational::from(0),
526 Rational::from(3),
527 Rational::from(-2),
528 Rational::from(1),
529 ],
530 );
531 let (f, g, v4_inv) = h.extend_dimension_by_point_unsafe(v4.clone());
532 assert_eq!(g.embed_point(&v4_inv), v4);
533
534 let x = Vector::new(
535 h.embedded_space(),
536 vec![Rational::from(5), Rational::from(7)],
537 );
538 assert_eq!(g.embed_point(&f.embed_point(&x)), h.embed_point(&x));
540 }
541}