Skip to content

Assignment 6: Missing Unit Tests #14

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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