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