415 lines
12 KiB
C++
415 lines
12 KiB
C++
// Copyright (C) 2007 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <dlib/graph.h>
|
|
#include <dlib/graph_utils.h>
|
|
#include <dlib/set.h>
|
|
|
|
#include "tester.h"
|
|
|
|
// This is called an unnamed-namespace and it has the effect of making everything inside this file "private"
|
|
// so that everything you declare will have static linkage. Thus we won't have any multiply
|
|
// defined symbol errors coming out of the linker when we try to compile the test suite.
|
|
namespace
|
|
{
|
|
|
|
using namespace test;
|
|
using namespace dlib;
|
|
using namespace std;
|
|
|
|
|
|
|
|
// Declare the logger we will use in this test. The name of the tester
|
|
// should start with "test."
|
|
logger dlog("test.graph");
|
|
|
|
template <
|
|
typename graph
|
|
>
|
|
void graph_test (
|
|
)
|
|
/*!
|
|
requires
|
|
- graph is an implementation of graph/graph_kernel_abstract.h
|
|
is instantiated with int
|
|
ensures
|
|
- runs tests on graph for compliance with the specs
|
|
!*/
|
|
{
|
|
|
|
print_spinner();
|
|
|
|
COMPILE_TIME_ASSERT(is_graph<graph>::value);
|
|
|
|
graph a, b;
|
|
dlib::set<unsigned long>::compare_1b_c s;
|
|
|
|
DLIB_TEST(graph_contains_length_one_cycle(a) == false);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == false);
|
|
|
|
DLIB_TEST(a.number_of_nodes() == 0);
|
|
|
|
a.set_number_of_nodes(5);
|
|
DLIB_TEST(graph_is_connected(a) == false);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == false);
|
|
DLIB_TEST(a.number_of_nodes() == 5);
|
|
DLIB_TEST(graph_contains_length_one_cycle(a) == false);
|
|
|
|
for (int i = 0; i < 5; ++i)
|
|
{
|
|
a.node(i).data = i;
|
|
DLIB_TEST(a.node(i).index() == (unsigned int)i);
|
|
}
|
|
|
|
a.remove_node(1);
|
|
|
|
DLIB_TEST(a.number_of_nodes() == 4);
|
|
|
|
|
|
// make sure that only the number with data == 1 was removed
|
|
int count = 0;
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
count += a.node(i).data;
|
|
DLIB_TEST(a.node(i).number_of_neighbors() == 0);
|
|
DLIB_TEST(a.node(i).index() == (unsigned int)i);
|
|
}
|
|
|
|
DLIB_TEST(count == 9);
|
|
|
|
|
|
a.add_edge(1,1);
|
|
DLIB_TEST(graph_contains_length_one_cycle(a) == true);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == true);
|
|
DLIB_TEST(a.has_edge(1,1));
|
|
DLIB_TEST(a.node(1).number_of_neighbors() == 1);
|
|
|
|
a.add_edge(1,3);
|
|
DLIB_TEST(a.node(1).number_of_neighbors() == 2);
|
|
DLIB_TEST(a.node(2).number_of_neighbors() == 0);
|
|
DLIB_TEST(a.node(3).number_of_neighbors() == 1);
|
|
DLIB_TEST(a.has_edge(1,1));
|
|
DLIB_TEST(a.has_edge(1,3));
|
|
DLIB_TEST(a.has_edge(3,1));
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == true);
|
|
a.remove_edge(1,1);
|
|
DLIB_TEST(graph_contains_length_one_cycle(a) == false);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == false);
|
|
DLIB_TEST(a.node(1).number_of_neighbors() == 1);
|
|
DLIB_TEST(a.node(2).number_of_neighbors() == 0);
|
|
DLIB_TEST(a.node(3).number_of_neighbors() == 1);
|
|
DLIB_TEST(a.has_edge(1,1) == false);
|
|
DLIB_TEST(a.has_edge(1,3));
|
|
DLIB_TEST(a.has_edge(3,1));
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == false);
|
|
|
|
swap(a,b);
|
|
|
|
|
|
DLIB_TEST(graph_contains_undirected_cycle(b) == false);
|
|
DLIB_TEST(b.node(1).number_of_neighbors() == 1);
|
|
DLIB_TEST(b.node(2).number_of_neighbors() == 0);
|
|
DLIB_TEST(b.node(3).number_of_neighbors() == 1);
|
|
DLIB_TEST(b.has_edge(1,1) == false);
|
|
DLIB_TEST(b.has_edge(1,3));
|
|
DLIB_TEST(b.has_edge(3,1));
|
|
DLIB_TEST(graph_contains_undirected_cycle(b) == false);
|
|
|
|
DLIB_TEST(a.number_of_nodes() == 0);
|
|
DLIB_TEST(b.number_of_nodes() == 4);
|
|
|
|
copy_graph_structure(b,b);
|
|
DLIB_TEST(b.number_of_nodes() == 4);
|
|
|
|
b.add_edge(1,2);
|
|
DLIB_TEST(graph_contains_undirected_cycle(b) == false);
|
|
DLIB_TEST(graph_contains_undirected_cycle(b) == false);
|
|
b.add_edge(3,2);
|
|
DLIB_TEST(graph_contains_undirected_cycle(b) == true);
|
|
b.add_edge(1,1);
|
|
DLIB_TEST(graph_is_connected(b) == false);
|
|
b.add_edge(0,2);
|
|
DLIB_TEST(graph_is_connected(b) == true);
|
|
|
|
DLIB_TEST(graph_contains_undirected_cycle(b) == true);
|
|
|
|
DLIB_TEST(a.number_of_nodes() == 0);
|
|
|
|
for (unsigned long i = 0; i < b.number_of_nodes(); ++i)
|
|
{
|
|
for (unsigned long j = 0; j < b.node(i).number_of_neighbors(); ++j)
|
|
{
|
|
b.node(i).edge(j) = 'c';
|
|
}
|
|
}
|
|
|
|
b.node(1).edge(0) = 'a';
|
|
const unsigned long e1 = b.node(1).neighbor(0).index();
|
|
b.node(0).edge(0) = 'n';
|
|
const unsigned long e2 = b.node(0).neighbor(0).index();
|
|
|
|
ostringstream sout;
|
|
serialize(b, sout);
|
|
istringstream sin(sout.str());
|
|
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == false);
|
|
|
|
a.set_number_of_nodes(10);
|
|
deserialize(a, sin);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == true);
|
|
|
|
for (unsigned long i = 0; i < a.number_of_nodes(); ++i)
|
|
{
|
|
for (unsigned long j = 0; j < a.node(i).number_of_neighbors(); ++j)
|
|
{
|
|
if ((i == 0 && a.node(i).neighbor(j).index() == e2) ||
|
|
(i == e2 && a.node(i).neighbor(j).index() == 0) )
|
|
{
|
|
DLIB_TEST(a.node(i).edge(j) == 'n');
|
|
}
|
|
else if ((i == 1 && a.node(i).neighbor(j).index() == e1) ||
|
|
(i == e1 && a.node(i).neighbor(j).index() == 1))
|
|
{
|
|
DLIB_TEST(a.node(i).edge(j) == 'a');
|
|
}
|
|
else
|
|
{
|
|
DLIB_TEST(i != 0 || a.node(i).neighbor(j).index() != e2);
|
|
DLIB_TEST_MSG(a.node(i).edge(j) == 'c',a.node(i).edge(j));
|
|
}
|
|
}
|
|
}
|
|
|
|
DLIB_TEST(a.number_of_nodes() == 4);
|
|
DLIB_TEST(a.has_edge(1,2) == true);
|
|
DLIB_TEST(a.has_edge(3,2) == true);
|
|
DLIB_TEST(a.has_edge(1,1) == true);
|
|
DLIB_TEST(a.has_edge(0,2) == true);
|
|
DLIB_TEST(a.has_edge(1,3) == true);
|
|
DLIB_TEST(a.has_edge(0,1) == false);
|
|
DLIB_TEST(a.has_edge(0,3) == false);
|
|
DLIB_TEST(a.has_edge(0,0) == false);
|
|
DLIB_TEST(a.has_edge(1,0) == false);
|
|
DLIB_TEST(a.has_edge(3,0) == false);
|
|
|
|
|
|
for (unsigned long i = 0; i < a.number_of_nodes(); ++i)
|
|
{
|
|
a.node(i).data = static_cast<int>(i);
|
|
}
|
|
|
|
a.remove_node(2);
|
|
DLIB_TEST(a.number_of_nodes() == 3);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == true);
|
|
|
|
count = 0;
|
|
for (unsigned long i = 0; i < a.number_of_nodes(); ++i)
|
|
{
|
|
if (a.node(i).data == 0)
|
|
{
|
|
DLIB_TEST(a.node(i).number_of_neighbors() == 0);
|
|
}
|
|
else if (a.node(i).data == 1)
|
|
{
|
|
DLIB_TEST(a.node(i).number_of_neighbors() == 2);
|
|
}
|
|
else if (a.node(i).data == 3)
|
|
{
|
|
DLIB_TEST(a.node(i).number_of_neighbors() == 1);
|
|
}
|
|
else
|
|
{
|
|
DLIB_TEST_MSG(false,"this is impossible");
|
|
}
|
|
|
|
for (unsigned long j = 0; j < a.number_of_nodes(); ++j)
|
|
{
|
|
if ((a.node(i).data == 1 && a.node(j).data == 1) ||
|
|
(a.node(i).data == 1 && a.node(j).data == 3) ||
|
|
(a.node(i).data == 3 && a.node(j).data == 1))
|
|
{
|
|
DLIB_TEST(a.has_edge(i,j) == true);
|
|
++count;
|
|
}
|
|
else
|
|
{
|
|
DLIB_TEST(a.has_edge(i,j) == false);
|
|
}
|
|
}
|
|
}
|
|
DLIB_TEST_MSG(count == 3,count);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == true);
|
|
a.remove_edge(1,1);
|
|
DLIB_TEST(graph_contains_undirected_cycle(a) == false);
|
|
|
|
DLIB_TEST(b.number_of_nodes() == 4);
|
|
b.clear();
|
|
DLIB_TEST(b.number_of_nodes() == 0);
|
|
|
|
|
|
a.clear();
|
|
|
|
/*
|
|
1 7
|
|
| / \
|
|
2 6 0
|
|
\ / |
|
|
3 /
|
|
/ \ /
|
|
4 5
|
|
*/
|
|
a.set_number_of_nodes(8);
|
|
a.add_edge(1,2);
|
|
a.add_edge(2,3);
|
|
a.add_edge(3,4);
|
|
a.add_edge(3,5);
|
|
a.add_edge(3,6);
|
|
a.add_edge(6,7);
|
|
a.add_edge(7,0);
|
|
a.add_edge(0,5);
|
|
|
|
DLIB_TEST(graph_is_connected(a));
|
|
|
|
dlib::set<dlib::set<unsigned long>::compare_1b_c>::kernel_1b_c sos;
|
|
|
|
dlib::graph<dlib::set<unsigned long>::compare_1b_c, dlib::set<unsigned long>::compare_1b_c>::kernel_1a_c join_tree;
|
|
unsigned long temp;
|
|
triangulate_graph_and_find_cliques(a,sos);
|
|
DLIB_TEST(a.number_of_nodes() == 8);
|
|
|
|
create_join_tree(a, join_tree);
|
|
DLIB_TEST(join_tree.number_of_nodes() == 6);
|
|
DLIB_TEST(graph_is_connected(join_tree) == true);
|
|
DLIB_TEST(graph_contains_undirected_cycle(join_tree) == false);
|
|
DLIB_TEST(is_join_tree(a, join_tree));
|
|
|
|
// check old edges
|
|
DLIB_TEST(a.has_edge(1,2));
|
|
DLIB_TEST(a.has_edge(2,3));
|
|
DLIB_TEST(a.has_edge(3,4));
|
|
DLIB_TEST(a.has_edge(3,5));
|
|
DLIB_TEST(a.has_edge(3,6));
|
|
DLIB_TEST(a.has_edge(6,7));
|
|
DLIB_TEST(a.has_edge(7,0));
|
|
DLIB_TEST(a.has_edge(0,5));
|
|
|
|
DLIB_TEST(graph_is_connected(a));
|
|
|
|
DLIB_TEST(sos.size() == 6);
|
|
|
|
|
|
temp = 1; s.add(temp);
|
|
temp = 2; s.add(temp);
|
|
DLIB_TEST(sos.is_member(s));
|
|
s.clear();
|
|
temp = 2; s.add(temp);
|
|
temp = 3; s.add(temp);
|
|
DLIB_TEST(sos.is_member(s));
|
|
s.clear();
|
|
temp = 4; s.add(temp);
|
|
temp = 3; s.add(temp);
|
|
DLIB_TEST(sos.is_member(s));
|
|
|
|
sos.reset();
|
|
while (sos.move_next())
|
|
{
|
|
DLIB_TEST(is_clique(a, sos.element()));
|
|
DLIB_TEST(is_maximal_clique(a, sos.element()));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void test_copy()
|
|
{
|
|
{
|
|
graph<int,int>::kernel_1a_c a,b;
|
|
|
|
a.set_number_of_nodes(3);
|
|
a.node(0).data = 1;
|
|
a.node(1).data = 2;
|
|
a.node(2).data = 3;
|
|
a.add_edge(0,1);
|
|
a.add_edge(0,2);
|
|
edge(a,0,1) = 4;
|
|
edge(a,0,2) = 5;
|
|
|
|
a.add_edge(0,0);
|
|
edge(a,0,0) = 9;
|
|
copy_graph(a, b);
|
|
|
|
DLIB_TEST(b.number_of_nodes() == 3);
|
|
DLIB_TEST(b.node(0).data == 1);
|
|
DLIB_TEST(b.node(1).data == 2);
|
|
DLIB_TEST(b.node(2).data == 3);
|
|
DLIB_TEST(edge(b,0,1) == 4);
|
|
DLIB_TEST(edge(b,0,2) == 5);
|
|
DLIB_TEST(edge(b,0,0) == 9);
|
|
}
|
|
{
|
|
graph<int,int>::kernel_1a_c a,b;
|
|
|
|
a.set_number_of_nodes(4);
|
|
a.node(0).data = 1;
|
|
a.node(1).data = 2;
|
|
a.node(2).data = 3;
|
|
a.node(3).data = 8;
|
|
a.add_edge(0,1);
|
|
a.add_edge(0,2);
|
|
a.add_edge(2,3);
|
|
edge(a,0,1) = 4;
|
|
edge(a,0,2) = 5;
|
|
edge(a,2,3) = 6;
|
|
|
|
copy_graph(a, b);
|
|
|
|
DLIB_TEST(b.number_of_nodes() == 4);
|
|
DLIB_TEST(b.node(0).data == 1);
|
|
DLIB_TEST(b.node(1).data == 2);
|
|
DLIB_TEST(b.node(2).data == 3);
|
|
DLIB_TEST(b.node(3).data == 8);
|
|
DLIB_TEST(edge(b,0,1) == 4);
|
|
DLIB_TEST(edge(b,0,2) == 5);
|
|
DLIB_TEST(edge(b,2,3) == 6);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class graph_tester : public tester
|
|
{
|
|
/*!
|
|
WHAT THIS OBJECT REPRESENTS
|
|
This object represents a test for the graph object. When it is constructed
|
|
it adds itself into the testing framework. The command line switch is
|
|
specified as test_directed_graph by passing that string to the tester constructor.
|
|
!*/
|
|
public:
|
|
graph_tester (
|
|
) :
|
|
tester ("test_graph",
|
|
"Runs tests on the graph component.")
|
|
{}
|
|
|
|
void perform_test (
|
|
)
|
|
{
|
|
dlog << LINFO << "testing kernel_1a_c";
|
|
graph_test<graph<int>::kernel_1a_c>();
|
|
|
|
dlog << LINFO << "testing kernel_1a";
|
|
graph_test<graph<int>::kernel_1a>();
|
|
|
|
test_copy();
|
|
}
|
|
} a;
|
|
|
|
|
|
}
|
|
|
|
|
|
|