ccsoft  0.0.0
Convolutional codes library with soft decision decoding
/shared/development/google_code/rssoft/libccsoft/lib/CC_StackDecoding.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  */
00024 #ifndef __CC_STACK_DECODING_H__
00025 #define __CC_STACK_DECODING_H__
00026 
00027 #include "CC_SequentialDecoding.h"
00028 #include "CC_SequentialDecodingInternal.h"
00029 #include "CC_Encoding.h"
00030 #include "CCSoft_Exception.h"
00031 #include "CC_TreeNodeEdge.h"
00032 #include "CC_ReliabilityMatrix.h"
00033 
00034 #include <cmath>
00035 #include <map>
00036 #include <algorithm>
00037 #include <iostream>
00038 
00039 
00040 namespace ccsoft
00041 {
00042 
00048 template<typename T_Register, typename T_IOSymbol>
00049 class CC_StackDecoding : public CC_SequentialDecoding<T_Register, T_IOSymbol>, public CC_SequentialDecodingInternal<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty>
00050 {
00051 public:
00061         CC_StackDecoding(const std::vector<unsigned int>& constraints,
00062             const std::vector<std::vector<T_Register> >& genpoly_representations) :
00063                 CC_SequentialDecoding<T_Register, T_IOSymbol>(constraints, genpoly_representations),
00064                 CC_SequentialDecodingInternal<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty>()
00065     {}
00066 
00070     virtual ~CC_StackDecoding()
00071     {}
00072 
00076     void reset()
00077     {
00078         ParentInternal::reset();
00079         Parent::reset();
00080         node_edge_stack.clear();
00081     }
00082 
00086     float get_stack_score() const
00087     {
00088         return node_edge_stack.begin()->first.path_metric;
00089     }
00090 
00094     unsigned int get_stack_size() const
00095     {
00096         return node_edge_stack.size();
00097     }
00098 
00104     virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message)
00105     {
00106         if (relmat.get_message_length() < Parent::encoding.get_m())
00107         {
00108             throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint");
00109         }
00110 
00111         if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n())
00112         {
00113             throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size");
00114         }
00115 
00116         reset();
00117         ParentInternal::init_root(); // initialize the root node
00118         Parent::node_count++;
00119         visit_node_forward(ParentInternal::root_node, relmat); // visit the root node
00120 
00121         // loop until we get to a terminal node or the metric limit is encountered hence the stack is empty
00122         while ((node_edge_stack.size() > 0)
00123             && (node_edge_stack.begin()->second->get_depth() < relmat.get_message_length() - 1))
00124         {
00125             StackNodeEdge* node = node_edge_stack.begin()->second;
00126             //std::cout << std::dec << node->get_id() << ":" << node->get_depth() << ":" << node_stack.begin()->first.path_metric << std::endl;
00127             visit_node_forward(node, relmat);
00128 
00129             if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit))
00130             {
00131                 std::cerr << "Node limit exhausted" << std::endl;
00132                 return false;
00133             }
00134         }
00135 
00136         // Top node has the solution if we have not given up
00137         if (!Parent::use_metric_limit || node_edge_stack.size() != 0)
00138         {
00139             //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;
00140             ParentInternal::back_track(node_edge_stack.begin()->second, decoded_message, true); // back track from terminal node to retrieve decoded message
00141             Parent::codeword_score = node_edge_stack.begin()->first.path_metric; // the codeword score is the path metric
00142             return true;
00143         }
00144         else
00145         {
00146             std::cerr << "Metric limit encountered" << std::endl;
00147             return false; // no solution
00148         }
00149     }
00150 
00156     virtual void print_stats(std::ostream& os, bool success)
00157     {
00158         std::cout << "score = " << Parent::get_score()
00159                 << " stack_score = " << get_stack_score()
00160                 << " #nodes = " << Parent::get_nb_nodes()
00161                 << " stack_size = " << get_stack_size()
00162                 << " max depth = " << Parent::get_max_depth() << std::endl;
00163         std::cout << "_RES " << (success ? 1 : 0) << ","
00164                 << Parent::get_score() << ","
00165                 << get_stack_score() << ","
00166                 << Parent::get_nb_nodes() << ","
00167                 << get_stack_size() << ","
00168                 << Parent::get_max_depth() << std::endl;
00169     }
00170 
00175     virtual void print_dot(std::ostream& os)
00176     {
00177         ParentInternal::print_dot_internal(os);
00178     }
00179 
00180 protected:
00181     typedef CC_SequentialDecoding<T_Register, T_IOSymbol> Parent;                                       
00182     typedef CC_SequentialDecodingInternal<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty> ParentInternal; 
00183     typedef CC_TreeNodeEdge<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty> StackNodeEdge; 
00184 
00190     virtual void visit_node_forward(CC_TreeNodeEdge<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty>* node_edge, const CC_ReliabilityMatrix& relmat)
00191     {
00192         int forward_depth = node_edge->get_depth() + 1;
00193         T_IOSymbol out_symbol;
00194         T_IOSymbol end_symbol;
00195 
00196         // return encoder to appropriate state
00197         if (node_edge->get_depth() >= 0) // does not concern the root node
00198         {
00199             Parent::encoding.set_registers(node_edge->get_registers());
00200         }
00201 
00202         if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m()))
00203         {
00204             end_symbol = 1; // if zero tail option assume tail symbols are all zeros
00205         }
00206         else
00207         {
00208             end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols
00209         }
00210 
00211         // loop through assumption for this symbol place
00212         for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++)
00213         {
00214             Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place
00215             float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias;
00216 
00217             float forward_path_metric = edge_metric + node_edge->get_path_metric();
00218             if ((!Parent::use_metric_limit) || (forward_path_metric > Parent::metric_limit))
00219             {
00220                 StackNodeEdge *next_node_edge = new StackNodeEdge(Parent::node_count, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth);
00221                 next_node_edge->set_registers(Parent::encoding.get_registers());
00222                 node_edge->add_outgoing_node_edge(next_node_edge); // add forward edge+node combo
00223                 node_edge_stack[NodeEdgeOrdering(forward_path_metric, Parent::node_count)] = next_node_edge;
00224                 //std::cout << "->" << std::dec << node_count << ":" << forward_depth << " (" << (unsigned int) in_symbol << "," << (unsigned int) out_symbol << "): " << forward_path_metric << std::endl;
00225                 Parent::node_count++;
00226             }
00227         }
00228 
00229         Parent::cur_depth = forward_depth; // new encoder position
00230 
00231         if (Parent::cur_depth > Parent::max_depth)
00232         {
00233             Parent::max_depth = Parent::cur_depth;
00234         }
00235 
00236         if (node_edge->get_depth() >= 0)
00237         {
00238             remove_node_from_stack(node_edge); // remove current node from the stack unless it is the root node which is not in the stack
00239         }
00240     }
00241 
00245     void remove_node_from_stack(StackNodeEdge* node_edge)
00246     {
00247         typename std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> >::iterator stack_it = node_edge_stack.begin();
00248 
00249         for (; stack_it != node_edge_stack.end(); ++stack_it)
00250         {
00251             if (node_edge == stack_it->second)
00252             {
00253                 node_edge_stack.erase(stack_it);
00254                 break;
00255             }
00256         }
00257     }
00258 
00259     std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> > node_edge_stack; 
00260 };
00261 
00262 } // namespace ccsoft
00263 
00264 #endif
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines