ccsoft  0.0.0
Convolutional codes library with soft decision decoding
/shared/development/google_code/rssoft/libccsoft/lib/CC_StackDecoding_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 stack or Zigangirov-Jelinek
00021  (ZJ) algorithm. Uses the node+edge combination in the code tree.
00022 
00023  Uses fixed arrays
00024 
00025  */
00026 #ifndef __CC_STACK_DECODING_FA_H__
00027 #define __CC_STACK_DECODING_FA_H__
00028 
00029 #include "CC_SequentialDecoding_FA.h"
00030 #include "CC_SequentialDecodingInternal_FA.h"
00031 #include "CC_Encoding_FA.h"
00032 #include "CCSoft_Exception.h"
00033 #include "CC_TreeNodeEdge_FA.h"
00034 #include "CC_ReliabilityMatrix.h"
00035 
00036 #include <cmath>
00037 #include <map>
00038 #include <algorithm>
00039 #include <iostream>
00040 
00041 
00042 namespace ccsoft
00043 {
00044 
00055 template<typename T_Register, typename T_IOSymbol, unsigned int N_k>
00056 class CC_StackDecoding_FA : public CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k>, public CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty, N_k>
00057 {
00058 public:
00068         CC_StackDecoding_FA(const std::vector<unsigned int>& constraints,
00069             const std::vector<std::vector<T_Register> >& genpoly_representations) :
00070                 CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k>(constraints, genpoly_representations),
00071                 CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty, N_k>()
00072     {}
00073 
00077     virtual ~CC_StackDecoding_FA()
00078     {}
00079 
00083     void reset()
00084     {
00085         ParentInternal::reset();
00086         Parent::reset();
00087         node_edge_stack.clear();
00088     }
00089 
00093     float get_stack_score() const
00094     {
00095         return node_edge_stack.begin()->first.path_metric;
00096     }
00097 
00101     unsigned int get_stack_size() const
00102     {
00103         return node_edge_stack.size();
00104     }
00105 
00111     virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message)
00112     {
00113         if (relmat.get_message_length() < Parent::encoding.get_m())
00114         {
00115             throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint");
00116         }
00117 
00118         if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n())
00119         {
00120             throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size");
00121         }
00122 
00123         reset();
00124         ParentInternal::init_root(); // initialize the root node
00125         Parent::node_count++;
00126         visit_node_forward(ParentInternal::root_node, relmat); // visit the root node
00127 
00128         // loop until we get to a terminal node or the metric limit is encountered hence the stack is empty
00129         while ((node_edge_stack.size() > 0)
00130             && (node_edge_stack.begin()->second->get_depth() < relmat.get_message_length() - 1))
00131         {
00132             StackNodeEdge* node = node_edge_stack.begin()->second;
00133             //std::cout << std::dec << node->get_id() << ":" << node->get_depth() << ":" << node_stack.begin()->first.path_metric << std::endl;
00134             visit_node_forward(node, relmat);
00135 
00136             if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit))
00137             {
00138                 std::cerr << "Node limit exhausted" << std::endl;
00139                 return false;
00140             }
00141         }
00142 
00143         // Top node has the solution if we have not given up
00144         if (!Parent::use_metric_limit || node_edge_stack.size() != 0)
00145         {
00146             //std::cout << "final: " << std::dec << node_stack.begin()->second->get_id() << ":" << node_stack.begin()->second->get_depth() << ":" << node_stack.begin()->first.path_metric << std::endl;
00147             ParentInternal::back_track(node_edge_stack.begin()->second, decoded_message, true); // back track from terminal node to retrieve decoded message
00148             Parent::codeword_score = node_edge_stack.begin()->first.path_metric; // the codeword score is the path metric
00149             return true;
00150         }
00151         else
00152         {
00153             std::cerr << "Metric limit encountered" << std::endl;
00154             return false; // no solution
00155         }
00156     }
00157 
00163     virtual void print_stats(std::ostream& os, bool success)
00164     {
00165         std::cout << "score = " << Parent::get_score()
00166                 << " stack_score = " << get_stack_score()
00167                 << " #nodes = " << Parent::get_nb_nodes()
00168                 << " stack_size = " << get_stack_size()
00169                 << " max depth = " << Parent::get_max_depth() << std::endl;
00170         std::cout << "_RES " << (success ? 1 : 0) << ","
00171                 << Parent::get_score() << ","
00172                 << get_stack_score() << ","
00173                 << Parent::get_nb_nodes() << ","
00174                 << get_stack_size() << ","
00175                 << Parent::get_max_depth() << std::endl;
00176     }
00177 
00182     virtual void print_dot(std::ostream& os)
00183     {
00184         ParentInternal::print_dot_internal(os);
00185     }
00186 
00187 protected:
00188     typedef CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k> Parent;                                       
00189     typedef CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty, N_k> ParentInternal; 
00190     typedef CC_TreeNodeEdge_FA<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty, N_k> StackNodeEdge; 
00191 
00197     virtual void visit_node_forward(CC_TreeNodeEdge_FA<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty, N_k>* node_edge, const CC_ReliabilityMatrix& relmat)
00198     {
00199         int forward_depth = node_edge->get_depth() + 1;
00200         T_IOSymbol out_symbol;
00201         T_IOSymbol end_symbol;
00202 
00203         // return encoder to appropriate state
00204         if (node_edge->get_depth() >= 0) // does not concern the root node
00205         {
00206             Parent::encoding.set_registers(node_edge->get_registers());
00207         }
00208 
00209         if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m()))
00210         {
00211             end_symbol = 1; // if zero tail option assume tail symbols are all zeros
00212         }
00213         else
00214         {
00215             end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols
00216         }
00217 
00218         // loop through assumption for this symbol place
00219         for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++)
00220         {
00221             Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place
00222             float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias;
00223 
00224             float forward_path_metric = edge_metric + node_edge->get_path_metric();
00225             if ((!Parent::use_metric_limit) || (forward_path_metric > Parent::metric_limit))
00226             {
00227                 StackNodeEdge *next_node_edge = new StackNodeEdge(Parent::node_count, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth);
00228                 next_node_edge->set_registers(Parent::encoding.get_registers());
00229                 node_edge->set_outgoing_node_edge(next_node_edge, in_symbol); // add forward edge+node combo
00230                 node_edge_stack[NodeEdgeOrdering(forward_path_metric, Parent::node_count)] = next_node_edge;
00231                 //std::cout << "->" << std::dec << node_count << ":" << forward_depth << " (" << (unsigned int) in_symbol << "," << (unsigned int) out_symbol << "): " << forward_path_metric << std::endl;
00232                 Parent::node_count++;
00233             }
00234         }
00235 
00236         Parent::cur_depth = forward_depth; // new encoder position
00237 
00238         if (Parent::cur_depth > Parent::max_depth)
00239         {
00240             Parent::max_depth = Parent::cur_depth;
00241         }
00242 
00243         if (node_edge->get_depth() >= 0)
00244         {
00245             remove_node_from_stack(node_edge); // remove current node from the stack unless it is the root node which is not in the stack
00246         }
00247     }
00248 
00252     void remove_node_from_stack(StackNodeEdge* node_edge)
00253     {
00254         typename std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> >::iterator stack_it = node_edge_stack.begin();
00255 
00256         for (; stack_it != node_edge_stack.end(); ++stack_it)
00257         {
00258             if (node_edge == stack_it->second)
00259             {
00260                 node_edge_stack.erase(stack_it);
00261                 break;
00262             }
00263         }
00264     }
00265 
00266     std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> > node_edge_stack; 
00267 };
00268 
00269 } // namespace ccsoft
00270 
00271 #endif
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines