⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 encoding.cpp

📁 关于Q元LDPC码的C++仿真程序
💻 CPP
字号:
/*********************************************************************************
 * The encoder in this file is based on:
 *
 * T. Richardson and R.Urbanke, "Efficient encoding of low-density parity-check codes," IEEE Trans. Inform. Theory, vol. 47,
 * pp. 638--656, February 2001.
 *
 *********************************************************************************/



#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <iostream.h>
#include <fstream.h>
#include <ctype.h>
#include <wchar.h>
#include "LDPC_1.h"
#include "LDPC_2.h"
#include "Utils_1.h"
#include "Encoding.h"


/*********************************************************************************
 *
 * Utility
 *
 *********************************************************************************/

GFq &check_node::Element(int index)
// Treats check node as a sparse matrix column
{
   static GFq ReturnVal(0);                    // Value of check at column

   for (int j = 0; j < GetDegree(); j++)
   {
      if (GetEdge(j).LeftNode().GetID() == index)
      {
         ReturnVal = GetEdge(j).label;
         break;
      }
   }

   return ReturnVal;
}



/*********************************************************************************
 *
 * Node lists
 *
 *********************************************************************************/

void NodeListWithID::SwitchNodes(int i1, int i2)
{
   node *Aux;

   Aux = Nodes[i1];
   Nodes[i1] = Nodes[i2];
   Nodes[i2] = Aux;

   // Update ID
   Nodes[i1]->SetID(i1);
   Nodes[i2]->SetID(i2);
}





void VariableNodeList::Init(variable_node VariableNodeArray[], int p_Length)
{
   Allocate(p_Length);
   for (int i = 0; i < p_Length; i++)
   {
      Nodes[i] = &(VariableNodeArray[i]);
      Nodes[i]->SetID(i);
   }
   CurrentLength = p_Length;
}




void CheckNodeList::Init(check_node CheckNodeArray[], int p_Length)
{
   Allocate(p_Length);
   int index = 0;

   for (int i = 0; i < p_Length; i++)
   {
      if (CheckNodeArray[i].GetDegree() != 0)      // Ignore the rare case of degree = 0
      {
         Nodes[index] = &(CheckNodeArray[i]);
         Nodes[index]->SetID(index);
         index++;
      }
   }
   CurrentLength = index;
}




void EraseKnown(node &KnownColumn, NodeListWithoutID &DegreeOneRows)
// "Erase" a known column
{
   for (int i = 0; i < KnownColumn.degree; i++)
   {
      node &AdjacentRow = KnownColumn.AdjacentNode(i);
      AdjacentRow.AuxDegree--;

      if (AdjacentRow.AuxDegree == 1)
         DegreeOneRows.Add(AdjacentRow);
   }
}


/*********************************************************************************
 *
 * Urbanke's Algorithm AH
 *
 *********************************************************************************/

// If gap ends up too big, it might be necessary to modify the following 3 to 300 or larger
#define MIN_GAP   3
#define MAX_GAP   10




void UrbankeAlgorithmAH(NodeListWithID &Columns, NodeListWithID &Rows)
{
   //------------------------------------------------------
   // Init degrees
   //------------------------------------------------------
   for (int i = 0; i < Rows.GetLength(); i++)
      Rows[i].AuxDegree = Rows[i].degree;

   // data structure for degree one nodes
   NodeListWithoutID DegreeOneRows;
   DegreeOneRows.Allocate(Rows.GetLength());

   //------------------------------------------------------
   // Initialization: select known columns
   //-----------------------------------------------------
   int SystematicColumns = max(Columns.GetLength() - Rows.GetLength(), 0) + MIN_GAP;


   for (int i = 0; i < SystematicColumns; i++)
   {
      // Select a known column among remaining columns
      int Known = uniform_random(Columns.GetLength() - i) + i;
      Columns.SwitchNodes(Known, i);          // Move known column to start 
      EraseKnown(Columns[i], DegreeOneRows);  // "Erase" known column
   }

   int FirstNonSystematic = SystematicColumns;

   //------------------------------------------------------
   // Diagonal extension steps
   //------------------------------------------------------
   int DegreeOneIndex = 0;
   int StartUnknown = FirstNonSystematic;
   for (; StartUnknown < Columns.GetLength(); StartUnknown++)
   {
      // Find next degree one row
      // Skip degree one rows which may have turned to zero
      for (; DegreeOneIndex < DegreeOneRows.GetLength(); DegreeOneIndex++)
         if (DegreeOneRows[DegreeOneIndex].AuxDegree == 1)
            break;

      if (DegreeOneIndex == DegreeOneRows.GetLength())
         break;       // If not finished and no degree one nodes remain

      node &CurrentDegreeOneRow = DegreeOneRows[DegreeOneIndex++];
      int CurrentRowNumber = CurrentDegreeOneRow.GetID();
      
      // Find the single unknown column (degree 1 refers to unknown connected nodes)
      int NewColumnToBeKnown = -1;
      for (int i = 0; i < CurrentDegreeOneRow.GetDegree(); i++)
      {
         int ColumnNumber = CurrentDegreeOneRow.AdjacentNode(i).GetID();
         if (ColumnNumber >= StartUnknown)
         {
            NewColumnToBeKnown = ColumnNumber;
            break;
         }
      }

      if (NewColumnToBeKnown == -1)     // Assertion - an unknown column must be found
      {
         cout << "LDPC_Code::GenerateEncoder(): No unknown column was found, while "
              << "because degree of row = 1, by definition one should have been found\n";
         exit(1);
      }

      Columns.SwitchNodes(NewColumnToBeKnown, StartUnknown);    // Make new known column StartUnknown 
      Rows.SwitchNodes(CurrentRowNumber, StartUnknown - FirstNonSystematic);
      EraseKnown(Columns[StartUnknown], DegreeOneRows);         // "Erase" new known node
   }

   //-------------------------------------------------------------
   // Generate gap by moving remaining unknowns down
   //-------------------------------------------------------------
   int LowerTriangularLength = StartUnknown - FirstNonSystematic;
   for (int i1 = Columns.GetLength()-1, i2 = StartUnknown - 1;  
        i2 >= FirstNonSystematic;  i1--, i2--)
        {
           Columns.SwitchNodes(i1, i2);
        }

   //-------------------------------------------------------------
   // Record gap
   //-------------------------------------------------------------
   Columns.Gap = Columns.GetLength() - LowerTriangularLength;
   Rows.Gap = Rows.GetLength() - LowerTriangularLength;

//   cout << "SystematicColumns = " << SystematicColumns << "\n"
//      << "StartUnknown = " << StartUnknown << "\n"
//      << "Columns.GetLength() = " << Columns.GetLength() << "\n"
//      << "Columns gap = " << Columns.Gap << "\n"
//      << "Rows.GetLength() = " << Rows.GetLength() << "\n"
//      << "Rows gap = " << Rows.Gap << "\n";
}


/*********************************************************************************
 *
 * Encoder
 *
 *********************************************************************************/



void LDPC_Code::GenerateRandomSystematic()
{
   //------------------------------------------------------
   // Randomly select values for systematic digits
   //------------------------------------------------------
   for (int i = 0; i < Systematic; i++)
      Variables[i].Symbol.val = uniform_random(GFq::q);
}
 



void LDPC_Code::Encode()
{
   int FirstVarOfTriangle = Systematic + Gap;
  
   //------------------------------------------------------
   // Determine gap symbols
   //------------------------------------------------------
   if (Gap > 0)
   {
      // Multiply systematic vector multiplied by GapMatrix
      matrix Vals(Gap);          // a column vector for results
      for (int i = 0; i < Gap; i++)
      {
         Vals[i] = 0;
         for (int j = 0; j < Systematic; j++)
            Vals[i] += Variables[j].Symbol * GapMatrix.Element(i,j);
      }

      matrix GapVars(Gap);
      GapVars = MinusPhiInverse * Vals;

      // place vals
      for (int i = 0; i < Gap; i++)
         Variables[Systematic + i].Symbol = GapVars[i];
   }

   //------------------------------------------------------
   // Determine all the rest
   //------------------------------------------------------
   for (int i = 0; i < Triangle; i++)
   {
      // Calculate value of check node without symbol
      Variables[FirstVarOfTriangle + i].Symbol = 0;
      GFq label = Checks[i].Element(FirstVarOfTriangle + i);
      Variables[FirstVarOfTriangle + i].Symbol = (Checks[i].Value()/label).Minus();
   }
}




void LDPC_Code::GenerateEncoder_WithoutGap()
{
   //------------------------------------------------------
   // Approximate lower triangularize
   //------------------------------------------------------
   // Init 
   Variables.Init(Graph.variable_nodes, Graph.N);
   Checks.Init(Graph.check_nodes, Graph.M);

   UrbankeAlgorithmAH(/* columns */ Checks, /* rows */ Variables);

   // Reverse because we have made checks the columns and variables the rows
   Variables.Reverse();
   Checks.Reverse();

   // Determine values
   Systematic = Variables.GetLength() - Checks.GetLength();
   Gap = Checks.Gap;
   Triangle = Variables.GetLength() - Systematic - Gap;

   int FirstCheckOfGap = Checks.GetLength() - Gap;

   //------------------------------------------------------
   // Eliminate gap check nodes
   //------------------------------------------------------
   if (Gap > MAX_GAP)
   {
      cout << "GenerateEncoder_WithoutGap: Gap = " << Gap << " too big\n";
      exit(1);
   }

   for (int i = FirstCheckOfGap; i < Checks.GetLength(); i++)
   {
      Checks[i].Disconnect();
   }

   // Update variables
   Systematic += Gap;
   Gap = 0;
   GapMatrix.deAllocate();
   MinusPhiInverse.deAllocate();
}



void LDPC_Code::GenerateEncoder()
{
   //------------------------------------------------------
   // Approximate lower triangularize
   //------------------------------------------------------
   // Init
   Variables.Init(Graph.variable_nodes, Graph.N);
   Checks.Init(Graph.check_nodes, Graph.M);

   UrbankeAlgorithmAH(/* columns */ Checks, /* rows */ Variables);

   // Reverse because we have made checks the columns and variables the rows
   Variables.Reverse();
   Checks.Reverse();

   // Determine values
   Systematic = Variables.GetLength() - Checks.GetLength();
   Gap = Checks.Gap;
   Triangle = Variables.GetLength() - Systematic - Gap;

   cout << "GenerateEncoder: Gap = " << Gap << "\n";

   //ofstream bbbTemp("Temp.txt");
   //for (int i = 0; i < Variables.GetLength(); i++)
   //   for (int j = 0; j < Variables[i].GetDegree(); j++)
   //      bbbTemp << Variables[i].AdjacentNode(j).GetID() << " " << i << "\n";
   //bbbTemp.close();
   //exit(0);

   int FirstCheckOfGap = Checks.GetLength() - Gap;
   int FirstVarOfTriangle = Systematic + Gap;

   //------------------------------------------------------
   // Handle gap
   //------------------------------------------------------
   // Init gap matrix
   GapMatrix.Init(Gap, Variables.GetLength());

   for (int i = 0; i < Gap; i++)
   {
      //cout << FirstCheckOfGap + i << ">" << Checks[FirstCheckOfGap + i].GetID() << " " << Checks[FirstCheckOfGap + i].degree << "\n";
      GapMatrix.Set(i, Checks[FirstCheckOfGap + i]);
   }

   //ofstream bbbTemp2("Temp.txt");
   //GapMatrix.SparseOut(bbbTemp2);
   //bbbTemp2.close();
   //exit(0);

   // Gaussian elimination 
   for (int j = Triangle - 1; j >= 0; j--)      // column
   {
      // Find element appropriate matrix element
      int EliminatedCol = FirstVarOfTriangle + j;     // Column to be eliminated
      check_node &CheckRow = Checks[j];     // j'th check should be nonzero at j'th column
      GFq EliminatingRowVal = CheckRow.Element(EliminatedCol);        // Value of row at column to be eliminated

      for (int i = 0; i < GapMatrix.M; i++)     // row of GapMatrix
      {
         GFq ValToBeEliminated = GapMatrix.Element(i, EliminatedCol);
         if (!ValToBeEliminated.IsZero())
         {
            GFq Mult = (ValToBeEliminated / EliminatingRowVal).Minus();
            GapMatrix.Add(i, CheckRow, Mult);
         }
      }
   }

   // obtain phi^-1
   // While matrix is singular, switch columns
   BOOLEAN Success = FALSE;
   for (int Attempts = 0; Attempts < 10000; Attempts++)
   {
      matrix phi = GapMatrix.Extract(Systematic, Gap);   // Systematic = first col after systematic
      MinusPhiInverse = phi.Inverse();

      if (!MinusPhiInverse.IsNull())    // if success
      {
         MinusPhiInverse.MultiplyByMinusOne();
         Success = TRUE;
         break;
      }
      else
      {  // switch columns randomly
         int i1 = uniform_random(Systematic);
         int i2 = uniform_random(Gap) + Systematic;

         GapMatrix.SwitchColumns(i1, i2);
         Variables.SwitchNodes(i1, i2);
      }
   }

   if (!Success)
   {
      cout << "Unable to find an invertible phi, maybe increase number of attempts\n";
      exit(1);
   }
}     

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -