Encoding.cpp
上传用户:speoil
上传日期:2021-10-06
资源大小:100k
文件大小:13k
源码类别:

3G开发

开发平台:

C/C++

  1. /*********************************************************************************
  2.  * The encoder in this file is based on:
  3.  *
  4.  * T. Richardson and R.Urbanke, "Efficient encoding of low-density parity-check codes," IEEE Trans. Inform. Theory, vol. 47,
  5.  * pp. 638--656, February 2001.
  6.  *
  7.  *********************************************************************************/
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include <stdlib.h>
  11. #include <iostream.h>
  12. #include <fstream.h>
  13. #include <ctype.h>
  14. #include <wchar.h>
  15. #include "LDPC_1.h"
  16. #include "LDPC_2.h"
  17. #include "Utils_1.h"
  18. #include "Encoding.h"
  19. /*********************************************************************************
  20.  *
  21.  * Utility
  22.  *
  23.  *********************************************************************************/
  24. GFq &check_node::Element(int index)
  25. // Treats check node as a sparse matrix column
  26. {
  27.    static GFq ReturnVal(0);                    // Value of check at column
  28.    for (int j = 0; j < GetDegree(); j++)
  29.    {
  30.       if (GetEdge(j).LeftNode().GetID() == index)
  31.       {
  32.          ReturnVal = GetEdge(j).label;
  33.          break;
  34.       }
  35.    }
  36.    return ReturnVal;
  37. }
  38. /*********************************************************************************
  39.  *
  40.  * Node lists
  41.  *
  42.  *********************************************************************************/
  43. void NodeListWithID::SwitchNodes(int i1, int i2)
  44. {
  45.    node *Aux;
  46.    Aux = Nodes[i1];
  47.    Nodes[i1] = Nodes[i2];
  48.    Nodes[i2] = Aux;
  49.    // Update ID
  50.    Nodes[i1]->SetID(i1);
  51.    Nodes[i2]->SetID(i2);
  52. }
  53. void VariableNodeList::Init(variable_node VariableNodeArray[], int p_Length)
  54. {
  55.    Allocate(p_Length);
  56.    for (int i = 0; i < p_Length; i++)
  57.    {
  58.       Nodes[i] = &(VariableNodeArray[i]);
  59.       Nodes[i]->SetID(i);
  60.    }
  61.    CurrentLength = p_Length;
  62. }
  63. void CheckNodeList::Init(check_node CheckNodeArray[], int p_Length)
  64. {
  65.    Allocate(p_Length);
  66.    int index = 0;
  67.    for (int i = 0; i < p_Length; i++)
  68.    {
  69.       if (CheckNodeArray[i].GetDegree() != 0)      // Ignore the rare case of degree = 0
  70.       {
  71.          Nodes[index] = &(CheckNodeArray[i]);
  72.          Nodes[index]->SetID(index);
  73.          index++;
  74.       }
  75.    }
  76.    CurrentLength = index;
  77. }
  78. void EraseKnown(node &KnownColumn, NodeListWithoutID &DegreeOneRows)
  79. // "Erase" a known column
  80. {
  81.    for (int i = 0; i < KnownColumn.degree; i++)
  82.    {
  83.       node &AdjacentRow = KnownColumn.AdjacentNode(i);
  84.       AdjacentRow.AuxDegree--;
  85.       if (AdjacentRow.AuxDegree == 1)
  86.          DegreeOneRows.Add(AdjacentRow);
  87.    }
  88. }
  89. /*********************************************************************************
  90.  *
  91.  * Urbanke's Algorithm AH
  92.  *
  93.  *********************************************************************************/
  94. // If gap ends up too big, it might be necessary to modify the following 3 to 300 or larger
  95. #define MIN_GAP   3
  96. #define MAX_GAP   10
  97. void UrbankeAlgorithmAH(NodeListWithID &Columns, NodeListWithID &Rows)
  98. {
  99.    //------------------------------------------------------
  100.    // Init degrees
  101.    //------------------------------------------------------
  102.    for (int i = 0; i < Rows.GetLength(); i++)
  103.       Rows[i].AuxDegree = Rows[i].degree;
  104.    // data structure for degree one nodes
  105.    NodeListWithoutID DegreeOneRows;
  106.    DegreeOneRows.Allocate(Rows.GetLength());
  107.    //------------------------------------------------------
  108.    // Initialization: select known columns
  109.    //-----------------------------------------------------
  110.    int SystematicColumns = max(Columns.GetLength() - Rows.GetLength(), 0) + MIN_GAP;
  111.    for (int i = 0; i < SystematicColumns; i++)
  112.    {
  113.       // Select a known column among remaining columns
  114.       int Known = uniform_random(Columns.GetLength() - i) + i;
  115.       Columns.SwitchNodes(Known, i);          // Move known column to start 
  116.       EraseKnown(Columns[i], DegreeOneRows);  // "Erase" known column
  117.    }
  118.    int FirstNonSystematic = SystematicColumns;
  119.    //------------------------------------------------------
  120.    // Diagonal extension steps
  121.    //------------------------------------------------------
  122.    int DegreeOneIndex = 0;
  123.    int StartUnknown = FirstNonSystematic;
  124.    for (; StartUnknown < Columns.GetLength(); StartUnknown++)
  125.    {
  126.       // Find next degree one row
  127.       // Skip degree one rows which may have turned to zero
  128.       for (; DegreeOneIndex < DegreeOneRows.GetLength(); DegreeOneIndex++)
  129.          if (DegreeOneRows[DegreeOneIndex].AuxDegree == 1)
  130.             break;
  131.       if (DegreeOneIndex == DegreeOneRows.GetLength())
  132.          break;       // If not finished and no degree one nodes remain
  133.       node &CurrentDegreeOneRow = DegreeOneRows[DegreeOneIndex++];
  134.       int CurrentRowNumber = CurrentDegreeOneRow.GetID();
  135.       
  136.       // Find the single unknown column (degree 1 refers to unknown connected nodes)
  137.       int NewColumnToBeKnown = -1;
  138.       for (int i = 0; i < CurrentDegreeOneRow.GetDegree(); i++)
  139.       {
  140.          int ColumnNumber = CurrentDegreeOneRow.AdjacentNode(i).GetID();
  141.          if (ColumnNumber >= StartUnknown)
  142.          {
  143.             NewColumnToBeKnown = ColumnNumber;
  144.             break;
  145.          }
  146.       }
  147.       if (NewColumnToBeKnown == -1)     // Assertion - an unknown column must be found
  148.       {
  149.          cout << "LDPC_Code::GenerateEncoder(): No unknown column was found, while "
  150.               << "because degree of row = 1, by definition one should have been foundn";
  151.          exit(1);
  152.       }
  153.       Columns.SwitchNodes(NewColumnToBeKnown, StartUnknown);    // Make new known column StartUnknown 
  154.       Rows.SwitchNodes(CurrentRowNumber, StartUnknown - FirstNonSystematic);
  155.       EraseKnown(Columns[StartUnknown], DegreeOneRows);         // "Erase" new known node
  156.    }
  157.    //-------------------------------------------------------------
  158.    // Generate gap by moving remaining unknowns down
  159.    //-------------------------------------------------------------
  160.    int LowerTriangularLength = StartUnknown - FirstNonSystematic;
  161.    for (int i1 = Columns.GetLength()-1, i2 = StartUnknown - 1;  
  162.         i2 >= FirstNonSystematic;  i1--, i2--)
  163.         {
  164.            Columns.SwitchNodes(i1, i2);
  165.         }
  166.    //-------------------------------------------------------------
  167.    // Record gap
  168.    //-------------------------------------------------------------
  169.    Columns.Gap = Columns.GetLength() - LowerTriangularLength;
  170.    Rows.Gap = Rows.GetLength() - LowerTriangularLength;
  171. //   cout << "SystematicColumns = " << SystematicColumns << "n"
  172. //      << "StartUnknown = " << StartUnknown << "n"
  173. //      << "Columns.GetLength() = " << Columns.GetLength() << "n"
  174. //      << "Columns gap = " << Columns.Gap << "n"
  175. //      << "Rows.GetLength() = " << Rows.GetLength() << "n"
  176. //      << "Rows gap = " << Rows.Gap << "n";
  177. }
  178. /*********************************************************************************
  179.  *
  180.  * Encoder
  181.  *
  182.  *********************************************************************************/
  183. void LDPC_Code::GenerateRandomSystematic()
  184. {
  185.    //------------------------------------------------------
  186.    // Randomly select values for systematic digits
  187.    //------------------------------------------------------
  188.    for (int i = 0; i < Systematic; i++)
  189.       Variables[i].Symbol.val = uniform_random(GFq::q);
  190. }
  191.  
  192. void LDPC_Code::Encode()
  193. {
  194.    int FirstVarOfTriangle = Systematic + Gap;
  195.   
  196.    //------------------------------------------------------
  197.    // Determine gap symbols
  198.    //------------------------------------------------------
  199.    if (Gap > 0)
  200.    {
  201.       // Multiply systematic vector multiplied by GapMatrix
  202.       matrix Vals(Gap);          // a column vector for results
  203.       for (int i = 0; i < Gap; i++)
  204.       {
  205.          Vals[i] = 0;
  206.          for (int j = 0; j < Systematic; j++)
  207.             Vals[i] += Variables[j].Symbol * GapMatrix.Element(i,j);
  208.       }
  209.       matrix GapVars(Gap);
  210.       GapVars = MinusPhiInverse * Vals;
  211.       // place vals
  212.       for (int i = 0; i < Gap; i++)
  213.          Variables[Systematic + i].Symbol = GapVars[i];
  214.    }
  215.    //------------------------------------------------------
  216.    // Determine all the rest
  217.    //------------------------------------------------------
  218.    for (int i = 0; i < Triangle; i++)
  219.    {
  220.       // Calculate value of check node without symbol
  221.       Variables[FirstVarOfTriangle + i].Symbol = 0;
  222.       GFq label = Checks[i].Element(FirstVarOfTriangle + i);
  223.       Variables[FirstVarOfTriangle + i].Symbol = (Checks[i].Value()/label).Minus();
  224.    }
  225. }
  226. void LDPC_Code::GenerateEncoder_WithoutGap()
  227. {
  228.    //------------------------------------------------------
  229.    // Approximate lower triangularize
  230.    //------------------------------------------------------
  231.    // Init 
  232.    Variables.Init(Graph.variable_nodes, Graph.N);
  233.    Checks.Init(Graph.check_nodes, Graph.M);
  234.    UrbankeAlgorithmAH(/* columns */ Checks, /* rows */ Variables);
  235.    // Reverse because we have made checks the columns and variables the rows
  236.    Variables.Reverse();
  237.    Checks.Reverse();
  238.    // Determine values
  239.    Systematic = Variables.GetLength() - Checks.GetLength();
  240.    Gap = Checks.Gap;
  241.    Triangle = Variables.GetLength() - Systematic - Gap;
  242.    int FirstCheckOfGap = Checks.GetLength() - Gap;
  243.    //------------------------------------------------------
  244.    // Eliminate gap check nodes
  245.    //------------------------------------------------------
  246.    if (Gap > MAX_GAP)
  247.    {
  248.       cout << "GenerateEncoder_WithoutGap: Gap = " << Gap << " too bign";
  249.       exit(1);
  250.    }
  251.    for (int i = FirstCheckOfGap; i < Checks.GetLength(); i++)
  252.    {
  253.       Checks[i].Disconnect();
  254.    }
  255.    // Update variables
  256.    Systematic += Gap;
  257.    Gap = 0;
  258.    GapMatrix.deAllocate();
  259.    MinusPhiInverse.deAllocate();
  260. }
  261. void LDPC_Code::GenerateEncoder()
  262. {
  263.    //------------------------------------------------------
  264.    // Approximate lower triangularize
  265.    //------------------------------------------------------
  266.    // Init
  267.    Variables.Init(Graph.variable_nodes, Graph.N);
  268.    Checks.Init(Graph.check_nodes, Graph.M);
  269.    UrbankeAlgorithmAH(/* columns */ Checks, /* rows */ Variables);
  270.    // Reverse because we have made checks the columns and variables the rows
  271.    Variables.Reverse();
  272.    Checks.Reverse();
  273.    // Determine values
  274.    Systematic = Variables.GetLength() - Checks.GetLength();
  275.    Gap = Checks.Gap;
  276.    Triangle = Variables.GetLength() - Systematic - Gap;
  277.    cout << "GenerateEncoder: Gap = " << Gap << "n";
  278.    //ofstream bbbTemp("Temp.txt");
  279.    //for (int i = 0; i < Variables.GetLength(); i++)
  280.    //   for (int j = 0; j < Variables[i].GetDegree(); j++)
  281.    //      bbbTemp << Variables[i].AdjacentNode(j).GetID() << " " << i << "n";
  282.    //bbbTemp.close();
  283.    //exit(0);
  284.    int FirstCheckOfGap = Checks.GetLength() - Gap;
  285.    int FirstVarOfTriangle = Systematic + Gap;
  286.    //------------------------------------------------------
  287.    // Handle gap
  288.    //------------------------------------------------------
  289.    // Init gap matrix
  290.    GapMatrix.Init(Gap, Variables.GetLength());
  291.    for (int i = 0; i < Gap; i++)
  292.    {
  293.       //cout << FirstCheckOfGap + i << ">" << Checks[FirstCheckOfGap + i].GetID() << " " << Checks[FirstCheckOfGap + i].degree << "n";
  294.       GapMatrix.Set(i, Checks[FirstCheckOfGap + i]);
  295.    }
  296.    //ofstream bbbTemp2("Temp.txt");
  297.    //GapMatrix.SparseOut(bbbTemp2);
  298.    //bbbTemp2.close();
  299.    //exit(0);
  300.    // Gaussian elimination 
  301.    for (int j = Triangle - 1; j >= 0; j--)      // column
  302.    {
  303.       // Find element appropriate matrix element
  304.       int EliminatedCol = FirstVarOfTriangle + j;     // Column to be eliminated
  305.       check_node &CheckRow = Checks[j];     // j'th check should be nonzero at j'th column
  306.       GFq EliminatingRowVal = CheckRow.Element(EliminatedCol);        // Value of row at column to be eliminated
  307.       for (int i = 0; i < GapMatrix.M; i++)     // row of GapMatrix
  308.       {
  309.          GFq ValToBeEliminated = GapMatrix.Element(i, EliminatedCol);
  310.          if (!ValToBeEliminated.IsZero())
  311.          {
  312.             GFq Mult = (ValToBeEliminated / EliminatingRowVal).Minus();
  313.             GapMatrix.Add(i, CheckRow, Mult);
  314.          }
  315.       }
  316.    }
  317.    // obtain phi^-1
  318.    // While matrix is singular, switch columns
  319.    BOOLEAN Success = FALSE;
  320.    for (int Attempts = 0; Attempts < 10000; Attempts++)
  321.    {
  322.       matrix phi = GapMatrix.Extract(Systematic, Gap);   // Systematic = first col after systematic
  323.       MinusPhiInverse = phi.Inverse();
  324.       if (!MinusPhiInverse.IsNull())    // if success
  325.       {
  326.          MinusPhiInverse.MultiplyByMinusOne();
  327.          Success = TRUE;
  328.          break;
  329.       }
  330.       else
  331.       {  // switch columns randomly
  332.          int i1 = uniform_random(Systematic);
  333.          int i2 = uniform_random(Gap) + Systematic;
  334.          GapMatrix.SwitchColumns(i1, i2);
  335.          Variables.SwitchNodes(i1, i2);
  336.       }
  337.    }
  338.    if (!Success)
  339.    {
  340.       cout << "Unable to find an invertible phi, maybe increase number of attemptsn";
  341.       exit(1);
  342.    }
  343. }