抽象代数的代码实现(3)向量空间

向量空间

概念定义

上篇文章介绍了域,域可以简单的理解为一个有理数集合,这个集合中有加法运算和乘法运算,运算后的结果是封闭的,还是有理数。接下来我们从这个集合中取出n个元素,这n个元素组成一个有顺序的子集,这个子集称为n维向量。

设a、b、c是有理数,那么(a b c)是一个三维向量。所有向量组成的集合称为V,假设有理数集合为K,V中的元素为A、B、C……如果下面的运算成立,那么把V称为K上的向量空间

  • a(A+B) = aA + aB
  • (a + b)A = aA + bA
  • a(bA) = (ab)A
  • 1A = A

代码实现

在上篇文章中已经定义了有理数域的数据结构,采用分数的形式,但是经过多次加减乘除运算后会产生溢出,为了避免这个麻烦,我们采用浮点型来表示

struct FieldEle
{
    
    
    u32 nmrtr;//分子
    u32 dnmtr;//分母
    float val;
    u8 eSymb;
};

向量的结构体可以看做是由FieldEle元素组成的数组

struct VectorEle
{
    
    
    int nEle;  //数组元素个数
    FieldEle **aVecEle;//存放有理数域的数组
};

现在来定义VectorEle向量的加法,只需把aVecEle每个对应的元素相加,有理数域中的元素与向量相乘时,只要把该元素分别与aVecEle的每个元素相乘,下面证明这样定义的VectorEle是一个向量空间

首先证明a(A+B) = aA + aB,代码如下

int VectorDist1(FieldSys *pField,int nEle)
{
    
    
    int rc = 0;
    int i,j,l;
    u32 k;
    FieldEle* pFieldEle;
    OperateSys *pMult = pField->pGroup2;
    VectorEle *pVector[2];
    VectorEle *pV[5];

    //随机测试10组数据
    for(i=0; i<10; i++)
    {
    
    
        //随机生成一个有理数
        k = FakeRand(i+j*10);
        SetGenPara(pMult,k);
        pFieldEle = pMult->xGen(pMult,k);
        //随机生成2个向量
        for(j=0; j<2; j++)
        {
    
    
            pVector[j] = (VectorEle *)malloc(sizeof(VectorEle));
            memset(pVector[j],0,sizeof(VectorEle));
            pVector[j]->nEle = nEle;
            pVector[j]->aVecEle = malloc(nEle*sizeof(void *));
            for(l=0;l<nEle; l++)
            {
    
    
                k = FakeRand(i+j+l);
                SetGenPara(pMult,k);
                pVector[j]->aVecEle[l] = pMult->xGen(pMult,k);
            }
        }
        //计算A+B
        pV[0] = VectorPlus(pField,pVector[0],pVector[1]);
         //计算a(A+B)
        pV[1] = FieldMultVector(pField,pFieldEle,pV[0]);
        //计算aA
        pV[2] = FieldMultVector(pField,pFieldEle,pVector[0]);
        //计算aB
        pV[3] = FieldMultVector(pField,pFieldEle,pVector[1]);
        //计算aA+aB
        pV[4] = VectorPlus(pField,pV[2],pV[3]);
        //验证是否相等
        rc = isVecotrEqual(pField,pV[1],pV[4]);
        FreeVector(pVector[0]);
        FreeVector(pVector[1]);
        for(j=0; j<5; j++)
        {
    
    
            FreeVector(pV[j]);
        }
        assert( rc );
    }
    loga("vector Distributive1 ok %d",rc);
    return rc;
}

其他几条性质的证明类似,接口如下

void isVectorSpace(FieldSys *pField,int nEle)
{
    
    
    //a(A+B) = aA + aB
    VectorDist1(pField,nEle);
    //证明(a + b)A = aA + bA
    VectorDist2(pField,nEle);
    //a(bA)=(ab)A
    VectorAsso(pField,nEle);
    //1A=A
    VectorIdentity(pField,nEle);
}

线性相关

有了向量空间的概念后,再来介绍一个非常重要的概念也就是线性相关。假如给定向量A、B、C,如果方程
(*) x 1 A + x 2 B + x 3 C = 0 x_{1}A+x_{2}B+x_{3}C = 0\tag{*} x1A+x2B+x3C=0(*)
的解x1,x2,x3,不全为0,那么我们说向量A、B、C线性相关,线性相关的意义就是这3个向量中每一个可以由另外2个向量表示,类似的线性相关的个数可以推广到更多。

现在我们来判断给定一个向量组,判断是否是线性相关,如果这是一个三维向量空间,那么假定
A = ( a 11 a 21 a 31 ) B = ( a 12 a 22 a 32 ) C = ( a 13 a 23 a 33 ) A=\begin{pmatrix} a_{11}\\ a_{21}\\ a_{31} \end{pmatrix}\quad B=\begin{pmatrix} a_{12}\\ a_{22}\\ a_{32} \end{pmatrix}\quad C=\begin{pmatrix} a_{13}\\ a_{23}\\ a_{33} \end{pmatrix} A=a11a21a31B=a12a22a32C=a13a23a33
那么(*)式的解也就是,下列方程组的解

{ a 11 x 1 + a 12 x 2 + a 13 x 3 = 0 ( 1 ) a 21 x 1 + a 22 x 2 + a 23 x 3 = 0 ( 2 ) a 31 x 1 + a 32 x 2 + a 33 x 3 = 0 ( 3 ) \left\{\begin{matrix} a_{11}x_{1}+a_{12}x_{2}+a_{13}x_{3}=0\qquad\qquad\qquad(1)\\ a_{21}x_{1}+a_{22}x_{2}+a_{23}x_{3}=0\qquad\qquad\qquad(2)\\ a_{31}x_{1}+a_{32}x_{2}+a_{33}x_{3}=0\qquad\qquad\qquad(3) \end{matrix}\right. a11x1+a12x2+a13x3=0(1)a21x1+a22x2+a23x3=0(2)a31x1+a32x2+a33x3=0(3)
求解时采用的是消元法,先把方程(2)和方程(3)减去方程(1)乘以相关系数,消掉x1,再递归求解方程(2)和方程(3)组成的2元方程,代码如下

int isLinearDepedent(
        FieldSys *pField,
        VectorEle **paVector,//输入的向量组
        int n,//n个变量
        int iRow,//输入的方程起始编号
        int nRow)//输入的方程个数
{
    
    
    int rc = 0;
    int i,j;
    OperateSys *pPlus = pField->pGroup1;
    FieldEle **paEle;
    FieldEle *pTemp;
    FieldEle *pTempEle;

    assert(n>0);
    assert(nRow>0);
    if( n==1 )
    {
    
    
        //不断消元递归后只剩一个变量,可能还有多个方程
        paEle= (FieldEle **)&((paVector[0])->aVecEle[iRow]);
        for(i=0; i<nRow; i++)
        {
    
    
            //线性变换后,最后一列有非零元素,所以不可能存在非零解,线性无关
            if( !pPlus->xIsEqual(paEle[i],pPlus->pBaseEle) )
            {
    
    
                return 0;
            }
        }
        //如果最后一列系数全是0,那么有非零解,线性相关
        return 1;
    }
    else if( nRow==1 )
    {
    
    
        //只剩一行,但是未知变量大于1,那么必定有非零解
        return 1;
    }
    else
    {
    
    
        paEle = (FieldEle **)&((paVector[0])->aVecEle[iRow]);
        for(i=0; i<nRow; i++)
        {
    
    
            //找到第1列的非0元素,换到第一行
            if( !pPlus->xIsEqual(paEle[i],pPlus->pBaseEle) )
            {
    
    

                for(j=0;j<n;j++)
                {
    
    
                    paEle = (FieldEle **)&((paVector[j])->aVecEle[iRow]);
                    pTempEle = paEle[i];
                    paEle[i] = paEle[0];
                    paEle[0] = pTempEle;
                }
                break;
            }
        }
        paEle = (FieldEle **)&((paVector[0])->aVecEle[iRow]);
        //如果第一列的元素全为0,那么忽略这一列,递归下一列
        //todo 此时是否可以直接认定为线性相关
        if( pPlus->xIsEqual(paEle[0],pPlus->pBaseEle) )
        {
    
    
            rc = isLinearDepedent(pField,&paVector[1],n-1,iRow,nRow);
        }
        else
        {
    
    
            for(i=1; i<nRow; i++)
            {
    
    
                paEle = (FieldEle **)&((paVector[0])->aVecEle[iRow]);
                pTemp = FiledDiv(pField,paEle[i],paEle[0]);
                //pTemp是后面方程的元素与第1个方程元素的比值
                for(j=0;j<n;j++)
                {
    
    
                    paEle = (FieldEle **)&((paVector[j])->aVecEle[iRow]);
                    //根据这个比值校园
                    paEle[i] = EliminationUnkowns(pField,paEle[i],paEle[0],pTemp);
                }
                free(pTemp);
            }
            //消去第一个变量后,递归下一列和下一行,重新执行以上步骤
            rc = isLinearDepedent(pField,&paVector[1],n-1,iRow+1,nRow-1);
        }
    }

    return rc;
}

参考代码

https://github.com/pfysw/CMath

猜你喜欢

转载自blog.csdn.net/pfysw/article/details/89525138