Commit 2ab7afe9 authored by Davis King's avatar Davis King

Added some more unit tests. Also fixed a bug in the potts_model_score() routine.

parent 9cc3947a
...@@ -439,7 +439,9 @@ namespace dlib ...@@ -439,7 +439,9 @@ namespace dlib
for (unsigned long n = 0; n < g.number_of_neighbors(i); ++n) for (unsigned long n = 0; n < g.number_of_neighbors(i); ++n)
{ {
const unsigned long idx2 = g.get_neighbor(i,n); const unsigned long idx2 = g.get_neighbor(i,n);
if (g.get_label(i) != g.get_label(idx2) && i < idx2) const bool label_i = (g.get_label(i)!=0);
const bool label_idx2 = (g.get_label(idx2)!=0);
if (label_i != label_idx2 && i < idx2)
score -= g.factor_value_disagreement(i, idx2); score -= g.factor_value_disagreement(i, idx2);
} }
} }
...@@ -447,6 +449,49 @@ namespace dlib ...@@ -447,6 +449,49 @@ namespace dlib
return score; return score;
} }
// ----------------------------------------------------------------------------------------
template <
typename graph_type
>
typename graph_type::edge_type potts_model_score (
const graph_type& g,
const std::vector<node_label>& labels
)
{
DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,
"\t edge_type potts_model_score(g,labels)"
<< "\n\t Invalid inputs were given to this function."
);
typedef typename graph_type::edge_type edge_type;
typedef typename graph_type::type type;
// The edges and node's have to use the same type to represent factor weights!
COMPILE_TIME_ASSERT((is_same_type<edge_type, type>::value == true));
typename graph_type::edge_type score = 0;
for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
{
const bool label = (labels[i]!=0);
if (label)
score += g.node(i).data;
}
for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
{
for (unsigned long n = 0; n < g.node(i).number_of_neighbors(); ++n)
{
const unsigned long idx2 = g.node(i).neighbor(n).index();
const bool label_i = (labels[i]!=0);
const bool label_idx2 = (labels[idx2]!=0);
if (label_i != label_idx2 && i < idx2)
score -= g.node(i).edge(n);
}
}
return score;
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
......
...@@ -191,6 +191,42 @@ namespace dlib ...@@ -191,6 +191,42 @@ namespace dlib
- Then this function returns F - D - Then this function returns F - D
!*/ !*/
// ----------------------------------------------------------------------------------------
template <
typename graph_type
>
typename graph_type::edge_type potts_model_score (
const graph_type& g,
const std::vector<node_label>& labels
);
/*!
requires
- graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
- graph_type::edge_type is some signed type such as int or double
- graph_type::type must be the same type as graph_type::edge_type
- graph_contains_length_one_cycle(g) == false
ensures
- This function does the same thing as the version of potts_model_score()
defined above, except that this version operates on a dlib::graph
instead of a potts_problem object.
- computes the model score for the given graph and labeling. We define this
precisely below:
- let L(i) == the boolean label of the ith variable in g. Or in other
words, L(i) == (labels[i] != 0).
- let F == the sum of values of g.node(i).data for only i values
where L(i) == true.
- Let D == the sum of values of edge(g,i,j) for only i and j
values which meet the following conditions:
- i and j are neighbors in the graph defined by g, that is,
it is valid to call edge(g,i,j).
- L(i) != L(j)
- i < j
(i.e. We want to make sure to only count the edge between i and j once)
- Then this function returns F - D
!*/
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
...@@ -232,7 +268,8 @@ namespace dlib ...@@ -232,7 +268,8 @@ namespace dlib
- This routine simply converts g into a potts_problem and calls the - This routine simply converts g into a potts_problem and calls the
version of find_max_factor_graph_potts() defined above on it. Therefore, version of find_max_factor_graph_potts() defined above on it. Therefore,
this routine is just a convenience wrapper that lets you use a dlib::graph this routine is just a convenience wrapper that lets you use a dlib::graph
to represent a potts problem. to represent a potts problem. This means that this function maximizes
the value of potts_model_score(g, #labels).
- #labels.size() == g.number_of_nodes() - #labels.size() == g.number_of_nodes()
- for all valid i: - for all valid i:
- #labels[i] == the optimal label for g.node(i) - #labels[i] == the optimal label for g.node(i)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <dlib/graph_cuts.h> #include <dlib/graph_cuts.h>
#include <dlib/graph_utils.h> #include <dlib/graph_utils.h>
#include <dlib/directed_graph.h> #include <dlib/directed_graph.h>
#include <dlib/graph.h>
#include <dlib/rand.h> #include <dlib/rand.h>
#include "tester.h" #include "tester.h"
...@@ -338,6 +339,125 @@ namespace ...@@ -338,6 +339,125 @@ namespace
} }
} }
// ----------------------------------------------------------------------------------------
template <typename graph_type>
void brute_force_potts_model_on_graph (
const graph_type& g,
std::vector<node_label>& labels_
)
{
std::vector<node_label> labels;
labels.resize(g.number_of_nodes());
const unsigned long num = (unsigned long)std::pow(2.0, (double)g.number_of_nodes());
double best_score = -std::numeric_limits<double>::infinity();
for (unsigned long i = 0; i < num; ++i)
{
for (unsigned long j = 0; j < g.number_of_nodes(); ++j)
{
unsigned long T = (1)<<j;
T = (T&i);
if (T != 0)
labels[j] = SINK_CUT;
else
labels[j] = SOURCE_CUT;
}
double score = potts_model_score(g,labels);
if (score > best_score)
{
best_score = score;
labels_ = labels;
}
}
}
// ----------------------------------------------------------------------------------------
template <typename graph_type>
void make_random_undirected_graph(
dlib::rand& rnd,
graph_type& g
)
{
typedef typename graph_type::edge_type edge_weight_type;
g.clear();
const unsigned int num_nodes = rnd.get_random_32bit_number()%8;
g.set_number_of_nodes(num_nodes);
const unsigned int num_edges = static_cast<unsigned int>(num_nodes*(num_nodes-1)/2*rnd.get_random_double() + 0.5);
// add the right number of randomly selected edges
unsigned int count = 0;
while (count < num_edges)
{
unsigned long i = rnd.get_random_32bit_number()%g.number_of_nodes();
unsigned long j = rnd.get_random_32bit_number()%g.number_of_nodes();
if (i != j && g.has_edge(i, j) == false)
{
++count;
g.add_edge(i, j);
edge(g, i, j) = static_cast<edge_weight_type>(rnd.get_random_double()*50);
}
}
for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
{
g.node(i).data = static_cast<edge_weight_type>(rnd.get_random_gaussian()*200);
}
}
// ----------------------------------------------------------------------------------------
void test_graph_potts_model(
dlib::rand& rnd
)
{
using namespace std;
double brute_force_score;
double graph_cut_score;
graph<double,double>::kernel_1a_c temp;
make_random_undirected_graph(rnd,temp);
{
std::vector<node_label> labels;
brute_force_potts_model_on_graph(temp, labels);
for (unsigned long i = 0; i < temp.number_of_nodes(); ++i)
{
dlog << LTRACE << "node " << i << ": "<< (int)labels[i];
}
brute_force_score = potts_model_score(temp, labels);
dlog << LTRACE << "brute force score: "<< brute_force_score;
}
dlog << LTRACE << "******************";
{
std::vector<node_label> labels;
find_max_factor_graph_potts(temp, labels);
DLIB_TEST(temp.number_of_nodes() == labels.size());
for (unsigned long i = 0; i < temp.number_of_nodes(); ++i)
{
dlog << LTRACE << "node " << i << ": "<< (int)labels[i];
}
graph_cut_score = potts_model_score(temp, labels);
dlog << LTRACE << "graph cut score: "<< graph_cut_score;
}
DLIB_TEST_MSG(graph_cut_score == brute_force_score, std::abs(graph_cut_score - brute_force_score));
dlog << LTRACE << "##################";
dlog << LTRACE << "##################";
dlog << LTRACE << "##################";
}
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template <typename potts_prob> template <typename potts_prob>
...@@ -732,6 +852,13 @@ namespace ...@@ -732,6 +852,13 @@ namespace
dense_potts_problem p(6, rnd); dense_potts_problem p(6, rnd);
impl_test_potts_model(p); impl_test_potts_model(p);
} }
for (int k = 0; k < 300; ++k)
{
dlog << LTRACE << "dense_potts_problem iter " << k;
print_spinner();
test_graph_potts_model(rnd);
}
} }
} a; } a;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment