高斯消去法

高斯消去法（）是线性代数中的一个算法，可以把矩阵转化为行阶梯形矩阵。高斯消去法可用来为线性方程组求解，求出矩阵的秩，以及求出可逆方阵的逆矩阵。
历史.
高斯消去法最早出现在中国数学典籍《九章算术》第八章〈方阵〉中，尽管书中未对其提供正式的证明。该方法在十八道题目中有所应用，处理的联立方程组数量介于二至五个之间。根据历史记载，此书最早的确切引用可追溯至公元 179 年，但其中部分内容可能早在公元前 150 年左右便已撰写完成。到了三世纪，刘徽为其作注解。
根据 Grcar 的研究，透过消去法求解线性方程组的概念在欧亚大陆的多个文化中独立发展，最早可追溯至古代。在欧洲，文艺复兴晚期（16 世纪 50 年代）便已有明确记载该方法的应用。当时，数学家可能已将其视为基础知识，因此未特意加以说明，这也使得我们难以确切还原其详细的发展历程，仅能确定该方法在当时的欧洲多个地区已被广泛使用。
在欧洲，高斯消去法的发展可追溯至艾萨克·牛顿的笔记。 1670 年，牛顿指出，他所知的代数书籍中皆缺少求解联立方程组的相关内容，于是他亲自补充了这一部分。剑桥大学最终于 1707 年出版了这些笔记，书名为《》，当时牛顿已经离开学术界。该书的内容被广泛仿效，使得（现今所称的）高斯消去法在 18 世纪末成为代数教科书中的标准课程。 1810 年，卡尔·高斯设计了一种用于对称消去的记号，并在 19 世纪被专业计算员采用，以求解最小二乘问题的法方程。然而，直到 1950 年代，由于对该方法历史的误解，这一演算法才被命名为「高斯消去法」。
部分学者将「高斯消去法」仅用于指将矩阵化为梯形（阶梯）形式的过程，而将「高斯－约旦消去法」用于指将矩阵进一步化为简化梯形（最简）形式的完整过程。之所以使用这一名称，是因为该方法是高斯消去法的变体，由于 1888 年加以描述。然而，同一年克拉森（Clasen）发表的文章中也提出了这种方法，因此乔丹与克拉森很可能是独立发现高斯－约旦消去法的。
例子.
高斯消去法可用来找出下列方程组的解或其解的限制：
formula_1
这个算法的原理是：
首先，要将formula_2以下的等式中的formula_3消除，然后再将formula_4以下的等式中的formula_5消除。这样可使整个方程组变成一个三角形似的格式。之后再将已得出的答案一个个地代入已被简化的等式中的未知数中，就可求出其余的答案了。
在刚才的例子中，我们将formula_6和formula_4相加，就可以将formula_4中的formula_3消除了。然后再将formula_2和formula_11相加，就可以将formula_11中的formula_3消除。
我们可以这样写：
结果就是：
现在将formula_19和formula_11相加，就可将formula_11中的formula_5消除：
其结果是：
这样就完成了整个算法的初步，一个三角形的格式（指：变数的格式而言，上例中的变数各为3,2,1个）出现了。
第二步，就是由尾至头地将已知的答案代入其他等式中的未知数。第一个答案就是：
然后就可以将formula_28代入formula_4中，立即就可得出第二个答案：
之后，将formula_28和formula_5代入formula_2之中，最后一个答案就出来了：
就是这样，这个方程组就被高斯消去法解决了。
这种算法可以用来解决所有线性方程组。即使一个方程组不能被化为一个三角形的格式，高斯消去法仍可找出它的解。例如，如果在第一步化简后，formula_4及formula_11中没有出现任何formula_5，没有三角形的格式，照著高斯消去法而产生的格式仍是一个-{zh-hans:行; zh-hant:列;}-阶梯形矩阵。这情况之下，这个方程组会有超过一个解，当中会有至少一个变数作为答案。每当变数被锁定，就会出现一个解。
通常人或电脑在应用高斯消去法的时候，不会直接写出方程组的等式来消去未知数，反而会使用矩阵来计算。以下就是使用矩阵来计算的例子： 
跟著以上的方法来运算，这个矩阵可以转变为以下的样子：
这矩阵叫做「-{zh-hans:行; zh-hant:列;}-阶梯形矩阵」。
最后，可以利用同样的算法产生以下的矩阵，便可把所得出的解或其限制简明地表示出来：
最后这矩阵叫做「简化-{zh-hans:行; zh-hant:列;}-阶梯形矩阵」，亦是高斯-若尔当消元法指定的步骤。
其他应用.
找出逆矩阵.
高斯消去法可以用来找出一个可逆矩阵的逆矩阵。设formula_41为一个formula_42的矩阵，其逆矩阵可被两个分块矩阵表示出来。将一个formula_42 单位矩阵放在formula_41的右手边，形成一个formula_45的分块矩阵formula_46。经过高斯消去法的计算程序后，矩阵formula_47的左手边会变成一个单位矩阵formula_48，而逆矩阵formula_49会出现在formula_47的右手边。
假如高斯消去法不能将formula_41化为三角形的格式，那就代表formula_41是一个不可逆的矩阵。
应用上，高斯消去法极少被用来求出逆矩阵。高斯消去法通常只为线性方程组求解。
计出秩和基底的基本算法.
高斯消去法可应用在任何formula_53的矩阵formula_41。在不可减去某数的情况下，我们都只有跳到下一行。以一个formula_55的矩阵作例，它可能可以变化为一个-{zh-hans:行; zh-hant:列;}-阶梯形矩阵：
而矩阵中的*是一些数字。这个-{zh-hans:行; zh-hant:列;}-阶梯形矩阵formula_57会有一些关于formula_41的资讯：
分析.
高斯消去法的算法复杂度是O("n"3)；这就是说，如果系数矩阵的是"n" × "n"，那么高斯消去法所需要的计算量大约与"n"3成比例。
高斯消去法可以用在电脑中来解决数千条等式及未知数。不过，如果有过百万条等式时，这个算法会十分费时。一些极大的方程组通常会用迭代法来解决。亦有一些方法特地用来解决一些有特别排列的系数的方程组。
高斯消去法可用在任何域中。
高斯消去法对于一些矩阵来说是稳定的。对于普遍的矩阵来说，高斯消去法在应用上通常也是稳定的，不过亦有例外。
伪代码.
高斯消去法的其中一种伪代码：
 i = 1
 j = 1
 while (i ≤ m and j ≤ n) do
 Find pivot in column j, starting in row i // 从第i行(row)开始，找出第j列(column )中的最大值（i、j值应保持不变） #台湾与大陆的列、行定义相反。台湾列为row行为column，大陆列为column行为row。
 maxi = i
 for k = i+1 to m do
 if abs(A[k,j]) &gt; abs(A[maxi,j]) then
 maxi = k // 使用交换法找出最大值（绝对值最大）
 end if
 end for
 if A[maxi,j] ≠ 0 then // 判定找到的绝对值最大值是否为零：若不为零就进行以下操作；若为零则说明该列第(i+1)列以下（包括第(i+1)列）均为零，不需要再处理，直接跳转至第(j+1)行第(i+1)列
 swap rows i and maxi, but do not change the value of i // 将第i行与找到的最大值所在行做交换，保持i值不变（i值记录了本次操作的起始行）
 Now A[i,j] will contain the old value of A[maxi,j].
 divide each entry in row i by A[i,j] // 将交换后的第i列归一化（第i列所有元素分别除以A[i,j]）
 Now A[i,j] will have the value 1.
 for u = i+1 to m do // 第j行中，第(i+1)列以下（包括第(i+1)列）所有元素都减去A[i,j]，直到第j行的i+1列以后元素均为零
 subtract A[u,j] * row i from row u
 Now A[u,j] will be 0, since A[u,j] - A[i,j] * A[u,j] = A[u,j] - 1 * A[u,j] = 0.
 end for
 i = i + 1 
 end if
 j = j + 1 // 第j行中，第(i+1)列以下（包括第(i+1)列）所有元素均为零。移至第(j+1)行，从第(i+1)列开始重复上述步骤。
 end while
这个算法和之前谈到的有点不同，它由绝对值最大的部分开始做起，这样可以改善算法的稳定性。本算法由左至右地计算，每作出以下三个步骤，才跳到下一行和下一列：
所有步骤完成后，这个矩阵会变成一个-{zh-hans:行; zh-hant:列;}-阶梯形矩阵，再用代入法就可以求解该方程组。
随着多核处理器的日益普及，现在的程序员可以利用线程级并行高斯消元算法来提高计算的速度。内存共享模式（而不是消息交换模式）的伪代码如下所示：
void parallel(int num_threads,int matrix_dimension)
 int i;
 for(i=0; i&lt;num_threads; i++)
 create_thread(&amp;threads[i],i);
 pthread_attr_destroy(&amp;attr); // Free attribute and wait for the other threads
 for(i=0; i&lt;p; i++)
 pthread_join(threads[i],NULL);
void *gauss(int thread_id)
 int i,k,j;
 for(k=0; k&lt;matrix_dimension-1; k++)
 if(thread_id==(k%num_thread)) //interleaved-row work distribution
 for(j=k+1; j&lt;matrix_dimension; j++)
 M[k][j]=M[k][j]/M[k][k];
 M[k][k]=1;
 barrier(num_thread,&amp;mybarrier); //wait for other thread finishing this round
 for(i=k+1; i&lt;matrix_dimension; i=i+1)
 if(i%p==thread_id)
 for(j=k+1; j&lt;matrix_dimension; j++)
 M[i][j]=M[i][j]-M[i][j]*M[k][j];
 M[i][k]=0;
 barrier(num_thread,&amp;mybarrier);
 return NULL;
void barrier(int num_thread, barrier_t * mybarrier)
 pthread_mutex_lock(&amp;(mybarrier-&gt;barrier_mutex));
 mybarrier-&gt;cur_count++;
 if(mybarrier-&gt;cur_count!=num_thread)
 pthread_cond_wait(&amp;(mybarrier-&gt;barrier_cond),&amp;(mybarrier-&gt;barrier_mutex));
 else
 mybarrier-&gt;cur_count=0;
 pthread_cond_broadcast(&amp;(mybarrier-&gt;barrier_cond));
 pthread_mutex_unlock(&amp;(mybarrier-&gt;barrier_mutex));