Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment 6: Missing Unit Tests #14

Open
sapo17 opened this issue Aug 28, 2024 · 0 comments
Open

Assignment 6: Missing Unit Tests #14

sapo17 opened this issue Aug 28, 2024 · 0 comments

Comments

@sapo17
Copy link

sapo17 commented Aug 28, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant