首页 > 代码库 > MyMathLib系列(一元多项式运算求初等因子等)

MyMathLib系列(一元多项式运算求初等因子等)

利用TExp类的运算来求矩阵的特征值,初等因子等:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyMathLib
{
    /// <summary>
    /// 一元多项式计算
    /// </summary>
   public class PolynomialOfOneBasic
   {
       /// <summary>
       /// 化成对阶梯矩阵
       /// </summary>
       /// <param name="CoefficientDeterminant">系数矩阵</param>
       public static void TransToEchelonMatrix(TExp[,] CoefficientDeterminant)
       {
           var theRowCount = CoefficientDeterminant.GetLength(0);
           var theColCount = CoefficientDeterminant.GetLength(1);
           int theN = theRowCount;
           int theE = theColCount;
           //从第1列到第theE列.
           for (int i = 0; i < theE; i++)
           {
               //从第theN-1行到第1行,将D[j,i]依次变为0,需要注意的是:
               //如果第j-1行,的左元素全部为0,才能继续交换.
               for (int j = theN - 1; j > 0; j--)
               {
                   //如果为当前值为0,则不处理,继续处理上一行
                   if (CoefficientDeterminant[j, i] == (TExp)0)
                   {
                       continue;
                   }
                   //******这里增加修改了判断是否继续交换消元的条件:
                   //如果左上邻元素[j-1, i-1]以及其左边的元素都为0方可交换
                   //因为当前元素的左边元素已经全部是零,因此如果要交换不能使本行左边产生非零数,
                   //则需要左上邻及其所有元素皆为0.
                   var theCanDo = true;
                   for (int s = i - 1; s >= 0; s--)
                   {
                       if (CoefficientDeterminant[j - 1, s] != (TExp)0)
                       {
                           theCanDo = false;
                           break;
                       }
                   }
                   if (theCanDo)
                   {
                       //如果[j,i]的上一行[j-1, i]的值为0则交换
                       if (CoefficientDeterminant[j - 1, i] == (TExp)0)
                       {
                           for (int k = 0; k < theE; k++)//这里要交换常数项
                           {
                               TExp theTmpDec = CoefficientDeterminant[j, k];
                               CoefficientDeterminant[j, k] = CoefficientDeterminant[j - 1, k];
                               CoefficientDeterminant[j - 1, k] = theTmpDec;
                           }
                       }
                       else
                       {
                           var theRate2 = CoefficientDeterminant[j, i];
                           var theRate1 = CoefficientDeterminant[j - 1, i];
                           for (int k = i; k < theE; k++)//这里要计算常数项
                           {
                               CoefficientDeterminant[j, k] = 
                                   CoefficientDeterminant[j, k] * theRate1
                                   - CoefficientDeterminant[j - 1, k] * theRate2;
                           }
                           //将第i行,以最高次数系数来消除大数项.
                           double theMaxRation = 0;
                           uint theMaxPower = 0;
                           for (int k = i+1; k < theE; k++)//这里要计算常数项
                           {
                               var theMaxItem = CoefficientDeterminant[j, k].GetMaxPowerExp();
                               if (theMaxItem.Power > theMaxPower)
                               {
                                   theMaxPower = theMaxItem.Power;
                                   theMaxRation = theMaxItem.Ratio;
                               }
                               else if (theMaxItem.Power == theMaxPower)
                               {
                                   if (Math.Abs(theMaxItem.Ratio) > Math.Abs(theMaxRation))
                                   {
                                       theMaxRation = theMaxItem.Ratio;
                                   }
                               }      
                           }
                           //
                           if (theMaxRation != 0)
                           {
                               theMaxRation = 1 / theMaxRation;
                               for (int k = i + 1; k < theE; k++)//这里要计算常数项
                               {
                                   CoefficientDeterminant[j, k] = CoefficientDeterminant[j, k]  * theMaxRation;
                               }
                           }
                       }
                   }
               }
           }
       }
       /// <summary>
       /// 变换成对角矩阵,这个算法的问题在于会增加方程解。
       /// </summary>
       /// <returns>变换过程记录.</returns>
       public static void TransToStandardForm(TExp[,] CoefficientDeterminant)
       {
           //先把矩阵转换成上三角矩阵。
           TransToEchelonMatrix(CoefficientDeterminant);
           //然后从最后一列开始,第1行开始变换为0.
           var theColCount = CoefficientDeterminant.GetLength(0);
           var theRowCount = CoefficientDeterminant.GetLength(1);
           for (int j = theColCount - 1; j >= 0; j--)
           {
               //从下到上找到第1个非0行,作为基准行(减少行)
               //因为矩阵的下半部分全为0,则开始找的位置在对角线上开始.
               int theR = -1;
               int theStartIndex = Math.Min(j, theRowCount - 1);
               for (int i = theStartIndex; i >= 0; i--)
               {
                   if (CoefficientDeterminant[i, j] != (TExp)0)
                   {
                       theR = i;
                       break;
                   }
               }
               //如果找到基准行,则开始变换,利用减去基准行*一个系数来消除第0到thR-1行的元素
               if (theR >= 0)
               {
                   for (int i = 0; i < theR; i++)
                   {
                       var theRate2 = CoefficientDeterminant[theR, j];
                       var theRate1 = CoefficientDeterminant[i, j];
                       for (int k = 0; k < theColCount; k++)//这里要计算常数项
                       {
                           CoefficientDeterminant[i, k] =
                               (CoefficientDeterminant[i, k] * theRate2)
                               - (CoefficientDeterminant[theR, k] * theRate1);
                       }
                       //将第i行,以最高次数系数来消除大数项.
                       double theMaxRation = 0;
                       uint theMaxPower = 0;
                       for (int k = 0; k < theColCount; k++)//这里要计算常数项
                       {
                           var theMaxItem = CoefficientDeterminant[i, k].GetMaxPowerExp();
                           if (theMaxItem.Power > theMaxPower)
                           {
                               theMaxPower = theMaxItem.Power;
                               theMaxRation = theMaxItem.Ratio;
                           }
                           else if (theMaxItem.Power == theMaxPower)
                           {
                               if (Math.Abs(theMaxItem.Ratio) > Math.Abs(theMaxRation))
                               {
                                   theMaxRation = theMaxItem.Ratio;
                               }
                           }
                       }
                       //
                       if (theMaxRation != 0)
                       {
                           theMaxRation = 1 / theMaxRation;
                           for (int k = 0; k < theColCount; k++)//这里要计算常数项
                           {
                               CoefficientDeterminant[i, k] = CoefficientDeterminant[i, k] * theMaxRation;
                           }
                       }
                   }
               }
           }
       }
       /// <summary>
       /// 转换到对角矩阵,不会增加矩阵乘积的次数,主要用于初等因子的寻找.
       /// </summary>
       /// <param name="Elements">Lambda矩阵.</param>
       public static void TransToDiagMatrix(TExp[,] Elements)
       {
           var theRowCount = Elements.GetLength(0);
           var theColCount = Elements.GetLength(1);
           if (theRowCount != theColCount || theColCount<=0)
           {
               throw new Exception("本方法仅支持方阵,阶数n大于等于0!");
           }
           //主要用于Lambda矩阵的处理,这里从第theColCount开始处理
           //相当于从右上角开始沿对角线进行处理[theRowCount-j-1,j]
           for (int j = theRowCount-1; j >= 0; j--)
           {

               //寻找i行i列中的常数元素 0 表示没找到 1 表示遍历行找到,-1 表示列遍历找到.
               //如果当前的元素为0,如果没找到,就把找到的非常数项交换到当前位置.
               //非常数项的次数应该尽量的低.
               int  theNotZeroR = -1;
               int  theNotZeroC = -1;
               uint theNotZeroPower = uint.MaxValue;
               var theHasFind = 0;
               var theIndex = -1;
               for (int k = j; k >= 0; k--)
               {
                   if (Elements[theRowCount - j - 1, k].GetMaxPowerExp().Power < theNotZeroPower)
                   {
                       if (!Elements[theRowCount - j - 1, k].IsZero)
                       {
                           theNotZeroPower = Elements[theRowCount - j - 1, k].GetMaxPowerExp().Power;
                           theNotZeroR = theRowCount - j - 1;
                           theNotZeroC = k;
                       }
                       
                       
                   }
                   if (Elements[theRowCount - k - 1, j].GetMaxPowerExp().Power < theNotZeroPower)
                   {
                       if (!Elements[theRowCount - k - 1, j].IsZero)
                       {
                           theNotZeroPower = Elements[theRowCount - k - 1, j].GetMaxPowerExp().Power;
                           theNotZeroR = theRowCount - k - 1;
                           theNotZeroC = j;
                       }
                   }
                   if (Elements[theRowCount - j - 1, k].IsNotZeroConst)
                   {
                       theHasFind = 1;
                       theIndex = k;
                       break;
                   }
                   if (Elements[theRowCount - k - 1, j].IsNotZeroConst)
                   {
                       theHasFind = -1;
                       theIndex = theRowCount - k - 1;
                       break;
                   }
               }
               if (theHasFind != 0)
               {
                   switch (theHasFind)
                   {
                       case -1:
                           Elements.SwapRow(theIndex, j);
                           theNotZeroR = -1;
                           theNotZeroC = -1;
                           break;
                       case 1:
                           Elements.SwapCol(theIndex, j);
                           theNotZeroC =-1;
                           theNotZeroR = -1;
                           break;
                   }
                   //处理[theRowCount-j-1,j]所在行列的元素
                   RemoveNoZeroElement(Elements, theRowCount - j - 1, j);
               }
               else
               {
                   //如果没找到常数项,且当前项为0项,则交换
                   if (Elements[theRowCount - j - 1, j].IsZero)
                   {
                       //行相同,交换列
                       if (theRowCount - j - 1 == theNotZeroR)
                       {
                           Elements.SwapCol(theNotZeroC, j);
                       }
                       else
                       {
                           if(j== theNotZeroC)
                           {
                               Elements.SwapRow(theNotZeroR, theRowCount - j - 1);
                           }
                       }
                   }
                   //继续找,这次是找两个相加后为常量的项
                   //以元素[theRowCount-j-1,j]为准,先向下找.
                   #region 在同一列上向下找
                   var theHasFind2 = false;
                   var theR1 = -1;
                   var theR2 = -1;
                   double theSign = 1;
                   //这里需要考虑到对应成比例的问题.
                   
                   for (int r1 = theRowCount - j - 1; r1 < theRowCount; r1++)
                   {
                       if (Elements[r1, j].IsZero)
                       {
                           continue;
                       }
                       else
                       {
                           for (int r2 = r1 + 1; r2 < theRowCount; r2++)
                           {
                               //零元素可以不考虑.
                               if (Elements[r2, j].IsZero)
                               {
                                   continue;
                               }
                               else
                               {
                                   var theTempRatio1 = Elements[r1, j].GetMaxPowerItemRatio();
                                   var theTempRatio2 = Elements[r2, j].GetMaxPowerItemRatio();
                                   var theTempRate = theTempRatio1 / theTempRatio2;
                                   var theTemp = Elements[r1, j] + (theTempRate * Elements[r2, j]);
                                   if (theTemp.IsNotZeroConst || theTemp.IsZero)
                                   {
                                       theHasFind2 = true;
                                       theR1 = r1;
                                       theR2 = r2;
                                       theSign = theTempRate;
                                       break;
                                   }
                                   else
                                   {
                                       theTemp = Elements[r1, j] - (theTempRate * Elements[r2, j]);
                                       if (theTemp.IsNotZeroConst || theTemp.IsZero)
                                       {
                                           theHasFind2 = true;
                                           theR1 = r1;
                                           theR2 = r2;
                                           theSign = -theTempRate;
                                           break;
                                       }
                                   }
                               }

                           }
                           if (theHasFind2)
                           {
                               break;
                           }
                       }
                   }
                   if (theHasFind2)
                   {
                           var theContinue2 = true;
                           if (theR1 == theRowCount - j - 1)
                           {
                               var theTempExp = Elements[theRowCount - j - 1, j] + Elements[theR2, j] * theSign;
                               if (theTempExp.IsZero)
                               {
                                   theContinue2 = false;
                               }
                           }
                           if (theContinue2)
                           {
                               //1、先将[r,j]变为非零常量项
                               for (int c = 0; c <= j; c++)
                               {
                                   Elements[theR1, c] = Elements[theR1, c] + (Elements[theR2, c] * theSign);
                               }
                               //2、交换theRowCount-j-1 行和r1(theR1)
                               Elements.SwapRow(theRowCount - j - 1, theR1);
                           }
                       //3、以[theRowCount-j-1,j]为准,变其所在行列的非零元素为零元素. 
                       //处理[theRowCount-j-1,j]所在行列的元素
                       //如果当前元素为0,则继续处理当前行.
                       if (Elements[theRowCount - j - 1, j].IsZero)
                       {
                           j++;
                       }
                       else
                       {
                           RemoveNoZeroElement(Elements, theRowCount - j - 1, j);
                       }
                   }
                   #endregion
                   else
                   {
                       //以元素[theRowCount-j-1,j]为准,向左找.
                       #region 同一行上向左找.
                       var theHasFind3 = false;
                       var theC1 = -1;
                       var theC2 = -1;
                       double theSign2 = 1;
                       //这里需要考虑到对应成比例的问题.
                       for (int c1 = j; c1 >=0; c1--)
                       {
                           if (Elements[theRowCount-j-1, c1].IsZero)
                           {
                               continue;
                           }
                           else
                           {
                               for (int c2 = c1 -1; c2 >= 0; c2--)
                               {
                                   //零元素可以不考虑.
                                   if (Elements[theRowCount - j - 1, c2].IsZero)
                                   {
                                       continue;
                                   }
                                   else
                                   {
                                       var theTempRatio1 = Elements[theRowCount - j - 1, c1].GetMaxPowerItemRatio();
                                       var theTempRatio2 = Elements[theRowCount - j - 1, c2].GetMaxPowerItemRatio();
                                       var theTempRate = theTempRatio1 / theTempRatio2;
                                       var theTemp = Elements[theRowCount - j - 1, c1] + (theTempRate * Elements[theRowCount - j - 1, c2]);
                                       if (theTemp.IsNotZeroConst || theTemp.IsZero)
                                       {
                                           theHasFind3 = true;
                                           theC1 = c1;
                                           theC2 = c2;
                                           theSign2 = theTempRate;
                                           break;
                                       }
                                       else
                                       {
                                           theTemp = Elements[theRowCount - j - 1, c1] - (theTempRate * Elements[theRowCount - j - 1, c2]);
                                           if (theTemp.IsNotZeroConst || theTemp.IsZero)
                                           {
                                               theHasFind3 = true;
                                               theC1 = c1;
                                               theC2 = c2;
                                               theSign2 = 0.0-theTempRate;
                                               break;
                                           }
                                       }
                                   }

                               }
                               if (theHasFind3)
                               {
                                   break;
                               }
                           }
                       }
                       if (theHasFind3)
                       {
                           //1、先将[theRowCount-j-1,theC1]变为非零常量项
                           //2、当如果变换使得当前元素为0,则不进行交换
                           var theContinue3 = true;
                           if (theC1 == j)
                           {
                               var theTempExp = Elements[theRowCount - j - 1, j] + Elements[theRowCount - j - 1, theC2] * theSign2;
                               if (theTempExp.IsZero)
                               {
                                   theContinue3 = false;
                               }
                           }
                           if (theContinue3)
                           {
                               for (int r = theRowCount - j - 1; r < theRowCount; r++)
                               {
                                   Elements[r, theC1] = Elements[r, theC1] + Elements[r, theC2] * theSign2;
                               }
                               //2、交换j列和c1(theC1)

                               Elements.SwapCol(j, theC1);
                           }
                           //3、以[theRowCount-j-1,j]为准,变其所在行列的非零元素为零元素. 
                           //处理[theRowCount-j-1,j]所在行列的元素
                           //如果当前元素为0,则继续处理当前行.
                           if (Elements[theRowCount - j - 1, j].IsZero)
                           {
                               j++;
                           }
                           else
                           {
                               RemoveNoZeroElement(Elements, theRowCount - j - 1, j);
                           }
                           
                       }
                       #endregion
                   }
                   
               }
           }

       }
       /// <summary>
       /// 消除Row行,Col列的非零元素
       /// </summary>
       /// <param name="Elements"></param>
       /// <param name="Row"></param>
       /// <param name="Col"></param>
       private static void RemoveNoZeroElement(TExp[,] Elements,int Row, int Col)
       {
           var theRowCount = Elements.GetLength(0);
           
           var theRate1 = Elements[Row, Col];
           //var theConstRate = 1;// / ((TSymbolExp)theRate1).Ratio;
           ////处理列[theRowCount-j-1,0..j]
           for (int c = 0; c < Col; c++)
           {
               //零元素不用消元
               if (Elements[Row, c].IsZero)
               {
                   continue;
               }
               var theRate2 = Elements[Row, c];
               var theConstRate =  theRate2.GetMaxPowerItemRatio() / theRate1.GetMaxPowerItemRatio();
               //获取两个表达式的相关系数.
               var theTempRatio = TExp.GetRelativRation(theRate1, theRate2);
              
               //c列所在元素都需要变为0
               double theAdjustRatio = 0;
               uint theAdjustPower = 0;
               for (int r = Row; r < theRowCount; r++)
               {
                   if (theTempRatio.IsEqualTo(0))
                   {
                       Elements[r, c] = theConstRate * ((Elements[r, c] * theRate1) - (Elements[r, Col] * theRate2));
                   }
                   else
                   {
                       Elements[r, c] = (Elements[r, c] * theTempRatio) - (Elements[r, Col]);
                   }
                   var theTmpPower = Elements[r, c].GetMaxPowerExp().Power;
                   var theTmpRatio = Elements[r, c].GetMaxPowerItemRatio();
                   if (theTmpPower > theAdjustPower)
                   {
                       theAdjustPower = theTmpPower;
                       theAdjustRatio = theTmpRatio;
                   }
                   else if (theTmpPower == theAdjustPower)
                   {
                       if (Math.Abs(theAdjustRatio) < Math.Abs(theTmpRatio))
                       {
                           theAdjustRatio = theTmpRatio;
                       }
                   }
               }
               if (theAdjustPower > 0)
               {
                   for (int r = Row; r < theRowCount; r++)
                   {
                       Elements[r, c] = Elements[r, c] * (1 / theAdjustRatio);
                   }
               }
           }

           //处理行[theRowCount-j..theRowCount,j]
           for (int r = Row + 1; r < theRowCount; r++)
           {
               //如果是零元素则继续.
               if (Elements[r, Col].IsZero)
               {
                   continue;
               }
               var theRate2 = Elements[r, Col];
               var theConstRate = theRate2.GetMaxPowerItemRatio() / theRate1.GetMaxPowerItemRatio();
               double theAdjustRatio = 0;
               uint theAdjustPower = 0;
               //获取两个表达式的相关系数.
               var theTempRatio = TExp.GetRelativRation(theRate1, theRate2);
               for (int c = 0; c <= Col; c++)
               {
                   if (theTempRatio.IsEqualTo(0))
                   {
                       Elements[r, c] = theConstRate * ((Elements[r, c] * theRate1) - (Elements[Row, c] * theRate2));
                   }
                   else
                   {
                       Elements[r, c] = (Elements[r, c] * theTempRatio) - (Elements[Row, c]);
                   }
                   var theTmpPower = Elements[r, c].GetMaxPowerExp().Power;
                   var theTmpRatio = Elements[r, c].GetMaxPowerItemRatio();
                   if (theTmpPower > theAdjustPower)
                   {
                       theAdjustPower = theTmpPower;
                       theAdjustRatio = theTmpRatio;
                   }
                   else if (theTmpPower == theAdjustPower)
                   {
                       if (Math.Abs(theAdjustRatio) < Math.Abs(theTmpRatio))
                       {
                           theAdjustRatio = theTmpRatio;
                       }
                   }

               }
               if (theAdjustPower > 0)
               {
                   for (int c = 0; c <= Col; c++)
                   {
                       Elements[r, c] = Elements[r, c] * (1 / theAdjustRatio);
                   }
               }

           }
          
       }
    }
}

用法:

var theBasis = new List<double[]>();
            theBasis.Add(new double[] { 1, 0, 0 });
            theBasis.Add(new double[] { 0, 1, 0 });
            theBasis.Add(new double[] { 0, 0, 1 });
            TExp x = new TSymbolExp() { Power = 1, Ratio = 1, Symbol = "x" };
            var theP = new TExp[3, 3]{
              {     2-x,      3.0,    0.0},
              {     3,        2-x,    0.0},
              {     3,        -3,      5-x}
            };
            MyMathLib.PolynomialOfOneBasic.TransToDiagMatrix(theP);
            FormatViewArray(theP);

这里的x为Lambda,就是λ-矩阵,theP等于(A-λE).计算结果会有小数上的差异,主要是浮点运算引起的,没有完全处理回去,大家注意就行,不影响结果。

线性代数部分就到此尾声了,后面会总结一下概念。

??

MyMathLib系列(一元多项式运算求初等因子等)