Skip to content

Assignment 6: Missing Unit Tests #14

@sapo17

Description

@sapo17

Hello!

First of all, I wanted to thank you for the wonderful lectures (youtube, and lecture notes). I am a visual computing master's student from TU Wien and wish we had this course in our university.

I did the coding assignments by following the lecture notes and recordings to the best of my ability. However, in assignment 6, I had some problems. All my unit tests other than TEST_F(HarmonicBasesTest, compute) were successful. In the end, I managed to find my bug by extending the unit tests---the unit tests are extremely helpful, so thank you!! I basically converted some of the missing JS unit tests to C++. If I did not miss anything, these tests were not available in the C++ version.

Below you can find the extended version of the unit tests for assignment 6 (i.e., test-decomp.cpp).

TEST_F(HarmonicBasesTest, buildPrimalSpanningTree) {
    TreeCotree treeCotree = TreeCotree(HB.mesh, HB.geometry);
    treeCotree.buildPrimalSpanningTree();
    auto nSelfEdges = 0;

    for (const auto& v : HB.mesh->vertices()) {
        if (treeCotree.vertexParent[v] == v) {
            nSelfEdges++;
        }
    }

    EXPECT_TRUE(nSelfEdges == 1)
        << "TreeCotree: buildPrimalSpanningTree does not have "
           "exactly one self-edge (the root)";

    Vertex root;
    for (const Vertex& v : HB.mesh->vertices()) {
        if (treeCotree.vertexParent[v] == v) {
            root = v;
            break;
        }
    }

    const auto n = HB.mesh->nVertices();
    bool connected = true;
    for (Vertex& v : HB.mesh->vertices()) {
        auto path_length = 0;
        while (v != root && path_length < n + 1) {
            v = treeCotree.vertexParent[v];
            path_length += 1;
        }
        if (v != root) {
            connected = false;
            break;
        }
    }
    EXPECT_TRUE(connected)
        << "TreeCotree: buildPrimalSpanningTree graph is not connected";
}

TEST_F(HarmonicBasesTest, inDualSpanningCotree) {
    TreeCotree treeCotree = TreeCotree(HB.mesh, HB.geometry);
    const auto& he = HB.mesh->edge(0).halfedge();
    auto& f1 = he.face();
    auto& f2 = he.twin().face();
    treeCotree.faceParent[f1] = f2;

    EXPECT_TRUE(treeCotree.inDualSpanningCotree(he))
        << "TreeCotree: buildPrimalSpanningTree not recognizes positively "
           "oriented halfedges in tree";

    f1 = he.twin().face();
    f2 = he.face();
    treeCotree.faceParent[f1] = f2;

    EXPECT_TRUE(treeCotree.inDualSpanningCotree(he))
        << "TreeCotree: buildPrimalSpanningTree not recognizes negatifely "
           "oriented "
           "halfedges in tree";

    treeCotree.faceParent.clear();
    EXPECT_FALSE(treeCotree.inDualSpanningCotree(he))
        << "TreeCotree: buildPrimalSpanningTree does not rejects halfedges not "
           "in tree";
}

TEST_F(HarmonicBasesTest, buildDualSpanningTree) {
    TreeCotree treeCotree = TreeCotree(HB.mesh, HB.geometry);
    treeCotree.buildPrimalSpanningTree();
    treeCotree.buildDualSpanningCoTree();

    auto nSelfEdges = 0;
    for (const auto& f : HB.mesh->faces()) {
        if (treeCotree.faceParent[f] == f) {
            nSelfEdges++;
        }
    }

    EXPECT_TRUE(nSelfEdges == 1)
        << "TreeCotree: buildDualSpanningTree does not have "
           "exactly one self-edge (the root)";

    Face root;
    for (const Face& f : HB.mesh->faces()) {
        if (treeCotree.faceParent[f] == f) {
            root = f;
            break;
        }
    }

    const auto n = HB.mesh->nFaces();
    bool connected = true;
    for (Face& f : HB.mesh->faces()) {
        auto path_length = 0;
        while (f != root && path_length < n + 1) {
            f = treeCotree.faceParent[f];
            path_length += 1;
        }
        if (f != root) {
            connected = false;
            break;
        }
    }
    EXPECT_TRUE(connected)
        << "TreeCotree: buildDualSpanningTree graph is not connected";

    for (const auto& e : HB.mesh->edges()) {
        const auto& h = e.halfedge();
        EXPECT_FALSE(treeCotree.inPrimalSpanningTree(h) &&
                     treeCotree.inDualSpanningCotree(h));
    }
}

TEST_F(HarmonicBasesTest, buildGenerators) {
    const auto g = 1 - HB.mesh->eulerCharacteristic() / 2;
    auto treeCotree = TreeCotree(HB.mesh, HB.geometry);
    treeCotree.buildGenerators();
    EXPECT_EQ(treeCotree.generators.size(), 2 * g)
        << "does not have 2g generators";
}

TEST_F(HarmonicBasesTest, buildClosedPrimalOneForm) {
    auto edgeIdx = HB.mesh->getEdgeIndices();
    std::vector<Halfedge> generator;

    for (auto i = 0; i < 5; i++) {
        generator.push_back(HB.mesh->edge(i).halfedge());
    }

    auto& w = HB.buildClosedPrimalOneForm(generator);

    for (const auto& e : HB.mesh->edges()) {
        auto i = edgeIdx[e];
        if (i < 5) {
            EXPECT_TRUE(w[i] != 0) << "HarmonicBases: buildClosedPrimalOneForm "
                                      "has not correct nonzero entries";
        } else {
            EXPECT_EQ(w[i], 0) << "HarmonicBases: buildClosedPrimalOneForm has "
                                  "not correct nonzero entries";
        }
    }

    generator.clear();

    for (auto i = 0; i < 5; i++) {
        if (i % 2 == 0) {
            generator.push_back(HB.mesh->edge(i).halfedge());
        } else {
            generator.push_back(HB.mesh->edge(i).halfedge().twin());
        }
    }

    w = HB.buildClosedPrimalOneForm(generator);

    for (auto e : HB.mesh->edges()) {
        auto i = edgeIdx[e];
        if (i < 5) {
            if (i % 2 == 0) {
                EXPECT_EQ(w[i], 1) << "HarmonicBases: buildClosedPrimalOneForm "
                                      "incorrect orientation";
            } else {
                EXPECT_EQ(w[i], -1)
                    << "HarmonicBases: buildClosedPrimalOneForm "
                       "incorrect orientation";
            }
        } else {
            EXPECT_EQ(w[i], 0) << "HarmonicBases: buildClosedPrimalOneForm "
                                  "incorrect orientation";
        }
    }
}

I am in no way ensuring their correctness, so beware of using it.

Sorry for opening an issue this would have been better as a discussion thread.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions