ccsoft  0.0.0
Convolutional codes library with soft decision decoding
/shared/development/google_code/rssoft/libccsoft/lib/CC_FanoDecoding_FA.h
Go to the documentation of this file.
00001 /*
00002  Copyright 2013 Edouard Griffiths <f4exb at free dot fr>
00003 
00004  This file is part of CCSoft. A Convolutional Codes Soft Decoding library
00005 
00006  This program is free software; you can redistribute it and/or modify
00007  it under the terms of the GNU General Public License as published by
00008  the Free Software Foundation; either version 2 of the License, or
00009  (at your option) any later version.
00010 
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU General Public License for more details.
00015 
00016  You should have received a copy of the GNU General Public License
00017  along with this program; if not, write to the Free Software
00018  Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA
00019 
00020  Convolutional soft-decision decoder based on the Fano sequential algorithm as described in
00021  Sequential Decoding of Convolutional Codes by Yunghsiang S. Han and Po-Ning Chen (algorithm p.26)
00022  web.ntpu.edu.tw/~yshan/book_chapter.pdf
00023 
00024  Uses a node+edge combo code tree representation‎
00025 
00026  */
00027 #ifndef __CC_FANO_DECODING_FA_H__
00028 #define __CC_FANO_DECODING_FA_H__
00029 
00030 #include "CC_SequentialDecoding_FA.h"
00031 #include "CC_SequentialDecodingInternal_FA.h"
00032 #include "CC_Encoding_FA.h"
00033 #include "CCSoft_Exception.h"
00034 #include "CC_TreeNodeEdge_FA.h"
00035 #include "CC_ReliabilityMatrix.h"
00036 #include "Debug.h"
00037 
00038 #include <cmath>
00039 #include <time.h>
00040 #include <algorithm>
00041 #include <iostream>
00042 #include <iomanip>
00043 
00044 namespace ccsoft
00045 {
00046 
00056 template<typename T_Register, typename T_IOSymbol, unsigned int N_k>
00057 class CC_FanoDecoding_FA : public CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k> ,public CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, bool, N_k>
00058 {
00059 public:
00073         CC_FanoDecoding_FA(const std::vector<unsigned int>& constraints,
00074             const std::vector<std::vector<T_Register> >& genpoly_representations,
00075             float _init_threshold,
00076             float _delta_threshold,
00077             unsigned int _tree_cache_size = 0,
00078             float _delta_init_threshold = 0.0) :
00079                 CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k>(constraints, genpoly_representations),
00080                 CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, bool, N_k>(),
00081                 init_threshold(_init_threshold),
00082                 cur_threshold(_init_threshold),
00083                 root_threshold(_init_threshold),
00084                 delta_threshold(_delta_threshold),
00085                 solution_found(false),
00086                 effective_node_count(0),
00087                 nb_moves(0),
00088                 tree_cache_size(_tree_cache_size),
00089                 unloop(_delta_init_threshold < 0.0),
00090                 delta_init_threshold(_delta_init_threshold)
00091     {}
00092 
00096     virtual ~CC_FanoDecoding_FA()
00097     {}
00098 
00103     void set_tree_cache_size(unsigned int _tree_cache_size)
00104     {
00105         tree_cache_size = _tree_cache_size;
00106     }
00107     
00111     void reset()
00112     {
00113         ParentInternal::reset();
00114         Parent::reset();
00115         cur_threshold = init_threshold;
00116         solution_found = false;
00117         effective_node_count = 0;
00118     }
00119 
00126     virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message)
00127     {
00128         FanoNodeEdge *node_edge_current, *node_edge_successor;
00129 
00130         if (relmat.get_message_length() < Parent::encoding.get_m())
00131         {
00132             throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint");
00133         }
00134 
00135         if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n())
00136         {
00137             throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size");
00138         }
00139 
00140         reset();
00141         ParentInternal::init_root(); // initialize root node
00142         Parent::node_count++;
00143         effective_node_count++;
00144         node_edge_current = ParentInternal::root_node;
00145         nb_moves = 0;
00146 
00147 #ifdef _DEBUG
00148         timespec time1, time2;
00149         int time_option = CLOCK_REALTIME;
00150         clock_gettime(time_option, &time1);
00151 #endif
00152 
00153         visit_node_forward(node_edge_current, relmat);
00154 
00155         while (continue_process(node_edge_current, relmat))
00156         {
00157             //std::cout << "T=" << cur_threshold << " depth=" << node_current->get_depth() << " node #" << node_current->get_id() << " Mc=" << node_current->get_path_metric() << std::endl;
00158             DEBUG_OUT(Parent::verbosity > 1, "T=" << cur_threshold << " depth=" << node_edge_current->get_depth() << " node #" << node_edge_current->get_id() << " Mc=" << node_edge_current->get_path_metric() << std::endl);
00159 
00160             if (node_edge_current->get_depth() > Parent::max_depth)
00161             {
00162                 Parent::max_depth = node_edge_current->get_depth();
00163             }
00164 
00165             if (node_edge_current == ParentInternal::root_node)
00166             {
00167                 root_threshold = cur_threshold;
00168             }
00169 
00170             nb_moves++;
00171             const std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges();
00172             typename std::array<FanoNodeEdge*, (1<<N_k)>::const_iterator ne_it = outgoing_node_edges.begin();
00173             std::vector<FanoNodeEdge*> child_node_edges;
00174 
00175             for (; ne_it != outgoing_node_edges.end(); ++ne_it)
00176             {
00177                 if ((*ne_it) && !((*ne_it)->get_tag())) // not traversed back
00178                 {
00179                     child_node_edges.push_back(*ne_it);
00180                 }
00181             }
00182 
00183             if (child_node_edges.size() == 0) // exhausted forward paths
00184             {
00185                 DEBUG_OUT(Parent::verbosity > 2, "exhaustion of forward paths at node #" << node_edge_current->get_id() << std::endl);
00186                 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current);
00187                 continue;
00188             }
00189 
00190             std::sort(child_node_edges.begin(), child_node_edges.end(), node_edge_pointer_ordering<FanoNodeEdge>);
00191             node_edge_successor = *child_node_edges.begin(); // best successor
00192             DEBUG_OUT(Parent::verbosity > 2, "best successor node #" << node_edge_successor->get_id() << " Ms=" << node_edge_successor->get_path_metric() << std::endl);
00193 
00194             if (node_edge_successor->get_path_metric() >= cur_threshold) // Ms >= T
00195             {
00196                 // move forward:
00197                 DEBUG_OUT(Parent::verbosity > 2, "forward" << std::endl);
00198                 FanoNodeEdge *node_predecessor = node_edge_current;
00199                 node_edge_current = node_edge_successor;
00200 
00201                 // termination with solution
00202                 if (node_edge_current->get_depth() == relmat.get_message_length() - 1)
00203                 {
00204                         Parent::codeword_score = node_edge_current->get_path_metric();
00205                     ParentInternal::back_track(node_edge_current, decoded_message, true); // back track from terminal node to retrieve decoded message
00206                     solution_found = true;
00207                     Parent::max_depth++;
00208 #ifdef _DEBUG
00209                     clock_gettime(time_option, &time2);
00210                     DEBUG_OUT(Parent::verbosity > 0, std::cout << "Decoding time: " << std::setw(12) << std::setprecision(9) << debug_get_time_difference(time2,time1) << " s" << std::endl);
00211 #endif
00212                     return true;
00213                 }
00214 
00215                 // threshold tightening for the new current node
00216                 if (node_predecessor->get_path_metric() < cur_threshold + delta_threshold)
00217                 {
00218                     int nb_delta = int((node_edge_current->get_path_metric() - init_threshold) / delta_threshold);
00219 
00220                     if (nb_delta < 0)
00221                     {
00222                         cur_threshold = ((nb_delta - 1) * delta_threshold) + init_threshold;
00223                     }
00224                     else
00225                     {
00226                         cur_threshold = (nb_delta * delta_threshold) + init_threshold;
00227                     }
00228 
00229                     DEBUG_OUT(Parent::verbosity > 2, "tightening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl);
00230                 }
00231 
00232                 // create children nodes from the new current node
00233                 visit_node_forward(node_edge_current, relmat);
00234             }
00235             else
00236             {
00237                 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current);
00238             }
00239         }
00240 
00241         return false;
00242     }
00243 
00249     virtual void print_stats(std::ostream& os, bool success)
00250     {
00251         std::cout << "score = " << Parent::get_score()
00252                 << " cur.threshold = " << cur_threshold
00253                 << " nodes = " << Parent::get_nb_nodes()
00254                 << " eff.nodes = " << effective_node_count
00255                 << " moves = " << nb_moves
00256                 << " max depth = " << Parent::get_max_depth() << std::endl;
00257         std::cout << "_RES " << (success ? 1 : 0) << ","
00258                 << Parent::get_score() << ","
00259                 << cur_threshold << ","
00260                 << Parent::get_nb_nodes() << ","
00261                 << effective_node_count << ","
00262                 << nb_moves << ","
00263                 << Parent::get_max_depth() << std::endl;
00264     }
00265 
00270     virtual void print_dot(std::ostream& os)
00271     {
00272         ParentInternal::print_dot_internal(os);
00273     }
00274 
00275 protected:
00276     typedef CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k> Parent; 
00277     typedef CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, bool, N_k> ParentInternal; 
00278     typedef CC_TreeNodeEdge_FA<T_IOSymbol, T_Register, bool, N_k> FanoNodeEdge;   
00279 
00285     virtual void visit_node_forward(FanoNodeEdge* node_edge, const CC_ReliabilityMatrix& relmat)
00286     {
00287         unsigned int n = Parent::encoding.get_n();
00288         int forward_depth = node_edge->get_depth() + 1;
00289         T_IOSymbol out_symbol;
00290         T_IOSymbol end_symbol;
00291 
00292         // return encoder to appropriate state
00293         if (node_edge->get_depth() >= 0) // does not concern the root node_edge
00294         {
00295             Parent::encoding.set_registers(node_edge->get_registers());
00296         }
00297 
00298         if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m()))
00299         {
00300             end_symbol = 1; // if zero tail option assume tail symbols are all zeros
00301         }
00302         else
00303         {
00304             end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols
00305         }
00306 
00307         if (!node_edge->valid_outgoing_node_edges(end_symbol)) // edges are not cached
00308         {
00309             if ((tree_cache_size > 0) && (effective_node_count >= tree_cache_size)) // if tree cache is used and cache limit reached
00310             {
00311                 purge_tree_cache(node_edge); // purge before allocating new nodes
00312             }
00313 
00314             // loop through assumption for this symbol place and create child nodes
00315             for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++)
00316             {
00317                 Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place
00318                 float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias;
00319                 float forward_path_metric = edge_metric + node_edge->get_path_metric();
00320                 FanoNodeEdge *next_node_edge = new FanoNodeEdge(Parent::node_count++, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth);
00321                 next_node_edge->get_tag() = false; // Init traversed back indicator
00322                 next_node_edge->set_registers(Parent::encoding.get_registers());
00323                 node_edge->set_outgoing_node_edge(next_node_edge, in_symbol); // add forward edge
00324                 effective_node_count++;
00325             }
00326         }
00327     }
00328 
00335     FanoNodeEdge *move_back_from_node_or_loosen_threshold(FanoNodeEdge *node_edge_current)
00336     {
00337         if (node_edge_current == ParentInternal::root_node) // at root node there are no other options than loosening threshold
00338         {
00339             cur_threshold -= delta_threshold;
00340             DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl);
00341         }
00342         else
00343         {
00344             FanoNodeEdge *node_edge_predecessor = node_edge_current->get_incoming_node_edge();
00345 
00346             if (node_edge_predecessor->get_path_metric() >= cur_threshold) // move backward
00347             {
00348                 DEBUG_OUT(Parent::verbosity > 2, std::cout << "backward" << std::endl);
00349 
00350                 if (tree_cache_size == 0) // tree cache is not used
00351                 {
00352                     // delete all successor edges and nodes
00353                     std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges();
00354                     typename std::array<FanoNodeEdge*, (1<<N_k)>::iterator ne_it = outgoing_node_edges.begin();
00355 
00356                     for (;ne_it != outgoing_node_edges.end(); ++ne_it)
00357                     {
00358                         delete *ne_it;
00359                     }
00360 
00361                     effective_node_count -= outgoing_node_edges.size();
00362                     std::fill(outgoing_node_edges.begin(), outgoing_node_edges.end(), (FanoNodeEdge*) 0);
00363                     //outgoing_node_edges.fill(0);
00364                 }
00365 
00366                 // mark incoming edge as traversed back
00367                 if (node_edge_predecessor != ParentInternal::root_node)
00368                 {
00369                     node_edge_current->get_tag() = true;
00370                 }
00371 
00372                 // move back: change node address to previous node address
00373                 node_edge_current = node_edge_predecessor;
00374             }
00375             else // loosen threshold
00376             {
00377                 cur_threshold -= delta_threshold;
00378                 DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl);
00379             }
00380         }
00381 
00382         return node_edge_current;
00383     }
00384 
00388     bool continue_process(FanoNodeEdge *node_edge_current, const CC_ReliabilityMatrix& relmat)
00389     {
00390         if ((node_edge_current == ParentInternal::root_node) && (nb_moves > 0) && (cur_threshold == root_threshold))
00391         {
00392             const std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges();
00393             typename std::array<FanoNodeEdge*, (1<<N_k)>::const_iterator ne_it = outgoing_node_edges.begin();
00394             bool children_open = true;
00395 
00396             for (; ne_it != outgoing_node_edges.end(); ++ne_it)
00397             {
00398                 if ((*ne_it)->get_tag()) // traversed back
00399                 {
00400                     children_open = false;
00401                     break;
00402                 }
00403             }
00404 
00405             if (children_open)
00406             {
00407                 if (unloop && ((Parent::use_metric_limit) && (init_threshold > Parent::metric_limit)))
00408                 {
00409                     init_threshold += delta_init_threshold; // lower initial threshold and start all over again (delta if used is negative)
00410                     Parent::reset();                        // reset but do not delete root node
00411                     cur_threshold = init_threshold;
00412                     solution_found = false;
00413                     ParentInternal::root_node->delete_outgoing_node_edges(); // effectively resets the root node without destroying it
00414                     Parent::node_count = 1;
00415                     effective_node_count = 1;
00416                     nb_moves = 0;
00417                     visit_node_forward(node_edge_current, relmat); // visit root node again
00418                     std::cerr << "Loop condition detected, restart with init threshold = " << init_threshold << std::endl;
00419                     return true;
00420                 }
00421                 else
00422                 {
00423                     std::cerr << "Loop condition detected, aborting" << std::endl;
00424                     return false;
00425                 }
00426             }
00427         }
00428 
00429         if ((Parent::use_metric_limit) && (cur_threshold < Parent::metric_limit))
00430         {
00431             std::cerr << "Metric limit encountered" << std::endl;
00432             return false;
00433         }
00434 
00435         if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit))
00436         {
00437             std::cerr << "Node limit exhausted" << std::endl;
00438             return false;
00439         }
00440 
00441         return true;
00442     }
00443 
00448     void purge_tree_cache(FanoNodeEdge *node_edge)
00449     {
00450         bool node_terminal = true;
00451         unsigned int remaining_nodes = 0;
00452 
00453         while (node_edge != ParentInternal::root_node)
00454         {
00455             FanoNodeEdge *node_edge_predecessor = node_edge->get_incoming_node_edge();
00456             std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_predecessor->get_outgoing_node_edges();
00457             typename std::array<FanoNodeEdge*, (1<<N_k)>::iterator ne_it = outgoing_node_edges.begin();
00458 
00459             for (;ne_it != outgoing_node_edges.end(); ++ne_it)
00460             {
00461                 if (*ne_it) // if using trailing zeros the corresponding edges for input symbol not zero are not constructed
00462                 {
00463                     FanoNodeEdge *node_edge_sibling = (*ne_it);
00464 
00465                     if (node_terminal || (node_edge_sibling != node_edge))
00466                     {
00467                         (*ne_it)->delete_outgoing_node_edges();
00468                     }
00469 
00470                     remaining_nodes++;
00471                 }
00472             }
00473 
00474             node_edge = node_edge_predecessor;
00475             node_terminal = false;
00476         }
00477 
00478         remaining_nodes++; // +1 for root node
00479         effective_node_count = remaining_nodes;
00480         DEBUG_OUT(Parent::verbosity > 1, "purged tree cache, nb of remaining nodes = " << remaining_nodes << std::endl);
00481     }
00482 
00483     float init_threshold;              
00484     float cur_threshold;               
00485     float delta_threshold;             
00486     bool solution_found;               
00487     unsigned int effective_node_count; 
00488     unsigned int nb_moves;             
00489     float root_threshold;              
00490     unsigned int tree_cache_size;      
00491     bool unloop;                       
00492     float delta_init_threshold;        
00493 };
00494 
00495 
00496 
00497 } // namespace ccsoft
00498 
00499 #endif // __CC_FANO_DECODING_FA_H__
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines