ccsoft  0.0.0
Convolutional codes library with soft decision decoding
/shared/development/google_code/rssoft/libccsoft/lib/CC_FanoDecoding.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_H__
00028 #define __CC_FANO_DECODING_H__
00029 
00030 #include "CC_SequentialDecoding.h"
00031 #include "CC_SequentialDecodingInternal.h"
00032 #include "CC_Encoding.h"
00033 #include "CCSoft_Exception.h"
00034 #include "CC_TreeNodeEdge.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 
00052 template<typename T_Register, typename T_IOSymbol>
00053 class CC_FanoDecoding : public CC_SequentialDecoding<T_Register, T_IOSymbol> ,public CC_SequentialDecodingInternal<T_Register, T_IOSymbol, bool>
00054 {
00055 public:
00069         CC_FanoDecoding(const std::vector<unsigned int>& constraints,
00070             const std::vector<std::vector<T_Register> >& genpoly_representations,
00071             float _init_threshold,
00072             float _delta_threshold,
00073             unsigned int _tree_cache_size = 0,
00074             float _delta_init_threshold = 0.0) :
00075                 CC_SequentialDecoding<T_Register, T_IOSymbol>(constraints, genpoly_representations),
00076                 CC_SequentialDecodingInternal<T_Register, T_IOSymbol, bool>(),
00077                 init_threshold(_init_threshold),
00078                 cur_threshold(_init_threshold),
00079                 root_threshold(_init_threshold),
00080                 delta_threshold(_delta_threshold),
00081                 solution_found(false),
00082                 effective_node_count(0),
00083                 nb_moves(0),
00084                 tree_cache_size(_tree_cache_size),
00085                 unloop(_delta_init_threshold < 0.0),
00086                 delta_init_threshold(_delta_init_threshold)
00087     {}
00088 
00092     virtual ~CC_FanoDecoding()
00093     {}
00094 
00099     void set_tree_cache_size(unsigned int _tree_cache_size)
00100     {
00101         tree_cache_size = _tree_cache_size;
00102     }
00103     
00107     void reset()
00108     {
00109         ParentInternal::reset();
00110         Parent::reset();
00111         cur_threshold = init_threshold;
00112         solution_found = false;
00113         effective_node_count = 0;
00114     }
00115 
00122     virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message)
00123     {
00124         FanoNodeEdge *node_edge_current, *node_edge_successor;
00125 
00126         if (relmat.get_message_length() < Parent::encoding.get_m())
00127         {
00128             throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint");
00129         }
00130 
00131         if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n())
00132         {
00133             throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size");
00134         }
00135 
00136         reset();
00137         ParentInternal::init_root(); // initialize root node
00138         Parent::node_count++;
00139         effective_node_count++;
00140         node_edge_current = ParentInternal::root_node;
00141         nb_moves = 0;
00142 
00143 #ifdef _DEBUG
00144         timespec time1, time2;
00145         int time_option = CLOCK_REALTIME;
00146         clock_gettime(time_option, &time1);
00147 #endif
00148 
00149         visit_node_forward(node_edge_current, relmat);
00150 
00151         while (continue_process(node_edge_current, relmat))
00152         {
00153             //std::cout << "T=" << cur_threshold << " depth=" << node_current->get_depth() << " node #" << node_current->get_id() << " Mc=" << node_current->get_path_metric() << std::endl;
00154             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);
00155 
00156             if (node_edge_current->get_depth() > Parent::max_depth)
00157             {
00158                 Parent::max_depth = node_edge_current->get_depth();
00159             }
00160 
00161             if (node_edge_current == ParentInternal::root_node)
00162             {
00163                 root_threshold = cur_threshold;
00164             }
00165 
00166             nb_moves++;
00167             const std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges();
00168             typename std::vector<FanoNodeEdge*>::const_iterator ne_it = outgoing_node_edges.begin();
00169             std::vector<FanoNodeEdge*> child_node_edges;
00170 
00171             for (; ne_it != outgoing_node_edges.end(); ++ne_it)
00172             {
00173                 if (!((*ne_it)->get_tag())) // not traversed back
00174                 {
00175                     child_node_edges.push_back(*ne_it);
00176                 }
00177             }
00178 
00179             if (child_node_edges.size() == 0) // exhausted forward paths
00180             {
00181                 DEBUG_OUT(Parent::verbosity > 2, "exhaustion of forward paths at node #" << node_edge_current->get_id() << std::endl);
00182                 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current);
00183                 continue;
00184             }
00185 
00186             std::sort(child_node_edges.begin(), child_node_edges.end(), node_edge_pointer_ordering<FanoNodeEdge>);
00187             node_edge_successor = *child_node_edges.begin(); // best successor
00188             DEBUG_OUT(Parent::verbosity > 2, "best successor node #" << node_edge_successor->get_id() << " Ms=" << node_edge_successor->get_path_metric() << std::endl);
00189 
00190             if (node_edge_successor->get_path_metric() >= cur_threshold) // Ms >= T
00191             {
00192                 // move forward:
00193                 DEBUG_OUT(Parent::verbosity > 2, "forward" << std::endl);
00194                 FanoNodeEdge *node_predecessor = node_edge_current;
00195                 node_edge_current = node_edge_successor;
00196 
00197                 // termination with solution
00198                 if (node_edge_current->get_depth() == relmat.get_message_length() - 1)
00199                 {
00200                         Parent::codeword_score = node_edge_current->get_path_metric();
00201                     ParentInternal::back_track(node_edge_current, decoded_message, true); // back track from terminal node to retrieve decoded message
00202                     solution_found = true;
00203                     Parent::max_depth++;
00204 #ifdef _DEBUG
00205                     clock_gettime(time_option, &time2);
00206                     DEBUG_OUT(Parent::verbosity > 0, std::cout << "Decoding time: " << std::setw(12) << std::setprecision(9) << debug_get_time_difference(time2,time1) << " s" << std::endl);
00207 #endif
00208                     return true;
00209                 }
00210 
00211                 // threshold tightening for the new current node
00212                 if (node_predecessor->get_path_metric() < cur_threshold + delta_threshold)
00213                 {
00214                     int nb_delta = int((node_edge_current->get_path_metric() - init_threshold) / delta_threshold);
00215 
00216                     if (nb_delta < 0)
00217                     {
00218                         cur_threshold = ((nb_delta - 1) * delta_threshold) + init_threshold;
00219                     }
00220                     else
00221                     {
00222                         cur_threshold = (nb_delta * delta_threshold) + init_threshold;
00223                     }
00224 
00225                     DEBUG_OUT(Parent::verbosity > 2, "tightening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl);
00226                 }
00227 
00228                 // create children nodes from the new current node
00229                 visit_node_forward(node_edge_current, relmat);
00230             }
00231             else
00232             {
00233                 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current);
00234             }
00235         }
00236 
00237         return false;
00238     }
00239 
00245     virtual void print_stats(std::ostream& os, bool success)
00246     {
00247         std::cout << "score = " << Parent::get_score()
00248                 << " cur.threshold = " << cur_threshold
00249                 << " nodes = " << Parent::get_nb_nodes()
00250                 << " eff.nodes = " << effective_node_count
00251                 << " moves = " << nb_moves
00252                 << " max depth = " << Parent::get_max_depth() << std::endl;
00253         std::cout << "_RES " << (success ? 1 : 0) << ","
00254                 << Parent::get_score() << ","
00255                 << cur_threshold << ","
00256                 << Parent::get_nb_nodes() << ","
00257                 << effective_node_count << ","
00258                 << nb_moves << ","
00259                 << Parent::get_max_depth() << std::endl;
00260     }
00261 
00266     virtual void print_dot(std::ostream& os)
00267     {
00268         ParentInternal::print_dot_internal(os);
00269     }
00270 
00271 protected:
00272     typedef CC_SequentialDecoding<T_Register, T_IOSymbol> Parent; 
00273     typedef CC_SequentialDecodingInternal<T_Register, T_IOSymbol, bool> ParentInternal; 
00274     typedef CC_TreeNodeEdge<T_IOSymbol, T_Register, bool> FanoNodeEdge;   
00275 
00281     virtual void visit_node_forward(FanoNodeEdge* node_edge, const CC_ReliabilityMatrix& relmat)
00282     {
00283         unsigned int n = Parent::encoding.get_n();
00284         int forward_depth = node_edge->get_depth() + 1;
00285         T_IOSymbol out_symbol;
00286         T_IOSymbol end_symbol;
00287 
00288         // return encoder to appropriate state
00289         if (node_edge->get_depth() >= 0) // does not concern the root node_edge
00290         {
00291             Parent::encoding.set_registers(node_edge->get_registers());
00292         }
00293 
00294         if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m()))
00295         {
00296             end_symbol = 1; // if zero tail option assume tail symbols are all zeros
00297         }
00298         else
00299         {
00300             end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols
00301         }
00302 
00303         if (node_edge->get_outgoing_node_edges().size() == 0) // edges are not cached
00304         {
00305             if ((tree_cache_size > 0) && (effective_node_count >= tree_cache_size)) // if tree cache is used and cache limit reached
00306             {
00307                 purge_tree_cache(node_edge); // purge before allocating new nodes
00308             }
00309 
00310             // loop through assumption for this symbol place and create child nodes
00311             for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++)
00312             {
00313                 Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place
00314                 float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias;
00315                 float forward_path_metric = edge_metric + node_edge->get_path_metric();
00316                 FanoNodeEdge *next_node_edge = new FanoNodeEdge(Parent::node_count++, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth);
00317                 next_node_edge->get_tag() = false; // Init traversed back indicator
00318                 next_node_edge->set_registers(Parent::encoding.get_registers());
00319                 node_edge->add_outgoing_node_edge(next_node_edge); // add forward edge
00320                 effective_node_count++;
00321             }
00322         }
00323     }
00324 
00331     FanoNodeEdge *move_back_from_node_or_loosen_threshold(FanoNodeEdge *node_edge_current)
00332     {
00333         if (node_edge_current == ParentInternal::root_node) // at root node there are no other options than loosening threshold
00334         {
00335             cur_threshold -= delta_threshold;
00336             DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl);
00337         }
00338         else
00339         {
00340             FanoNodeEdge *node_edge_predecessor = node_edge_current->get_incoming_node_edge();
00341 
00342             if (node_edge_predecessor->get_path_metric() >= cur_threshold) // move backward
00343             {
00344                 DEBUG_OUT(Parent::verbosity > 2, std::cout << "backward" << std::endl);
00345 
00346                 if (tree_cache_size == 0) // tree cache is not used
00347                 {
00348                     // delete all successor edges and nodes
00349                     std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges();
00350                     typename std::vector<FanoNodeEdge*>::iterator ne_it = outgoing_node_edges.begin();
00351 
00352                     for (;ne_it != outgoing_node_edges.end(); ++ne_it)
00353                     {
00354                         delete *ne_it;
00355                     }
00356 
00357                     effective_node_count -= outgoing_node_edges.size();
00358                     outgoing_node_edges.clear();
00359                 }
00360 
00361                 // mark incoming edge as traversed back
00362                 if (node_edge_predecessor != ParentInternal::root_node)
00363                 {
00364                     node_edge_current->get_tag() = true;
00365                 }
00366 
00367                 // move back: change node address to previous node address
00368                 node_edge_current = node_edge_predecessor;
00369             }
00370             else // loosen threshold
00371             {
00372                 cur_threshold -= delta_threshold;
00373                 DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl);
00374             }
00375         }
00376 
00377         return node_edge_current;
00378     }
00379 
00383     bool continue_process(FanoNodeEdge *node_edge_current, const CC_ReliabilityMatrix& relmat)
00384     {
00385         if ((node_edge_current == ParentInternal::root_node) && (nb_moves > 0) && (cur_threshold == root_threshold))
00386         {
00387             const std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges();
00388             typename std::vector<FanoNodeEdge*>::const_iterator ne_it = outgoing_node_edges.begin();
00389             bool children_open = true;
00390 
00391             for (; ne_it != outgoing_node_edges.end(); ++ne_it)
00392             {
00393                 if ((*ne_it)->get_tag()) // traversed back
00394                 {
00395                     children_open = false;
00396                     break;
00397                 }
00398             }
00399 
00400             if (children_open)
00401             {
00402                 if (unloop && ((Parent::use_metric_limit) && (init_threshold > Parent::metric_limit)))
00403                 {
00404                     init_threshold += delta_init_threshold; // lower initial threshold and start all over again (delta if used is negative)
00405                     Parent::reset();                        // reset but do not delete root node
00406                     cur_threshold = init_threshold;
00407                     solution_found = false;
00408                     ParentInternal::root_node->delete_outgoing_node_edges(); // effectively resets the root node without destroying it
00409                     Parent::node_count = 1;
00410                     effective_node_count = 1;
00411                     nb_moves = 0;
00412                     visit_node_forward(node_edge_current, relmat); // visit root node again
00413                     std::cerr << "Loop condition detected, restart with init threshold = " << init_threshold << std::endl;
00414                     return true;
00415                 }
00416                 else
00417                 {
00418                     std::cerr << "Loop condition detected, aborting" << std::endl;
00419                     return false;
00420                 }
00421             }
00422         }
00423 
00424         if ((Parent::use_metric_limit) && (cur_threshold < Parent::metric_limit))
00425         {
00426             std::cerr << "Metric limit encountered" << std::endl;
00427             return false;
00428         }
00429 
00430         if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit))
00431         {
00432             std::cerr << "Node limit exhausted" << std::endl;
00433             return false;
00434         }
00435 
00436         return true;
00437     }
00438 
00443     void purge_tree_cache(FanoNodeEdge *node_edge)
00444     {
00445         bool node_terminal = true;
00446         unsigned int remaining_nodes = 0;
00447 
00448         while (node_edge != ParentInternal::root_node)
00449         {
00450             FanoNodeEdge *node_edge_predecessor = node_edge->get_incoming_node_edge();
00451             std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_predecessor->get_outgoing_node_edges();
00452             typename std::vector<FanoNodeEdge*>::iterator ne_it = outgoing_node_edges.begin();
00453 
00454             for (;ne_it != outgoing_node_edges.end(); ++ne_it)
00455             {
00456                 FanoNodeEdge *node_edge_sibling = (*ne_it);
00457 
00458                 if (node_terminal || (node_edge_sibling != node_edge))
00459                 {
00460                     (*ne_it)->delete_outgoing_node_edges();
00461                 }
00462 
00463                 remaining_nodes++;
00464             }
00465 
00466             node_edge = node_edge_predecessor;
00467             node_terminal = false;
00468         }
00469 
00470         remaining_nodes++; // +1 for root node
00471         effective_node_count = remaining_nodes;
00472         DEBUG_OUT(Parent::verbosity > 1, "purged tree cache, nb of remaining nodes = " << remaining_nodes << std::endl);
00473     }
00474 
00475     float init_threshold;              
00476     float cur_threshold;               
00477     float delta_threshold;             
00478     bool solution_found;               
00479     unsigned int effective_node_count; 
00480     unsigned int nb_moves;             
00481     float root_threshold;              
00482     unsigned int tree_cache_size;      
00483     bool unloop;                       
00484     float delta_init_threshold;        
00485 };
00486 
00487 
00488 
00489 } // namespace ccsoft
00490 
00491 #endif // __CC_FANO_DECODING_H__
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines