/* Tests basic behavior of the copy constructor and assignment operator. */ void BasicCopyTest() try { #if BasicCopyTestEnabled PrintBanner("Basic Copy Test"); /* For simplicity, we'll use one-dimensional KDTrees in this step. */ KDTree<1, size_t> one; for (size_t i = 0; i < 10; ++i) one[MakePoint(2 * i)] = i; // Load with 0, 2, 4, ..., 18 { /* Create a clone of one and confirm that everything copied correctly. * This uses the copy constructor. */ KDTree<1, size_t> clone = one; /* Basic checks. */ CheckCondition(one.size() == clone.size(), "Copy has the same number of elements as the original."); CheckCondition(one.empty() == clone.empty(), "Copy and original agree on emptiness."); CheckCondition(one.dimension() == clone.dimension(), "Copy and original agree on dimension."); /* Check that everything in one is there. */ for (size_t i = 0; i < 10; ++i) CheckCondition(clone.at(MakePoint(2 * i)) == i, "Element from original present in copy."); /* Check that nothing else is. */ for (size_t i = 0; i < 10; ++i) CheckCondition(!clone.contains(MakePoint(2 * i + 1)), "Other elements not present in copy."); } { /* Create a clone of one and confirm that everything copied correctly. * This uses the assignment operator. */ KDTree<1, size_t> clone; clone = one; /* Basic checks. */ CheckCondition(one.size() == clone.size(), "Copy has the same number of elements as the original."); CheckCondition(one.empty() == clone.empty(), "Copy and original agree on emptiness."); CheckCondition(one.dimension() == clone.dimension(), "Copy and original agree on dimension."); /* Check that everything in one is there. */ for (size_t i = 0; i < 10; ++i) CheckCondition(clone.at(MakePoint(2 * i)) == i, "Element from original present in copy."); /* Check that nothing else is. */ for (size_t i = 0; i < 10; ++i) CheckCondition(!clone.contains(MakePoint(2 * i + 1)), "Other elements not present in copy."); } EndTest(); #else TestDisabled("BasicCopyTest"); #endif } catch (const exception& e) { FailTest(e); }
/* A more merciless test of copy behavior.. */ void ModerateCopyTest() try { #if BasicCopyTestEnabled PrintBanner("Moderate Copy Test"); /* For simplicity, we'll use one-dimensional KDTrees in this step. */ KDTree<1, size_t> one; for (size_t i = 0; i < 10; ++i) one[MakePoint(2 * i)] = i; // Load with 0, 2, 4, ..., 18 { /* Create a clone of one and confirm that everything copied correctly. * This uses the copy constructor. */ KDTree<1, size_t> clone = one; /* Add odd numbers to the clone. */ for (size_t i = 0; i < 10; ++i) clone[MakePoint(2 * i + 1)] = i; /* Confirm that they didn't appear in one. */ CheckCondition(one.size() == 10, "Adding to clone change original size."); for (size_t i = 0; i < 10; ++i) CheckCondition(!one.contains(MakePoint(2 * i + 1)), "Modifying copy doesn't modify original."); } /* Check the integrity of the original out here as well to see that the dtor didn't hose things. */ CheckCondition(one.size() == 10, "After dtor, original is still good."); for (size_t i = 0; i < 10; ++i) { CheckCondition(!one.contains(MakePoint(2 * i + 1)), "After dtor, missing elements still missing."); CheckCondition(one[MakePoint(2 * i)] == i, "After dtor, original elements are still there."); } { /* Create a clone of one and confirm that everything copied correctly. * This uses the assignment operator. */ KDTree<1, size_t> clone; clone = one; /* Do awful, awful things to the copy. */ clone = clone = (clone = clone); (clone = one) = clone; clone = clone = clone = clone = clone; } EndTest(); #else TestDisabled("ModerateCopyTest"); #endif } catch (const exception& e) { FailTest(e); }
/* Basic test: Can we build a small tree and look up the elements it contains? */ void BasicKDTreeTest() try { #if BasicKDTreeTestEnabled PrintBanner("Basic KDTree Test"); /* Construct the KDTree. */ KDTree<3, size_t> kd; CheckCondition(true, "KDTree construction completed."); /* Check basic properties of the KDTree. */ CheckCondition(kd.dimension() == 3, "Dimension is three."); CheckCondition(kd.size() == 0, "New KD tree has no elements."); CheckCondition(kd.empty(), "New KD tree is empty."); /* Add some elements. */ const double dataPoints[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }; for (size_t i = 0; i < 3; ++i) kd.insert(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3), i); /* Check basic properties again. */ CheckCondition(kd.size() == 3, "After adding three elements, KDTree has size 3."); CheckCondition(!kd.empty(), "After adding three elements, KDTree is not empty."); /* Make sure that the elements we built the tree out of are still there. */ CheckCondition(kd.contains(PointFromRange<3>(dataPoints[0], dataPoints[0] + 3)), "New KD tree has element zero."); CheckCondition(kd.contains(PointFromRange<3>(dataPoints[1], dataPoints[1] + 3)), "New KD tree has element one."); CheckCondition(kd.contains(PointFromRange<3>(dataPoints[2], dataPoints[2] + 3)), "New KD tree has element two."); /* Make sure that the values of these points are correct. */ for (size_t i = 0; i < 3; ++i) CheckCondition(kd.at(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)) == i, "New KD tree has correct values."); EndTest(); #else TestDisabled("BasicKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* This test actively mutates the elements of the KDTree using * operator[]. If you are failing this test, check to make sure * that your implementation of operator[] correctly allows for * mutation and that it inserts elements if they don't already * exist. */ void MutatingKDTreeTest() try { #if MutatingKDTreeTestEnabled PrintBanner("Mutating KDTree Test"); /* Build the data set. */ const double dataPoints[8][3] = { {0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0}, {1, 1, 1}, }; /* Add points using []. */ KDTree<3, size_t> kd; for (size_t i = 0; i < 8; ++i) kd[PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)] = i; /* Basic checks. */ CheckCondition(kd.dimension() == 3, "Dimension is three."); CheckCondition(kd.size() == 8, "New KD tree has the right number of elements."); CheckCondition(!kd.empty(), "New KD tree is nonempty."); /* Make sure everything can be found. */ for (size_t i = 0; i < kd.size(); ++i) CheckCondition(kd.contains(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)), "Lookup succeeded."); /* Change every other element to have key 0. */ for (size_t i = 0; i < 8; i += 2) kd[PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)] = 0; /* Check that the keys are right. */ for (size_t i = 1; i < 8; i += 2) CheckCondition(kd[PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)] == i, "Keys are correct for odd elements."); /* Check that the keys are right. */ for (size_t i = 0; i < 8; i += 2) CheckCondition(kd[PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)] == 0, "Keys are correct for even elements."); EndTest(); #else TestDisabled("MutatingKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* A trickier test that involves looking up nonexistent elements and working with a * larger data set. */ void ModerateKDTreeTest() try { #if ModerateKDTreeTestEnabled PrintBanner("Moderate KDTree Test"); /* Build the data set. */ const double dataPoints[][4] = { {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1}, {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 0, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 1}, }; KDTree<4, size_t> kd; for (size_t i = 0; i < 16; ++i) kd.insert(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4), i); /* Check that basic properties hold. */ CheckCondition(kd.dimension() == 4, "Dimension is four."); CheckCondition(kd.size() == 16, "New KD tree has the right number of elements."); CheckCondition(!kd.empty(), "New KD tree is nonempty."); /* Make sure that the values of these points are correct. */ for (size_t i = 0; i < 16; ++i) CheckCondition(kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i, "New KD tree has correct values."); /* Try looking up some nonexistent elements and see what happens. */ CheckCondition(!kd.contains(MakePoint(1.0, 1.0, 1.0, 0.5)), "Nonexistent elements aren't in the tree."); CheckCondition(!kd.contains(MakePoint(0.0, 0.0, 0.0, -0.5)), "Nonexistent elements aren't in the tree."); EndTest(); #else TestDisabled("ModerateKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* This test still uses just the basic functionality, but it hammers it a bit more * by checking for strange edge cases like duplicated elements. */ void HarderKDTreeTest() try { #if HarderKDTreeTestEnabled PrintBanner("Harder KDTree Test"); /* Build the data set. */ const double dataPoints[][4] = { {0, 0, 0, 0}, {0, 1, 0, 1}, {0, 0, 0, 0}, // Duplicate! {0, 1, 0, 1}, // Duplicate! {0, 1, 1, 0}, {1, 0, 1, 0}, }; KDTree<4, size_t> kd; for (size_t i = 0; i < 6; ++i) kd.insert(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4), i); /* Check basic properties. */ CheckCondition(kd.dimension() == 4, "Dimension is four."); CheckCondition(kd.size() == 4, "New KD tree has the right number of elements (no duplicates)."); CheckCondition(!kd.empty(), "New KD tree is nonempty."); /* Make sure that elements are still there, without checking values. */ for (size_t i = 0; i < 6; ++i) CheckCondition(kd.contains(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)), "New KD tree has original elems."); /* Check that the elements have the correct keys. Elements [2, 6) should have the * correct keys, but elements 0 and 1 will have the keys of elements 2 and 3 because * they were overwritten. */ for (size_t i = 2; i < 6; ++i) CheckCondition(kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i, "KD tree has correct labels."); for (size_t i = 0; i < 2; ++i) CheckCondition(kd.at(PointFromRange<4>(dataPoints[i], dataPoints[i] + 4)) == i + 2, "Insert overwrites old labels."); EndTest(); #else TestDisabled("HarderKDTreeTest"); #endif } catch (const exception& e) { FailTest(e); }
/* This test builds a KDTree where the data has the same values everywhere except * along one coordinate axis. If you are failing this test case, make sure that * your implementation of find() descends into the left subtree only if the current * coordinate is _strictly less_ than the partition point's coordinate. */ void EdgeCaseKDTreeTest() try { #if EdgeCaseKDTreeTestEnabled PrintBanner("Edge Case KDTree Test"); /* Build the data set. */ const double dataPoints[8][3] = { {0, 0, 0}, {0, 1, 0}, {0, 2, 0}, {0, 3, 0}, {0, 4, 0}, {0, 5, 0}, {0, 6, 0}, {0, 7, 0}, }; /* Add points. */ KDTree<3, size_t> kd; for (size_t i = 0; i < 8; ++i) kd.insert(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3), i); /* Basic checks. */ CheckCondition(kd.dimension() == 3, "Dimension is three."); CheckCondition(kd.size() == 8, "New KD tree has the right number of elements."); CheckCondition(!kd.empty(), "New KD tree is nonempty."); /* Make sure everything can be found. */ for (size_t i = 0; i < kd.size(); ++i) CheckCondition(kd.contains(PointFromRange<3>(dataPoints[i], dataPoints[i] + 3)), "Lookup succeeded."); EndTest(); #else TestDisabled("EdgeCaseTreeTest"); #endif } catch (const exception& e) { FailTest(e); }