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