Advertisement
Guest User

Untitled

a guest
Apr 13th, 2021
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function invModGcdEx(x, domain)
  2. {
  3.     if(x === 1)
  4.     {
  5.         return 1;
  6.     }
  7.     else
  8.     {
  9.         //В случае 0 или делителя нуля возвращается 0, означающий некий "некорректный результат"
  10.         if(x === 0 || domain % x === 0)
  11.         {
  12.             return 0;
  13.         }
  14.         else
  15.         {
  16.             //Расширенный алгоритм Евклида, вычисляющий такое число tCurr, что tCurr * x + rCurr * N = 1
  17.             //Другими словами, существует такое число rCurr, при котором tCurr * x mod N = 1
  18.             let tCurr = 0;
  19.             let rCurr = domain;
  20.             let tNext = 1;
  21.             let rNext = x;
  22.             while(rNext !== 0)
  23.             {
  24.                 let quotR = Math.floor(rCurr / rNext);
  25.                 let tPrev = tCurr;
  26.                 let rPrev = rCurr;
  27.  
  28.                 tCurr = tNext;
  29.                 rCurr = rNext;
  30.  
  31.                 tNext = Math.floor(tPrev - quotR * tCurr);
  32.                 rNext = Math.floor(rPrev - quotR * rCurr);
  33.             }
  34.  
  35.             tCurr = (tCurr + domain) % domain;
  36.             return tCurr;
  37.         }
  38.     }
  39. }
  40.  
  41. function wholeMod(x, domain)
  42. {
  43.     return ((x % domain) + domain) % domain;
  44. }
  45.  
  46. function mulSubRow(rowLeft, rowRight, mulValue, domain)
  47. {
  48.     for(let i = 0; i < rowLeft.length; i++)
  49.     {
  50.         rowLeft[i] = wholeMod(rowLeft[i] - mulValue * rowRight[i], domain);
  51.     }
  52. }
  53.  
  54. function mulRow(row, mulValue, domain)
  55. {
  56.     for(let i = 0; i < row.length; i++)
  57.     {
  58.         row[i] = (row[i] * mulValue) % domain;
  59.     }
  60. }
  61.  
  62. function mulSubRowCached(rowLeft, rowRight, mulValue, wholeModCache, cacheIndexOffset)
  63. {
  64.     for(let i = 0; i < rowLeft.length; i++)
  65.     {
  66.         rowLeft[i] = wholeModCache[rowLeft[i] - mulValue * rowRight[i] + cacheIndexOffset];
  67.     }
  68. }
  69.  
  70. function mulRowCached(row, mulValue, domain, wholeModCache, cacheIndexOffset)
  71. {
  72.     for(let i = 0; i < row.length; i++)
  73.     {
  74.         row[i] = domain - wholeModCache[cacheIndexOffset - row[i] * mulValue];
  75.     }
  76. }
  77.  
  78. function invertMatrix(matrix, domain)
  79. {
  80.     let matrixSize = matrix.length;
  81.  
  82.     //Инициализируем обратную матрицу единичной
  83.     let invMatrix = [];
  84.     for(let i = 0; i < matrixSize; i++)
  85.     {
  86.         let matrixRow = new Uint8Array(matrixSize);
  87.         matrixRow.fill(0);
  88.  
  89.         matrixRow[i] = 1;
  90.         invMatrix.push(matrixRow);
  91.     }
  92.  
  93.     //Прямой ход: приведение матрицы к ступенчатому виду
  94.     for(let i = 0; i < matrixSize; i++)
  95.     {
  96.         let thisRowFirst = matrix[i][i];
  97.         if(thisRowFirst === 0 || (thisRowFirst !== 1 && domain % thisRowFirst === 0)) //Первый элемент строки 0 или делитель нуля, меняем строку местами со следующей строкой, у которой первый элемент не 0
  98.         {
  99.             for(let j = i + 1; j < matrixSize; j++)
  100.             {
  101.                 let otherRowFirst = matrix[j][i];
  102.                 if(otherRowFirst !== 0 && (otherRowFirst === 1 || domain % otherRowFirst !== 0)) //Нашли строку с ненулевым первым элементом
  103.                 {
  104.                     thisRowFirst = otherRowFirst;
  105.                    
  106.                     let tmpMatrixRow = matrix[i];
  107.                     matrix[i]        = matrix[j];
  108.                     matrix[j]        = tmpMatrixRow;
  109.  
  110.                     let tmpInvMatrixRow = invMatrix[i];
  111.                     invMatrix[i]        = invMatrix[j];
  112.                     invMatrix[j]        = tmpInvMatrixRow;
  113.  
  114.                     break;
  115.                 }
  116.             }
  117.         }
  118.  
  119.         //Обнуляем первые элементы всех строк после первой, отнимая от них (otherRowFirst / thisRowFirst) * x mod N
  120.         let invThisRowFirst = invModGcdEx(thisRowFirst, domain);
  121.         for(let j = i + 1; j < matrixSize; j++)
  122.         {
  123.             let otherRowFirst = matrix[j][i];
  124.             let mulValue      = invThisRowFirst * otherRowFirst;
  125.  
  126.             if(otherRowFirst !== 0 && (otherRowFirst === 1 || domain % otherRowFirst !== 0))
  127.             {
  128.                 mulSubRow(matrix[j],    matrix[i],    mulValue, domain);
  129.                 mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);
  130.             }
  131.         }
  132.     }
  133.  
  134.     //Обратный ход - обнуление всех элементов выше главной диагонали
  135.     let matrixRank = matrixSize;
  136.     for(let i = matrixSize - 1; i >= 0; i--)
  137.     {
  138.         let thisRowLast    = matrix[i][i];
  139.         let invThisRowLast = invModGcdEx(thisRowLast, domain);
  140.         for(let j = i - 1; j >= 0; j--)
  141.         {
  142.             let otherRowLast = matrix[j][i];
  143.             let mulValue     = invThisRowLast * otherRowLast;
  144.  
  145.             if(otherRowLast !== 0 && (otherRowLast === 1 || domain % otherRowLast !== 0))
  146.             {
  147.                 mulSubRow(matrix[j],    matrix[i],    mulValue, domain);
  148.                 mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);
  149.             }
  150.         }
  151.  
  152.         if(thisRowLast !== 0 && domain % thisRowLast !== 0)
  153.         {
  154.             mulRow(matrix[i],    invThisRowLast, domain);
  155.             mulRow(invMatrix[i], invThisRowLast, domain);
  156.         }
  157.  
  158.         if(matrix[i].every(val => val === 0))
  159.         {
  160.             matrixRank -= 1;
  161.         }
  162.     }
  163.  
  164.     return {inverse: invMatrix, rank: matrixRank};
  165. }
  166.  
  167. function invertMatrixCachedInverses(matrix, domain)
  168. {
  169.     let matrixSize = matrix.length;
  170.  
  171.     //Инициализируем обратную матрицу единичной
  172.     let invMatrix = [];
  173.     for(let i = 0; i < matrixSize; i++)
  174.     {
  175.         let matrixRow = new Uint8Array(matrixSize);
  176.         matrixRow.fill(0);
  177.  
  178.         matrixRow[i] = 1;
  179.         invMatrix.push(matrixRow);
  180.     }
  181.  
  182.     //Вычисляем все обратные элементы заранее
  183.     let domainInvs = [];
  184.     for(let d = 0; d < domain; d++)
  185.     {
  186.         domainInvs.push(invModGcdEx(d, domain));
  187.     }
  188.  
  189.     //Прямой ход: приведение матрицы к ступенчатому виду
  190.     for(let i = 0; i < matrixSize; i++)
  191.     {
  192.         let thisRowFirst = matrix[i][i];
  193.         if(domainInvs[thisRowFirst] === 0) // <--- Первый элемент строки 0 или делитель нуля, меняем строку местами со следующей строкой, у которой первый элемент не 0
  194.         {
  195.             for(let j = i + 1; j < matrixSize; j++)
  196.             {
  197.                 let otherRowFirst = matrix[j][i];
  198.                 if(domainInvs[otherRowFirst] !== 0) // <--- Нашли строку с ненулевым первым элементом
  199.                 {
  200.                     thisRowFirst = otherRowFirst;
  201.                    
  202.                     let tmpMatrixRow = matrix[i];
  203.                     matrix[i]        = matrix[j];
  204.                     matrix[j]        = tmpMatrixRow;
  205.  
  206.                     let tmpInvMatrixRow = invMatrix[i];
  207.                     invMatrix[i]        = invMatrix[j];
  208.                     invMatrix[j]        = tmpInvMatrixRow;
  209.  
  210.                     break;
  211.                 }
  212.             }
  213.         }
  214.  
  215.         //Обнуляем первые элементы всех строк после первой, отнимая от них (otherRowFirst / thisRowFirst) * x mod N
  216.         let invThisRowFirst = domainInvs[thisRowFirst]; // <---
  217.         for(let j = i + 1; j < matrixSize; j++)
  218.         {
  219.             let otherRowFirst = matrix[j][i];
  220.             let mulValue      = invThisRowFirst * otherRowFirst;
  221.  
  222.             if(domainInvs[otherRowFirst] !== 0) // <---
  223.             {
  224.                 mulSubRow(matrix[j],    matrix[i],    mulValue, domain);
  225.                 mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);
  226.             }
  227.         }
  228.     }
  229.  
  230.     //Обратный ход - обнуление всех элементов выше главной диагонали
  231.     let matrixRank = matrixSize;
  232.     for(let i = matrixSize - 1; i >= 0; i--)
  233.     {
  234.         let thisRowLast    = matrix[i][i];
  235.         let invThisRowLast = domainInvs[thisRowLast]; // <---
  236.         for(let j = i - 1; j >= 0; j--)
  237.         {
  238.             let otherRowLast = matrix[j][i];
  239.             let mulValue     = invThisRowLast * otherRowLast;
  240.  
  241.             if(domainInvs[otherRowLast] !== 0) // <---
  242.             {
  243.                 mulSubRow(matrix[j],    matrix[i],    mulValue, domain);
  244.                 mulSubRow(invMatrix[j], invMatrix[i], mulValue, domain);
  245.             }
  246.         }
  247.  
  248.         if(domainInvs[thisRowLast] !== 0) // <---
  249.         {
  250.             mulRow(matrix[i],    invThisRowLast, domain);
  251.             mulRow(invMatrix[i], invThisRowLast, domain);
  252.         }
  253.  
  254.         if(matrix[i].every(val => val === 0))
  255.         {
  256.             matrixRank -= 1;
  257.         }
  258.     }
  259.  
  260.     return {inverse: invMatrix, rank: matrixRank};
  261. }
  262.  
  263. function invertMatrixCachedMod(matrix, domain)
  264. {
  265.     let matrixSize = matrix.length;
  266.  
  267.     //Инициализируем обратную матрицу единичной
  268.     let invMatrix = [];
  269.     for(let i = 0; i < matrixSize; i++)
  270.     {
  271.         let matrixRow = new Uint8Array(matrixSize);
  272.         matrixRow.fill(0);
  273.  
  274.         matrixRow[i] = 1;
  275.         invMatrix.push(matrixRow);
  276.     }
  277.  
  278.     //Вычисляем все обратные элементы заранее
  279.     let domainInvs = [];
  280.     for(let d = 0; d < domain; d++)
  281.     {
  282.         domainInvs.push(invModGcdEx(d, domain));
  283.     }
  284.  
  285.     //Вычисляем кэш деления по модулю
  286.     const cacheIndexOffset = (domain - 1) * (domain - 1);
  287.  
  288.     let wholeModCache = new Uint8Array((domain - 1) * (domain - 1) + domain);
  289.     for(let i = 0; i < wholeModCache.length; i++)
  290.     {
  291.         let divisor      = i - cacheIndexOffset; //[-cacheIndexOffset, domain - 1]
  292.         wholeModCache[i] = wholeMod(divisor, domain);
  293.     }
  294.  
  295.     //Прямой ход: приведение матрицы к ступенчатому виду
  296.     for(let i = 0; i < matrixSize; i++)
  297.     {
  298.         let thisRowFirst = matrix[i][i];
  299.         if(domainInvs[thisRowFirst] === 0) //Первый элемент строки 0 или делитель нуля, меняем строку местами со следующей строкой, у которой первый элемент не 0
  300.         {
  301.             for(let j = i + 1; j < matrixSize; j++)
  302.             {
  303.                 let otherRowFirst = matrix[j][i];
  304.                 if(domainInvs[otherRowFirst] !== 0) //Нашли строку с ненулевым первым элементом
  305.                 {
  306.                     thisRowFirst = otherRowFirst;
  307.                    
  308.                     let tmpMatrixRow = matrix[i];
  309.                     matrix[i]        = matrix[j];
  310.                     matrix[j]        = tmpMatrixRow;
  311.  
  312.                     let tmpInvMatrixRow = invMatrix[i];
  313.                     invMatrix[i]        = invMatrix[j];
  314.                     invMatrix[j]        = tmpInvMatrixRow;
  315.  
  316.                     break;
  317.                 }
  318.             }
  319.         }
  320.  
  321.         //Обнуляем первые элементы всех строк после первой, отнимая от них (otherRowFirst / thisRowFirst) * x mod N
  322.         let invThisRowFirst = domainInvs[thisRowFirst];
  323.         for(let j = i + 1; j < matrixSize; j++)
  324.         {
  325.             let otherRowFirst = matrix[j][i];
  326.             let mulValue      = domain - wholeModCache[cacheIndexOffset - invThisRowFirst * otherRowFirst]; // <---
  327.  
  328.             if(domainInvs[otherRowFirst] !== 0)
  329.             {
  330.                 mulSubRowCached(matrix[j],    matrix[i],    mulValue, wholeModCache, cacheIndexOffset); // <---
  331.                 mulSubRowCached(invMatrix[j], invMatrix[i], mulValue, wholeModCache, cacheIndexOffset); // <---
  332.             }
  333.         }
  334.     }
  335.  
  336.     //Обратный ход - обнуление всех элементов выше главной диагонали
  337.     let matrixRank = matrixSize;
  338.     for(let i = matrixSize - 1; i >= 0; i--)
  339.     {
  340.         let thisRowLast    = matrix[i][i];
  341.         let invThisRowLast = domainInvs[thisRowLast];
  342.         for(let j = i - 1; j >= 0; j--)
  343.         {
  344.             let otherRowLast = matrix[j][i];
  345.             let mulValue     = domain - wholeModCache[cacheIndexOffset - invThisRowLast * otherRowLast]; // <---
  346.  
  347.             if(domainInvs[otherRowLast] !== 0)
  348.             {
  349.                 mulSubRowCached(matrix[j],    matrix[i],    mulValue, wholeModCache, cacheIndexOffset); // <---
  350.                 mulSubRowCached(invMatrix[j], invMatrix[i], mulValue, wholeModCache, cacheIndexOffset); // <---
  351.             }
  352.         }
  353.  
  354.         if(domainInvs[thisRowLast] !== 0)
  355.         {
  356.             mulRowCached(matrix[i],    invThisRowLast, domain, wholeModCache, cacheIndexOffset); // <---
  357.             mulRowCached(invMatrix[i], invThisRowLast, domain, wholeModCache, cacheIndexOffset); // <---
  358.         }
  359.  
  360.         if(matrix[i].every(val => val === 0))
  361.         {
  362.             matrixRank -= 1;
  363.         }
  364.     }
  365.  
  366.     return {inverse: invMatrix, rank: matrixRank};
  367. }
  368.  
  369. function createRandomMatrix(matrixSize, domain)
  370. {
  371.     let matrix = [];
  372.     for(let i = 0; i < matrixSize; i++)
  373.     {
  374.         let matrixRow = new Uint8Array(matrixSize);
  375.         for(let j = 0; j < matrixSize; j++)
  376.         {
  377.             matrixRow[j] = Math.floor(Math.random() * domain);
  378.         }
  379.        
  380.         matrix.push(matrixRow);
  381.     }
  382.  
  383.     return matrix;
  384. }
  385.  
  386. function main()
  387. {
  388.     let matrixSize = 500;
  389.     let domains    = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
  390.  
  391.     const test_count = 5;
  392.     for(let i = 0; i < domains.length; i++)
  393.     {
  394.         let domain = domains[i];
  395.         console.log("");
  396.         console.log("DOMAIN: " + domain);
  397.  
  398.         for(let i = 0; i < test_count; i++)
  399.         {
  400.             let matrix = createRandomMatrix(matrixSize, domain);
  401.    
  402.             console.time("Matrix regular inversion " + i);
  403.             invMatrixData = invertMatrix(matrix, domain);
  404.             console.timeEnd("Matrix regular inversion " + i);
  405.         }
  406.    
  407.         for(let i = 0; i < test_count; i++)
  408.         {
  409.             let matrix = createRandomMatrix(matrixSize, domain);
  410.    
  411.             console.time("Matrix domain inverses " + i);
  412.             invMatrixData = invertMatrixCachedInverses(matrix, domain);
  413.             console.timeEnd("Matrix domain inverses "  + i);
  414.         }
  415.    
  416.         for(let i = 0; i < test_count; i++)
  417.         {
  418.             let matrix = createRandomMatrix(matrixSize, domain);
  419.    
  420.             console.time("Matrix cached all " + i);
  421.             invMatrixData = invertMatrixCachedMod(matrix, domain);
  422.             console.timeEnd("Matrix cached all " + i);
  423.         }
  424.     }
  425. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement