Commit fc65fab0 authored by Davis King's avatar Davis King

Changed find_max_factor_graph_viterbi() so you can use run-time

defined order and num_states parameters.
parent afddb2d4
......@@ -62,11 +62,14 @@ namespace dlib
)
{
using namespace dlib::impl;
const unsigned long order = map_problem::order;
const unsigned long num_states = map_problem::num_states;
COMPILE_TIME_ASSERT(num_states > 0);
const unsigned long order = prob.order();
const unsigned long num_states = prob.num_states();
DLIB_ASSERT(prob.num_states() > 0,
"\t void find_max_factor_graph_viterbi()"
<< "\n\t The nodes in a factor graph have to be able to take on more than 0 states."
);
DLIB_ASSERT(std::pow(num_states,(double)order) < std::numeric_limits<unsigned long>::max(),
"\t void find_max_factor_graph_viterbi()"
<< "\n\t The order is way too large for this algorithm to handle."
......@@ -144,32 +147,55 @@ namespace dlib
}
}
else
else if (order == 1)
{
matrix<unsigned long,1,order+1> node_states;
node_states = 0;
unsigned long count = 0;
for (unsigned long i = 0; i < trellis_size; ++i)
{
unsigned long back_index = 0;
double best_score = -std::numeric_limits<double>::infinity();
for (unsigned long s = 0; s < num_states; ++s)
{
const double temp = prob.factor_value(node,node_states) + trellis[node-1][count%trellis_size].val;
if (temp > best_score)
{
best_score = temp;
back_index = count%trellis_size;
}
advance_state(node_states,num_states);
++count;
}
trellis[node][i].val = best_score;
trellis[node][i].back_index = back_index;
/*
WHAT'S THE DEAL WITH THIS PREPROCESSOR MACRO?
Well, if we can declare the dimensions of node_states as a compile
time constant then this function runs significantly faster. So this macro
is here to let us do that. It just lets us avoid replicating this code
block in the following if statements for different order sizes.
*/
#define DLIB_FMFGV_WORK \
node_states = 0; \
unsigned long count = 0; \
for (unsigned long i = 0; i < trellis_size; ++i) \
{ \
unsigned long back_index = 0; \
double best_score = -std::numeric_limits<double>::infinity(); \
for (unsigned long s = 0; s < num_states; ++s) \
{ \
const double temp = prob.factor_value(node,node_states) + trellis[node-1][count%trellis_size].val; \
if (temp > best_score) \
{ \
best_score = temp; \
back_index = count%trellis_size; \
} \
advance_state(node_states,num_states); \
++count; \
} \
trellis[node][i].val = best_score; \
trellis[node][i].back_index = back_index; \
}
matrix<unsigned long,1,2> node_states;
DLIB_FMFGV_WORK
}
else if (order == 2)
{
matrix<unsigned long,1,3> node_states;
DLIB_FMFGV_WORK
}
else if (order == 3)
{
matrix<unsigned long,1,4> node_states;
DLIB_FMFGV_WORK
}
else
{
// The general case, here we don't define the size of node_states at compile time.
matrix<unsigned long,1,0> node_states(order+1);
DLIB_FMFGV_WORK
}
}
......
......@@ -29,13 +29,22 @@ namespace dlib
public:
// This model can represent a high order Markov chain. If order==1 then map_problem
// represents a basic chain-structured graph where nodes only depend on their immediate
// neighbors. However, high order Markov models can also be used by setting order > 1.
const static unsigned long order;
unsigned long order (
) const;
/*!
ensures
- returns the order of this model. The order has the following interpretation:
This model can represent a high order Markov chain. If order()==1 then map_problem
represents a basic chain-structured graph where nodes only depend on their immediate
neighbors. However, high order Markov models can also be used by setting order() > 1.
!*/
// Defines the number of states attainable by each variable/node in the graph.
const static unsigned long num_states;
unsigned long num_states (
) const;
/*!
ensures
- returns the number of states attainable by each variable/node in the graph.
!*/
unsigned long number_of_nodes (
) const;
......@@ -57,13 +66,13 @@ namespace dlib
- EXP::type == unsigned long
(i.e. node_states contains unsigned longs)
- node_id < number_of_nodes()
- node_states.size() == min(node_id, order) + 1
- node_states.size() == min(node_id, order()) + 1
- is_vector(node_states) == true
- max(node_states) < num_states
- max(node_states) < num_states()
ensures
- In a chain-structured graph, each node has a potential function associated with
it. The potential function operates on the variable given by the node as well
as the order previous variables. Therefore, factor_value() returns the value
as the order() previous variables. Therefore, factor_value() returns the value
of the factor/potential function associated with node node_id where the following
nodes take on the values defined below:
- node_states(0) == the value of the node with ID node_id
......@@ -83,8 +92,8 @@ namespace dlib
);
/*!
requires
- map_problem::num_states > 0
- std::pow(map_problem::num_states, map_problem::order) < std::numeric_limits<unsigned long>::max()
- prob.num_states() > 0
- std::pow(prob.num_states(), prob.order()) < std::numeric_limits<unsigned long>::max()
(i.e. The Viterbi algorithm is exponential in the order of the map problem. So don't
make order too large.)
- map_problem == an object with an interface compatible with the map_problem
......@@ -94,11 +103,11 @@ namespace dlib
graphical model or factor graph. That is, it attempts to solve a certain kind of
optimization problem which can be defined as follows:
- Let X denote a set of prob.number_of_nodes() integer valued variables, each taking
a value in the range [0, map_problem::num_states).
a value in the range [0, prob.num_states()).
- Let X(i) = the ith variable in X.
- Let F(i) = factor_value_i(X(i), X(i-1), ..., X(i-map_problem::order))
- Let F(i) = factor_value_i(X(i), X(i-1), ..., X(i-prob.order()))
(This is the value returned by prob.factor_value(i, node_states). Note that
each factor value function operates on at most map_problem::order+1 variables.
each factor's value function operates on at most prob.order()+1 variables.
Moreover, the variables are adjacent and hence the graph is "chain-structured".)
Then this function finds the assignments to the X variables which
......@@ -107,7 +116,7 @@ namespace dlib
- #map_assignment == the result of the optimization.
- #map_assignment.size() == prob.number_of_nodes()
- for all valid i:
- #map_assignment[i] < map_problem::num_states
- #map_assignment[i] < prob.num_states()
- #map_assignment[i] == The MAP assignment for node/variable i.
!*/
......
......@@ -31,12 +31,12 @@ namespace
class map_problem
{
public:
const static unsigned long order = O;
const static unsigned long num_states = NS;
unsigned long order() const { return O; }
unsigned long num_states() const { return NS; }
map_problem()
{
data = randm(number_of_nodes(),(long)std::pow(num_states,(double)order+1), rnd);
data = randm(number_of_nodes(),(long)std::pow(num_states(),(double)order()+1), rnd);
}
unsigned long number_of_nodes (
......@@ -56,11 +56,11 @@ namespace
if (node_states.size() == 1)
return data(node_id, node_states(0));
else if (node_states.size() == 2)
return data(node_id, node_states(0) + node_states(1)*num_states);
return data(node_id, node_states(0) + node_states(1)*NS);
else if (node_states.size() == 3)
return data(node_id, (node_states(0) + node_states(1)*num_states)*num_states + node_states(2));
return data(node_id, (node_states(0) + node_states(1)*NS)*NS + node_states(2));
else
return data(node_id, ((node_states(0) + node_states(1)*num_states)*num_states + node_states(2))*num_states + node_states(3));
return data(node_id, ((node_states(0) + node_states(1)*NS)*NS + node_states(2))*NS + node_states(3));
}
matrix<double> data;
......@@ -78,8 +78,8 @@ namespace
)
{
using namespace dlib::impl;
const int order = map_problem::order;
const int num_states = map_problem::num_states;
const int order = prob.order();
const int num_states = prob.num_states();
map_assignment.resize(prob.number_of_nodes());
double best_score = -std::numeric_limits<double>::infinity();
......
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