CDT++
Causal Dynamical Triangulations in C++
Loading...
Searching...
No Matches
Manifold_test.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Causal Dynamical Triangulations in C++ using CGAL
3
4 Copyright © 2018 Adam Getchell
5 ******************************************************************************/
6
10
11#include "Manifold.hpp"
12
13#include <doctest/doctest.h>
14
15#include <numbers>
16
17using namespace std;
18using namespace manifolds;
19
20static inline auto constexpr RADIUS_2 = 2.0 * std::numbers::inv_sqrt3_v<double>;
21
22SCENARIO("Manifold special member and swap properties" *
23 doctest::test_suite("manifold"))
24{
25 spdlog::debug("Manifold special member and swap properties.\n");
26 GIVEN("A 3-dimensional manifold.")
27 {
28 WHEN("Special members are examined.")
29 {
30 THEN("It is no-throw destructible.")
31 {
32 REQUIRE(is_nothrow_destructible_v<Manifold_3>);
33 spdlog::debug("It is no-throw destructible.\n");
34 }
35 THEN("It is default constructible.")
36 {
37 REQUIRE(is_default_constructible_v<Manifold_3>);
38 spdlog::debug("It is default constructible.\n");
39 }
40 THEN("It is NOT trivially constructible.")
41 {
42 CHECK_FALSE(is_trivially_constructible_v<Manifold_3>);
43 }
44 THEN("It is NOT trivially default constructible.")
45 {
46 CHECK_FALSE(is_trivially_default_constructible_v<Manifold_3>);
47 }
48 THEN("It is no-throw copy constructible.")
49 {
50 REQUIRE(is_nothrow_copy_constructible_v<Manifold_3>);
51 spdlog::debug("It is no-throw copy constructible.\n");
52 }
53 THEN("It is no-throw copy assignable.")
54 {
55 REQUIRE(is_nothrow_copy_assignable_v<Manifold_3>);
56 spdlog::debug("It is no-throw copy assignable.\n");
57 }
58 THEN("It is no-throw move constructible.")
59 {
60 REQUIRE(is_nothrow_move_constructible_v<Manifold_3>);
61 spdlog::debug("It is no-throw move constructible.\n");
62 }
63 THEN("It is no-throw move assignable.")
64 {
65 REQUIRE(is_nothrow_move_assignable_v<Manifold_3>);
66 spdlog::debug("It is no-throw move assignable.\n");
67 }
68 THEN("It is no-throw swappable.")
69 {
70 REQUIRE(is_nothrow_swappable_v<Manifold_3>);
71 spdlog::debug("It is no-throw swappable.\n");
72 }
73 THEN("It is constructible from a FoliatedTriangulation.")
74 {
75 REQUIRE(is_constructible_v<
77 spdlog::debug("It is constructible from a FoliatedTriangulation.\n");
78 }
79 THEN("It is constructible from 2 parameters.")
80 {
81 REQUIRE(is_constructible_v<Manifold_3, Int_precision, Int_precision>);
82 spdlog::debug("It is constructible from 2 parameters.\n");
83 }
84 THEN("It is constructible from 4 parameters.")
85 {
86 REQUIRE(is_constructible_v<Manifold_3, Int_precision, Int_precision,
87 double, double>);
88 spdlog::debug("It is constructible from 4 parameters.\n");
89 }
90 THEN("It is constructible from Causal_vertices.")
91 {
92 REQUIRE(is_constructible_v<Manifold_3, Causal_vertices_t<3>>);
93 spdlog::debug("It is constructible from Causal_vertices.\n");
94 }
95 THEN("It is constructible from Causal_vertices and INITIAL_RADIUS.")
96 {
97 REQUIRE(is_constructible_v<Manifold_3, Causal_vertices_t<3>, double>);
98 spdlog::debug(
99 "It is constructible from Causal_vertices and INITIAL_RADIUS.\n");
100 }
101 THEN(
102 "It is constructible from Causal_vertices, INITIAL_RADIUS, and "
103 "RADIAL_SEPARATION.")
104 {
105 REQUIRE(is_constructible_v<Manifold_3, Causal_vertices_t<3>, double,
106 double>);
107 spdlog::debug(
108 "It is constructible from Causal_vertices, INITIAL_RADIUS, and "
109 "RADIAL_SEPARATION.\n");
110 }
111 }
112 }
113}
114
115SCENARIO("Manifold free functions" * doctest::test_suite("manifold"))
116{
117 spdlog::debug("manifolds:: functions.\n");
118
119 GIVEN("A vector of points and timevalues.")
120 {
121 vector const Vertices{Point_t<3>(1, 0, 0), Point_t<3>(0, 1, 0),
122 Point_t<3>(0, 0, 1),
123 Point_t<3>(RADIUS_2, RADIUS_2, RADIUS_2)};
124 vector<size_t> const Timevalues{1, 1, 1, 2};
125 WHEN("Causal vertices are created.")
126 {
127 auto causal_vertices =
128 manifolds::make_causal_vertices<3>(Vertices, Timevalues);
129 THEN("They are correct.")
130 {
131 REQUIRE_EQ(causal_vertices.size(), 4);
132 REQUIRE_EQ(causal_vertices[0].first, Point_t<3>(1, 0, 0));
133 REQUIRE_EQ(causal_vertices[0].second, 1);
134 REQUIRE_EQ(causal_vertices[1].first, Point_t<3>(0, 1, 0));
135 REQUIRE_EQ(causal_vertices[1].second, 1);
136 REQUIRE_EQ(causal_vertices[2].first, Point_t<3>(0, 0, 1));
137 REQUIRE_EQ(causal_vertices[2].second, 1);
138 REQUIRE_EQ(causal_vertices[3].first,
139 Point_t<3>(RADIUS_2, RADIUS_2, RADIUS_2));
140 REQUIRE_EQ(causal_vertices[3].second, 2);
141 }
142 }
143 }
144 GIVEN("A mismatched set of points and timevalues.")
145 {
146 vector const Vertices{Point_t<3>(1, 0, 0), Point_t<3>(0, 1, 0),
147 Point_t<3>(0, 0, 1),
148 Point_t<3>(RADIUS_2, RADIUS_2, RADIUS_2)};
149 vector<size_t> const Timevalues{1, 1, 1};
150 WHEN("Causal vertices are created.")
151 {
152 THEN("An exception is thrown.")
153 {
154 REQUIRE_THROWS(
155 manifolds::make_causal_vertices<3>(Vertices, Timevalues));
156 }
157 }
158 }
159 GIVEN("4 points.")
160 {
161 using Point = Point_t<3>;
162 auto p_1 = Point(1, 0, 0);
163 auto p_2 = Point(0, 1, 0);
164 auto p_3 = Point(0, 0, 1);
165 auto p_4 = Point(RADIUS_2, RADIUS_2, RADIUS_2);
166 vector const Vertices{p_1, p_2, p_3, p_4};
167 vector<size_t> const Timevalues{1, 1, 1, 2};
168 auto causal_vertices =
169 manifolds::make_causal_vertices<3>(Vertices, Timevalues);
170
171 WHEN("The manifold is constructed.")
172 {
173 Manifold_3 const manifold(causal_vertices, 1, 1.0);
174 THEN("It is correct.")
175 {
176 REQUIRE(manifold.is_correct());
177 manifold.print();
178 manifold.print_details();
179 manifold.print_vertices();
180 }
181 THEN("We can obtain the vertices from the points.")
182 {
183 Vertex_handle_t<3> const v_1 = manifold.get_vertex(p_1);
184 CHECK(v_1->is_valid());
185 cout << "v_1 contains point " << v_1->point() << '\n';
187 // CHECK(manifold.get_delaunay().is_vertex(v_1));
188 }
189 THEN("We can obtain the cell from the vertices.")
190 {
191 Vertex_handle_t<3> const v_1 = manifold.get_vertex(p_1);
192 Vertex_handle_t<3> const v_2 = manifold.get_vertex(p_2);
193 Vertex_handle_t<3> const v_3 = manifold.get_vertex(p_3);
194 Vertex_handle_t<3> const v_4 = manifold.get_vertex(p_4);
195 auto const& cell = manifold.get_cell(v_1, v_2, v_3, v_4);
196 CHECK(cell->is_valid());
198 // CHECK(manifold.get_delaunay().is_cell(cell));
199 // We have to have a valid Cell handle to obtain a tetrahedron
200 auto tetrahedron = manifold.get_delaunay().tetrahedron(cell);
201 CHECK_FALSE(tetrahedron.is_degenerate());
202 cout << "Vertex 0 of tetrahedron is " << tetrahedron.vertex(0) << '\n';
203 cout << "Vertex 1 of tetrahedron is " << tetrahedron.vertex(1) << '\n';
204 cout << "Vertex 2 of tetrahedron is " << tetrahedron.vertex(2) << '\n';
205 cout << "Vertex 3 of tetrahedron is " << tetrahedron.vertex(3) << '\n';
206 }
207 }
208 }
209}
210
211SCENARIO("Manifold static members" * doctest::test_suite("manifold"))
212{
213 spdlog::debug("Manifold static members.\n");
214 GIVEN("A default constructed Manifold_3")
215 {
216 Manifold_3 const test{};
217 WHEN("The dimensionality of the manifold is queried.")
218 {
219 THEN("The correct dimensionality is returned.")
220 {
221 REQUIRE_EQ(test.dimension, 3);
222 }
223 }
224 }
225}
226
227SCENARIO("Manifold functions" * doctest::test_suite("manifold"))
228{
229 spdlog::debug("Manifold functions.\n");
230 GIVEN("A 3-manifold with four vertices.")
231 {
232 Causal_vertices_t<3> causal_vertices;
233 causal_vertices.emplace_back(Point_t<3>(1, 0, 0), 1);
234 causal_vertices.emplace_back(Point_t<3>(0, 1, 0), 1);
235 causal_vertices.emplace_back(Point_t<3>(0, 0, 1), 1);
236 causal_vertices.emplace_back(Point_t<3>(RADIUS_2, RADIUS_2, RADIUS_2), 2);
237 Manifold_3 const manifold(causal_vertices);
238
239 REQUIRE(manifold.is_correct());
240 WHEN("are_vertex_timevalues_valid() is called.")
241 {
242 THEN("The vertices have valid timevalues.")
243 {
244 REQUIRE_EQ(manifold.N0(), 4);
245 CHECK(manifold.is_correct());
246 // Human verification
247 manifold.print_vertices();
248 }
249 }
250 AND_WHEN("The vertices are mis-labelled.")
251 {
252 for (std::span const vertices(manifold.get_vertices());
253 auto const& vertex : vertices)
254 {
255 vertex->info() = std::numeric_limits<int>::max();
256 }
257 THEN("The incorrect vertex time-values are identified.")
258 {
259 CHECK_FALSE(manifold.is_correct());
260 // Human verification
261 manifold.print_vertices();
262 }
263 }
264 }
265}
266
267SCENARIO("3-Manifold initialization" * doctest::test_suite("manifold"))
268{
269 spdlog::debug("Manifold initialization.\n");
270 using Point = Point_t<3>;
271 GIVEN("A 3-manifold.")
272 {
273 WHEN("It is default constructed.")
274 {
275 Manifold_3 const manifold;
276 THEN("The triangulation is valid.")
277 {
278 auto const& manifold_type = typeid(manifold.get_triangulation()).name();
279 std::string manifold_string{manifold_type};
280 CHECK_NE(manifold_string.find("FoliatedTriangulation"),
281 std::string::npos);
282 fmt::print("The triangulation data structure is of type {}\n",
283 manifold_string);
284 REQUIRE(manifold.is_delaunay());
285 REQUIRE(manifold.is_valid());
286 }
287 THEN("The geometry is of type geometry class.")
288 {
289 auto const& geometry_type = typeid(manifold.get_geometry()).name();
290 std::string geometry_string{geometry_type};
291 CHECK_NE(geometry_string.find("Geometry"), std::string::npos);
292 fmt::print("The Geometry data structure is of type {}\n",
293 geometry_string);
294 }
295 }
296 WHEN("It is constructed from causal vertices.")
297 {
298 vector const Vertices{Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0),
299 Point(0, 0, 1),
300 Point(RADIUS_2, RADIUS_2, RADIUS_2)};
301 vector<size_t> const Timevalues{1, 2, 2, 2, 3};
302 auto causal_vertices =
303 manifolds::make_causal_vertices<3>(Vertices, Timevalues);
304 Manifold_3 const manifold(causal_vertices, 0, 1.0);
305 THEN("The triangulation is valid.")
306 {
307 auto const& manifold_type = typeid(manifold.get_triangulation()).name();
308 std::string manifold_string{manifold_type};
309 CHECK_NE(manifold_string.find("FoliatedTriangulation"),
310 std::string::npos);
311 fmt::print("The triangulation data structure is of type {}\n",
312 manifold_string);
313 REQUIRE(manifold.is_delaunay());
314 REQUIRE(manifold.is_valid());
315 }
316 THEN("The geometry is of type geometry class.")
317 {
318 auto const& geometry_type = typeid(manifold.get_geometry()).name();
319 std::string geometry_string{geometry_type};
320 CHECK_NE(geometry_string.find("Geometry"), std::string::npos);
321 fmt::print("The Geometry data structure is of type {}\n",
322 geometry_string);
323 }
324 THEN("The geometry matches the triangulation.")
325 {
326 REQUIRE(manifold.is_foliated());
327 REQUIRE_EQ(manifold.N0(), 5);
328 REQUIRE_EQ(manifold.N1_SL(), 3);
329 REQUIRE_EQ(manifold.N1_TL(), 6);
330 // How many spacelike facets have a timevalue of 2? Should be 1.
331 REQUIRE_EQ(manifold.N2_SL().count(2), 1);
332 // There shouldn't be spacelike facets with other time values.
333 REQUIRE_EQ(manifold.N2_SL().count(1), 0);
334 REQUIRE_EQ(manifold.N2_SL().count(3), 0);
335 REQUIRE_EQ(manifold.N3(), 2);
336 REQUIRE_EQ(manifold.min_time(), 1);
337 REQUIRE_EQ(manifold.max_time(), 3);
338 REQUIRE(manifold.check_simplices());
339 // Human verification
340 manifold.print();
342 }
343 }
344 WHEN("It is constructed from a Foliated triangulation.")
345 {
346 vector const Vertices{Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0),
347 Point(0, 0, 1),
348 Point(RADIUS_2, RADIUS_2, RADIUS_2)};
349 vector<size_t> const Timevalues{1, 2, 2, 2, 3};
350 auto causal_vertices =
351 manifolds::make_causal_vertices<3>(Vertices, Timevalues);
353 foliated_triangulation(causal_vertices, 0, 1.0);
354 Manifold_3 const manifold(foliated_triangulation);
355 CHECK_EQ(manifold.get_delaunay(), foliated_triangulation.get_delaunay());
356 THEN("The triangulation is valid.")
357 {
358 auto const& manifold_type = typeid(manifold.get_triangulation()).name();
359 std::string manifold_string{manifold_type};
360 CHECK_NE(manifold_string.find("FoliatedTriangulation"),
361 std::string::npos);
362 fmt::print("The triangulation data structure is of type {}\n",
363 manifold_string);
364 REQUIRE(manifold.is_delaunay());
365 REQUIRE(manifold.is_valid());
366 }
367 THEN("The geometry is of type geometry class.")
368 {
369 auto const& geometry_type = typeid(manifold.get_geometry()).name();
370 std::string geometry_string{geometry_type};
371 CHECK_NE(geometry_string.find("Geometry"), std::string::npos);
372 fmt::print("The Geometry data structure is of type {}\n",
373 geometry_string);
374 }
375 THEN("The geometry matches the triangulation.")
376 {
377 REQUIRE(manifold.is_foliated());
378 REQUIRE_EQ(manifold.N0(), 5);
379 REQUIRE_EQ(manifold.N1_SL(), 3);
380 REQUIRE_EQ(manifold.N1_TL(), 6);
381 // How many spacelike facets have a timevalue of 2? Should be 1.
382 CHECK_EQ(manifold.N2_SL().count(2), 1);
383 // There shouldn't be spacelike facets with other time values.
384 CHECK_EQ(manifold.N2_SL().count(1), 0);
385 REQUIRE_EQ(manifold.N2_SL().count(3), 0);
386 REQUIRE_EQ(manifold.N3(), 2);
387 CHECK_EQ(manifold.min_time(), 1);
388 CHECK_EQ(manifold.max_time(), 3);
389 REQUIRE(manifold.check_simplices());
390 // Human verification
391 manifold.print();
393 }
394 }
395 WHEN("Constructing the minimum size triangulation.")
396 {
397 auto constexpr desired_simplices = 2;
398 auto constexpr desired_timeslices = 2;
399 Manifold_3 const manifold(desired_simplices, desired_timeslices);
400 THEN("Triangulation is valid.") { REQUIRE(manifold.is_correct()); }
401 THEN("The geometry matches the triangulation.")
402 {
403 REQUIRE(manifold.is_foliated());
404 REQUIRE_EQ(manifold.vertices(), manifold.N0());
405 REQUIRE_EQ(manifold.edges(), manifold.N1());
406 REQUIRE_EQ(manifold.faces(), manifold.N2());
407 REQUIRE(manifold.check_simplices());
408 // We have 1 to 8 vertices
409 auto number_of_vertices{manifold.N0()};
410 CHECK_GE(number_of_vertices, 1);
411 CHECK_LE(number_of_vertices, 8);
412 // We have 1 to 12 number_of_cells
413 auto number_of_cells{manifold.N3()};
414 CHECK_GE(number_of_cells, 1);
415 CHECK_LE(number_of_cells, 12);
416 // We have all the time values
417 CHECK_EQ(manifold.min_time(), 1);
418 CHECK_EQ(manifold.max_time(), desired_timeslices);
419 // Human verification
420 manifold.print();
422 }
423 }
424 WHEN("Constructing a small triangulation.")
425 {
426 auto constexpr desired_simplices = 640;
427 auto constexpr desired_timeslices = 4;
428 Manifold_3 const manifold(desired_simplices, desired_timeslices);
429 THEN("Triangulation is valid.") { REQUIRE(manifold.is_correct()); }
430 THEN("The geometry matches the triangulation.")
431 {
432 REQUIRE(manifold.is_foliated());
433 REQUIRE_EQ(manifold.vertices(), manifold.N0());
434 REQUIRE_EQ(manifold.edges(), manifold.N1());
435 REQUIRE_EQ(manifold.faces(), manifold.N2());
436 REQUIRE(manifold.check_simplices());
437 // Human verification
438 manifold.print();
440 }
441 }
442 WHEN("Constructing a medium triangulation.")
443 {
444 auto constexpr desired_simplices = 6400;
445 auto constexpr desired_timeslices = 7;
446 Manifold_3 const manifold(desired_simplices, desired_timeslices);
447 THEN("Triangulation is valid.") { REQUIRE(manifold.is_correct()); }
448 THEN("The geometry matches the triangulation.")
449 {
450 REQUIRE(manifold.is_foliated());
451 REQUIRE_EQ(manifold.vertices(), manifold.N0());
452 REQUIRE_EQ(manifold.edges(), manifold.N1());
453 REQUIRE_EQ(manifold.faces(), manifold.N2());
454 REQUIRE(manifold.check_simplices());
455 // Human verification
456 manifold.print();
458 }
459 }
460 }
461}
462
463SCENARIO("3-Manifold function checks" * doctest::test_suite("manifold"))
464{
465 spdlog::debug("3-Manifold function checks.\n");
466 GIVEN("The default manifold from the default triangulation")
467 {
468 THEN("There is only one vertex, the infinite vertex.")
469 {
470 Manifold_3 const manifold;
471 auto&& vertices =
472 manifold.get_triangulation().get_delaunay().tds().vertices();
473 auto&& vertex = vertices.begin();
474
475 CHECK_EQ(vertices.size(), 1);
476 CHECK(manifold.is_vertex(vertex));
477 CHECK(manifold.get_triangulation().is_infinite(vertex));
478 }
479 }
480
481 GIVEN("A 3-manifold")
482 {
483 WHEN("It is initialized.")
484 {
485 auto constexpr desired_timeslices = 4;
486 auto constexpr desired_simplices = 640;
487 Manifold_3 const manifold(desired_simplices, desired_timeslices);
488 THEN("Functions referencing geometry data are accurate")
489 {
490 CHECK_EQ(manifold.N3(), manifold.get_geometry().N3);
491 CHECK_EQ(manifold.N3_31(), manifold.get_geometry().N3_31);
492 CHECK_EQ(manifold.N3_13(), manifold.get_geometry().N3_13);
493 CHECK_EQ(manifold.N3_31_13(), manifold.get_geometry().N3_31_13);
494 CHECK_EQ(manifold.N3_22(), manifold.get_geometry().N3_22);
495 CHECK_EQ(manifold.N2(), manifold.get_geometry().N2);
496 CHECK_EQ(manifold.N1(), manifold.get_geometry().N1);
497 CHECK_EQ(manifold.N1_TL(), manifold.get_geometry().N1_TL);
498 CHECK_EQ(manifold.N1_SL(), manifold.get_geometry().N1_SL);
499 CHECK_EQ(manifold.N0(), manifold.get_geometry().N0);
500 }
501 }
502 }
503}
504SCENARIO("3-Manifold copying" * doctest::test_suite("manifold"))
505{
506 spdlog::debug("3-Manifold copying.\n");
507 GIVEN("A 3-manifold.")
508 {
509 auto constexpr desired_simplices = 640;
510 auto constexpr desired_timeslices = 4;
511 Manifold_3 manifold(desired_simplices, desired_timeslices);
512 WHEN("It is copied.")
513 {
514 auto manifold2 = manifold;
515
516 THEN("The two objects are distinct.")
517 {
518 auto* manifold_ptr = &manifold;
519 auto* manifold2_ptr = &manifold2;
520 CHECK_NE(manifold_ptr, manifold2_ptr);
521 }
522 THEN("The manifolds have identical properties.")
523 {
524 CHECK_EQ(manifold2.N3(), manifold.N3());
525 CHECK_EQ(manifold2.N3_31(), manifold.N3_31());
526 CHECK_EQ(manifold2.N3_22(), manifold.N3_22());
527 CHECK_EQ(manifold2.N3_13(), manifold.N3_13());
528 CHECK_EQ(manifold2.N3_31_13(), manifold.N3_31_13());
529 CHECK_EQ(manifold2.N2(), manifold.N2());
530 CHECK_EQ(manifold2.N1(), manifold.N1());
531 CHECK_EQ(manifold2.N1_TL(), manifold.N1_TL());
532 CHECK_EQ(manifold2.N1_SL(), manifold.N1_SL());
533 CHECK_EQ(manifold2.N0(), manifold.N0());
534 CHECK_EQ(manifold2.max_time(), manifold.max_time());
535 CHECK_EQ(manifold2.min_time(), manifold.min_time());
536 // Human verification
537 fmt::print("Manifold properties:\n");
538 manifold.print();
540 auto cells = manifold.get_delaunay().tds().cells();
541 fmt::print("Cell compact container size == {}\n", cells.size());
542 fmt::print("Now compact container size == {}\n", cells.size());
543 fmt::print("Vertex compact container size == {}\n",
544 manifold.get_triangulation()
545 .get_delaunay()
546 .tds()
547 .vertices()
548 .size());
549 fmt::print("Copied manifold properties:\n");
550 manifold2.print();
551 manifold2.print_volume_per_timeslice();
552 }
553 }
554 }
555}
556
557SCENARIO("3-Manifold update geometry" * doctest::test_suite("manifold"))
558{
559 spdlog::debug("3-Manifold update geometry.\n");
560 GIVEN("A 3-manifold.")
561 {
562 auto constexpr desired_simplices = 640;
563 auto constexpr desired_timeslices = 4;
564 Manifold_3 manifold(desired_simplices, desired_timeslices);
565 WHEN("We call update().")
566 {
567 // Get values for manifold1
568 auto manifold_N3 = manifold.N3();
569 auto manifold_N2 = manifold.N2();
570 auto manifold_N1 = manifold.N1();
571 auto manifold_N0 = manifold.N0();
572 fmt::print("Manifold N3 = {}\n", manifold_N3);
573 fmt::print("Manifold N2 = {}\n", manifold_N2);
574 fmt::print("Manifold N1 = {}\n", manifold_N1);
575 fmt::print("Manifold N0 = {}\n", manifold_N0);
576 manifold.update();
577 fmt::print("update() called.\n");
578 THEN("We get back the same values.")
579 {
580 fmt::print("Manifold N3 is still {}\n", manifold.N3());
581 CHECK_EQ(manifold.N3(), manifold_N3);
582 fmt::print("Manifold N2 is still {}\n", manifold.N2());
583 CHECK_EQ(manifold.N2(), manifold_N2);
584 fmt::print("Manifold N1 is still {}\n", manifold.N1());
585 CHECK_EQ(manifold.N1(), manifold_N1);
586 fmt::print("Manifold N0 is still {}\n", manifold.N0());
587 CHECK_EQ(manifold.N0(), manifold_N0);
588 }
589 }
590 }
591}
592
593SCENARIO("3-Manifold mutation" * doctest::test_suite("manifold"))
594{
595 spdlog::debug("3-Manifold mutation.\n");
596 GIVEN("A pair of 3-manifolds.")
597 {
598 auto constexpr desired_simplices = 640;
599 auto constexpr desired_timeslices = 4;
600 Manifold_3 manifold1(desired_simplices, desired_timeslices);
601 Manifold_3 const manifold2(desired_simplices, desired_timeslices);
602 WHEN("We swap the triangulation of one manifold for another.")
603 {
604 // Get values for manifold1
605 auto manifold1_N3 = manifold1.N3();
606 auto manifold1_N2 = manifold1.N2();
607 auto manifold1_N1 = manifold1.N1();
608 auto manifold1_N0 = manifold1.N0();
609 fmt::print("Manifold 1 N3 = {}\n", manifold1_N3);
610 fmt::print("Manifold 1 N2 = {}\n", manifold1_N2);
611 fmt::print("Manifold 1 N1 = {}\n", manifold1_N1);
612 fmt::print("Manifold 1 N0 = {}\n", manifold1_N0);
613 // Get values for manifold2
614 auto manifold2_N3 = manifold2.N3();
615 auto manifold2_N2 = manifold2.N2();
616 auto manifold2_N1 = manifold2.N1();
617 auto manifold2_N0 = manifold2.N0();
618 fmt::print("Manifold 2 N3 = {}\n", manifold2_N3);
619 fmt::print("Manifold 2 N2 = {}\n", manifold2_N2);
620 fmt::print("Manifold 2 N1 = {}\n", manifold2_N1);
621 fmt::print("Manifold 2 N0 = {}\n", manifold2_N0);
622 // Change manifold1's triangulation to manifold2's
623 manifold1.triangulation() = manifold2.get_triangulation();
624 fmt::print("Manifolds swapped.\n");
625 THEN("Not calling update() gives old values.")
626 {
627 CHECK_EQ(manifold1.N3(), manifold1_N3);
628 CHECK_EQ(manifold1.N2(), manifold1_N2);
629 CHECK_EQ(manifold1.N1(), manifold1_N1);
630 CHECK_EQ(manifold1.N0(), manifold1_N0);
631
632 AND_WHEN("We call update().")
633 {
634 manifold1.update();
635 fmt::print("update() called.\n");
636 THEN("The geometry matches the new triangulation.")
637 {
638 fmt::print("Manifold 1 N3 is now {}\n", manifold1.N3());
639 CHECK_EQ(manifold1.N3(), manifold2_N3);
640 fmt::print("Manifold 1 N2 is now {}\n", manifold1.N2());
641 CHECK_EQ(manifold1.N2(), manifold2_N2);
642 fmt::print("Manifold 1 N1 is now {}\n", manifold1.N1());
643 CHECK_EQ(manifold1.N1(), manifold2_N1);
644 fmt::print("Manifold 1 N0 is now {}\n", manifold1.N0());
645 CHECK_EQ(manifold1.N0(), manifold2_N0);
646 }
647 }
648 }
649 }
650 }
651}
652
653SCENARIO("3-Manifold validation and fixing" * doctest::test_suite("manifold"))
654{
655 spdlog::debug("3-Manifold validation and fixing.\n");
656 using Point = Point_t<3>;
657 GIVEN("A (1,3) and (3,1) stacked on each other.")
658 {
659 vector const Vertices{Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0),
660 Point(0, 0, 1), Point(RADIUS_2, RADIUS_2, RADIUS_2)};
661 vector<size_t> const Timevalues{1, 2, 2, 2, 3};
662 auto causal_vertices =
663 manifolds::make_causal_vertices<3>(Vertices, Timevalues);
664 Manifold_3 manifold(causal_vertices, 0.0, 1.0);
665 auto print = [&manifold](auto& vertex) {
666 fmt::print(
667 "Vertex: ({}) Timevalue: {} is a vertex: {} and is "
668 "infinite: {}\n",
669 utilities::point_to_str(vertex->point()), vertex->info(),
670 manifold.is_vertex(vertex),
671 manifold.get_triangulation().is_infinite(vertex));
672 };
673
674 WHEN("It is constructed.")
675 {
676 THEN("The number of timeslices is correct.")
677 {
678 REQUIRE_EQ(manifold.min_time(), 1);
679 REQUIRE_EQ(manifold.max_time(), 3);
680 }
681 THEN("Every vertex in the manifold has a correct timevalue.")
682 {
683 manifold.print_vertices();
684 REQUIRE(manifold.get_triangulation().check_all_vertices());
685 }
686 THEN("Every cell in the manifold is correctly classified.")
687 {
688 manifold.print_cells();
689 REQUIRE(manifold.check_simplices());
690 }
691 }
692 WHEN("We insert an invalid timevalue into a vertex.")
693 {
694 auto cells = manifold.get_triangulation().get_cells();
695 auto broken_cell = cells[0];
696 auto broken_vertex = broken_cell->vertex(0);
697 fmt::print("Info on vertex was {}\n", broken_vertex->info());
698 broken_vertex->info() = std::numeric_limits<int>::max();
699 fmt::print("Info on vertex is now {}\n", broken_vertex->info());
700 THEN("We can detect invalid vertex timevalues.")
701 {
702 CHECK_FALSE(manifold.is_correct());
703 // Human verification
704 auto bad_vertices =
705 manifold.get_triangulation().find_incorrect_vertices();
706 ranges::for_each(bad_vertices, print);
707 }
708 THEN("But the invalid cell is fixed on update.")
709 {
710 CHECK_FALSE(manifold.check_simplices());
711 manifold.update();
712 manifold.print_cells();
713 CHECK(manifold.check_simplices());
714 }
715 }
716 }
717 GIVEN("A medium sized manifold.")
718 {
719 WHEN("It is constructed.")
720 {
721 auto constexpr desired_timeslices = 7;
722 auto constexpr desired_simplices = 6400;
723 Manifold_3 const manifold(desired_simplices, desired_timeslices);
724 THEN("The triangulation is valid and Delaunay.")
725 {
726 REQUIRE(manifold.is_correct());
727 }
728 THEN("The geometry matches the triangulation.")
729 {
730 REQUIRE(manifold.is_foliated());
731 REQUIRE_EQ(manifold.vertices(), manifold.N0());
732 REQUIRE_EQ(manifold.edges(), manifold.N1());
733 REQUIRE_EQ(manifold.faces(), manifold.N2());
734 REQUIRE_EQ(manifold.simplices(), manifold.N3());
735 }
736 THEN("The number of timeslices is correct.")
737 {
738 REQUIRE_EQ(manifold.min_time(), 1);
739 REQUIRE_EQ(manifold.max_time(), desired_timeslices);
740 }
741 THEN("Every vertex in the manifold has a correct timevalue.")
742 {
743 REQUIRE(manifold.get_triangulation().check_all_vertices());
744 }
745 THEN("Every cell in the manifold is correctly classified.")
746 {
747 REQUIRE(manifold.check_simplices());
748 }
749 }
750 }
751}
Data structures for manifolds.
std::int_fast32_t Int_precision
Definition: Settings.hpp:31
SCENARIO("Perform bistellar flip on Delaunay triangulation" *doctest::test_suite("bistellar"))
void print() const
Print manifold.
Definition: Manifold.hpp:372
auto get_geometry() const -> Geometry const &
Definition: Manifold.hpp:164
auto check_simplices() const -> bool
Definition: Manifold.hpp:352
void print_details() const
Print details of the manifold.
Definition: Manifold.hpp:387
auto get_delaunay() const noexcept
Definition: Manifold.hpp:152
auto N2_SL() const -> auto const &
Definition: Manifold.hpp:262
void print_cells() const
Print timevalues of each vertex in the cell and the resulting cell->info()
Definition: Manifold.hpp:369
auto get_triangulation() const noexcept -> Triangulation const &
Definition: Manifold.hpp:145
auto get_vertex(Point_t< 3 > const &point) const -> Vertex_handle_t< 3 >
Obtains a vertex handle from a point.
Definition: Manifold.hpp:406
void update()
Update the Manifold data structures.
Definition: Manifold.hpp:130
auto simplices() const
Definition: Manifold.hpp:252
auto get_cell(Vertex_handle_t< 3 > const &vh1, Vertex_handle_t< 3 > const &vh2, Vertex_handle_t< 3 > const &vh3, Vertex_handle_t< 3 > const &vh4) const -> Cell_handle_t< 3 >
Get a cell handle from 4 vertex handles.
Definition: Manifold.hpp:419
void print_vertices() const
Print values of a vertex->info()
Definition: Manifold.hpp:365
void print_volume_per_timeslice() const
Print the codimension 1 volume of simplices (faces) per timeslice.
Definition: Manifold.hpp:359
auto is_valid() const -> bool
Forwarding to FoliatedTriangulation.is_tds_valid()
Definition: Manifold.hpp:185
auto is_foliated() const -> bool
Forwarding to FoliatedTriangulation_3.is_foliated()
Definition: Manifold.hpp:171
auto is_delaunay() const -> bool
Forwarding to FoliatedTriangulation.is_delaunay()
Definition: Manifold.hpp:178
auto is_correct() const -> bool
Definition: Manifold.hpp:191
auto is_vertex(VertexType &&t_vertex_candidate) const -> bool
Perfect forwarding to FoliatedTriangulation_3.is_vertex()
Definition: Manifold.hpp:201