![薛定宇教授大讲堂(卷Ⅳ):MATLAB最优化计算](https://wfqqreader-1252317822.image.myqcloud.com/cover/152/29977152/b_29977152.jpg)
2.4 联立方程组的精确求解
前面介绍过,利用图解方法只能求出给定方程的实数根,并不能求出方程的复数根,具体例子可以参见例2-12。另外,如果联立方程有多个实数根,则只能用图形方法绘制出根所在的位置,并不能直接得出根的具体值,需要逐个根进行局部放大求解,求解过程比较烦琐。此外,前面介绍的数值求解方法由于每次只能求出方程的一个根,使用起来有时也不方便。
MATLAB工具箱提供了代数方程的解析求解函数solve(),可以直接用于求解解析解存在的代数方程。如果方程的解析解不存在,则可以采用vpasolve()函数求取方程的高精度数值解,解的误差可能达到10−30或更高精度,远大于双精度数据结构下的数值解。本书称这类解为准解析解,以区别于方程的解析解与双精度意义下的数值解。
2.4.1 低阶多项式方程的解析求解
一元一次和一元二次方程可以利用solve()函数直接求解,该函数还可以用于含有其他参数的方程求解。不过如果有其他参数的存在,则可能利用现有的solve()函数不易得出三次或四次方程的解析解,尽管这些方程是存在代数解法的,除非给出特别的控制选项,后面将通过例子演示。
solve()函数的调用格式为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P37_29714.jpg?sign=1739339853-Ozw4jK24LBJdKPSbMaxiMQdj36rQU1vt-0-76d10c6d68c0dfa26e3d6f5eda5863d3)
式中,待求解的方程由符号表达式eqni表示,自变量由xi表示。返回的解是一个结构体型变量,其解由S.xi直接提取。在调用格式中eqni可以是单个的方程也可以是向量、矩阵描述的一组方程,还可以将所有的方程描述成一个向量与矩阵符号表达式eqn1,直接求解这些方程。
当然,用下面的调用格式还可以直接获得方程的解。
[x1,x2,…,xn]=solve(...),%输入变量表示与前面一致
从函数的调用和使用方面看,这种直接返回变量的调用格式比返回结构体变量的格式更实用,所以本书尽量使用这样的格式。
例2-22 试重新求解例2-2中的鸡兔同笼问题。
解 声明符号变量,并将方程用符号表达式表示出来,则可以调用solve()函数直接求解给定的方程。注意,方程中的等号应该由双等号表示。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P37_29717.jpg?sign=1739339853-9jz3SpySsMFjVKbH6Z6JmGVcT1ScjJsL-0-41f21c26bfbc82236abbfd72ed286845)
得出方程的解为x1=23,x2=12。返回变量的名字还可以选择为其他的变量,此外,如果方程右边为零,则可以省略等号。例如,上面的求解语句还可以修改成
>> syms x1 x2; [x0,y0]=solve(x1+x2-35,2*x1+4*x2-94)
例2-23 中国唐代数学家王孝通所著《缉古算经》中有一道应用题,翻译成现代数学符号可以写出下面的三次方程,试求解该方程。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P37_29721.jpg?sign=1739339853-XQIxVBipa93VxmqPIv27ir1woktvjwTL-0-cd626be7c6c3c457e98ef728a30b33dd)
解 利用符号运算方法可以直接求解这个三次方程。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P37_29723.jpg?sign=1739339853-yIQas7en5mvAl8IKkvwJXOcQoFJ5TvLZ-0-05d8ffe3e40f24f54772cda91bedd1e1)
得出方程的三个解如下。王孝通只得到了31这个解,由于它为整数,是原应用题的解,其他两个是负数,不是应用题的解。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P37_29725.jpg?sign=1739339853-WKttI1V7RApFjjNYZLhZRZMfQwSVUeYQ-0-e9a1531bebba95d256fe0402bebeb567)
例2-24 试求解下面的联立方程组,并给出方程有实数根的条件。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P38_29727.jpg?sign=1739339853-IYzy7UDO1EoYu937hdkEi5fIZYlwLFQA-0-fa9a0dc17cfdb9700b66f26b7da88986)
解 可以看出,如果对方程进行简单变换,则可以得到关于x或y一元二次方程,利用相应的求根公式,则可以写出方程的解析解。不过从给出的表达式看,如果想手工求解这样的方程并不是一件简单的事情,所以应该利用计算机来完成这样烦琐的推导。
先声明必要的符号变量,则可以将两个方程用符号表达式描述出来,再给出下面的直接求解命令。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P38_29729.jpg?sign=1739339853-3SZBg0MR4dPTUVbudLKOT7vIwDLD6uev-0-5766eebe53843297172bd241b3c3d6d7)
则可以得出方程的一对解为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P38_29731.jpg?sign=1739339853-IX1d2uQPPiq5e4ESHbvOmX5uilUcEoZg-0-60fba8f0e0d4c6365ad80a1f66c77471)
由得出的结果看,如果期望方程有实数根,则根号下的表达式应该大于等于零,即
c4−48ac−8a2c−12bc2−12a3−16c2−16ab+64≥0
例2-25 试在符号运算的框架下求取例2-7中复系数多项式方程的解析解。
解 由于已知方程的解析解存在,所以可以调用solve()函数解方程,最终得出方程的解析解为[−2,−1−j,−1−j,−1−j]T。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P38_29735.jpg?sign=1739339853-7xliBwYp7A8JbpCROKE5mcxrosmuArOa-0-13f40e73f527b2f855333733f86e8be6)
例2-26 试求解四次方程的解析解。
7s4+119s3+756s2+2128s+2240=0
解 由于四次方程有代数解求根公式,所以可以将其输入MATLAB环境,则可以调用solve()函数尝试求解。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P38_29739.jpg?sign=1739339853-uwaZOAozRZaC39Htfej5RSqql6KINIWV-0-3f69ebf1a41f39e56a717687e37c63ff)
得出方程的解为x=−5,−4,−4,−4。事实上,虽然四次方程有自己的代数解求根公式,得出的解也可能是无理数,换句话说,真正意义下的解析解也可能不存在。例如,如果原方程左侧加1,则方程仍然是四次多项式方程,这时方程的解析解可能不存在。
>> f=f+1; x=solve(f)
这样的方程由solve()函数是不能直接求解的,因为直接得出的结果如下:
root(z^4 + 17*z^3 + 108*z^2 + 304*z + 2241/7, z, 1) root(z^4 + 17*z^3 + 108*z^2 + 304*z + 2241/7, z, 2) root(z^4 + 17*z^3 + 108*z^2 + 304*z + 2241/7, z, 3) root(z^4 + 17*z^3 + 108*z^2 + 304*z + 2241/7, z, 4)
表明方程的解是z4+17z3+108z2+304z+2241/7=0的多项式方程的四个根。如果实在想得出方程的数值解,则可以调用vpa()函数或直接调用vpasolve()函数直接求解方程,得出的误差向量范数为4.7877×10−36。
>> x1=vpa(x), norm(subs(f,s,x1))
其实,若真的想求出三次或四次方程的解析解,还是可以通过设定'MaxDegree'选项实现的,不过得出的解很冗长。下面将通过例子演示得出的解。
例2-27 试求出例2-26改变后四次方程的解析解。
解 可以重新求解该方程,由于是四次方程,所以将'MaxDegree'选项设置为4。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P39_29746.jpg?sign=1739339853-aozznefOwhO9gdsvWLGKDk5eLbyDMoQ3-0-6c89c09d2c382d3d687e91146fc5ebc0)
得出的结果还是很烦琐的,经过细心的手工变量替换与化简可得
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P39_29748.jpg?sign=1739339853-VmK1U7GDqIkh5P4kYkj8x6v886wmOtdY-0-723bd53e72d73d91d9179f47317cb841)
式中,
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P39_29749.jpg?sign=1739339853-TpN1l6kLCNKxTCXzeESoj2oMzSxHHBXW-0-d018f011a8bbe7edb253b6628316be53)
有了这样的求解公式,则可以得出任意精度的方程的解。例如,由下面的语句可以得出误差为7.9004×10−104。
>> norm(vpa(subs(f,s,x),100))
2.4.2 多项式型方程的准解析解
对于一般的多项式型代数方程而言,采用vpasolve()函数有望得出方程全部的准解析解,而一般非线性代数方程只能得到一个准解析解。本节将通过例子演示各类方程的准解析解方法。
例2-28 试求解例2-12中给出的联立方程。
解 由图解法并不能有效求解例子中的联立方程,因为原方程既含有实数根,也含有复数根。可以先将方程用符号表达式的方式输入给计算机,然后调用vpasolve()函数,则可以直接求解该方程组。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P39_29755.jpg?sign=1739339853-3xyH3lSwDlUzmjjKaGeBIeGyclW6bvsI-0-51b71c216663d4d4656d250de2f85ed9)
得出的解为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P40_29756.jpg?sign=1739339853-iazPEMkKJMir0YayRmowd6tnW0ZVeF1e-0-371494dbb021d7aa634549231a2e7d0b)
得出的结果在x0和y0向量中返回,所以要检验得出的误差并不是一件容易的事,因为要重新输入方程的表达式,再求值。另一种求解的方法是将两个方程用符号变量表示出来,再直接求解,这样得出的结果与前面是完全一致的。将解代入原方程,可以得出误差为1.0196×10−38。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P40_29758.jpg?sign=1739339853-6K7f9UcqZtk00NPZKsxxR1RjeyahMKja-0-949993dc5f1eed0899eeda24b3ecbedf)
从这里给出的例子看,求解这样复杂的高阶代数方程组的难度对用户而言,与求解鸡兔同笼问题是一样的,用户需要做的就是将方程用符号表达式表示出来送给求解函数,然后等待得出的解就行了。
更简单地,还可以用向量的形式表示两个方程,这样,再调用vpasolve()函数则可以重新求解相应的方程,得出的结果与前面语句完全一致。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P40_29760.jpg?sign=1739339853-o7iu7FFVGJ8W6AALzl2OwzToBpuB5wL2-0-00ca6156e776889a7ebf79e49ecef0c4)
例2-29 试求解下面看起来很复杂的代数方程。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P40_29761.jpg?sign=1739339853-CUyEQDoH17F16fYg2x9vXk60ZOfemxyR-0-d5c6cd5ef28057839809277590807d3f)
解 这个方程与例2-12中给出的方程不一样,至少例2-12中的方程可以将一个方程代入另一个方程,最终手工得出一个高阶的多项式方程,而这个方程就没那么容易变换了。不用说求解方程,就是判定方程有多少个根,不借助计算机也不是一件容易的事。
不过不必考虑或担心这类底层问题,只需用下面的语句将原始的方程用规范的语句原原本本表示出来,就可以直接得出原方程的准解析解。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P40_29763.jpg?sign=1739339853-SEHG3Ix4K5yWSaMwkCRBCe8DeEczvFDr-0-ede9f0251c4f5363aaf9e9c9f676d5b9)
将得出的全部26个根代入原始方程,则能得出很小的计算误差,达到10−33级,说明该方程的各个解都是非常精确的。求解这样看起来难度极高的代数方程,对用户而言,求解的难度也与鸡兔同笼问题是一样的。
即使著名的Abel–Ruffini定理已经指明这类高阶多项式方程没有解析解,还是可以通过代数方程求解方法得出高精度的准解析解,得出解的精度是非常高的。
2.4.3 高次多项式矩阵方程的准解析解
定义2-8中描述了代数Riccati方程,该方程是关于X的二次型方程,是多项式型方程。如何用符号表达式表示Riccati方程是求解该方程的关键一步。这里先通过例子探讨使用vpasolve()函数求解该方程的方法。
例2-30 试求解例2-17中给出的Riccati代数方程全部的根。
解 如果想得出方程全部的根,则应该尝试vpasolve()函数。若想表示未知的X矩阵,则需要将其设置为符号变量,再构成符号矩阵,这样就可以由简单的符号表达式描述Riccati方程本身,再调用vpasolve()函数求解方程。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P41_29768.jpg?sign=1739339853-Qtvh7G97lHUEIdmgkwImRBWoVLtdt4AU-0-fc679e7e566460c7b40dd7efb98e32ac)
由符号运算可以推导出Riccati方程对应的联立方程为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P41_29770.jpg?sign=1739339853-2MkcegFNVwSLbUXQGOf9s5a9K71sjizu-0-3bd6004675012019e86f20a2d72e99f4)
经过23.04s的等待,可以得出方程全部的20组根,其中,第5、10、15、18这四组根为实数矩阵,其余为共轭复数矩阵。得出的四个实数矩阵分别为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P41_29772.jpg?sign=1739339853-ZOBTqiGub83pgSsDXdzJ22AjotFV3iz8-0-131378a0de12951d611f0f450579b586)
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P42_29773.jpg?sign=1739339853-akf0EKOO6Y13k2QFMoeKLjKnKqkOEJU4-0-cc3c1d822ac444b360b4a19b0881120c)
例2-17中得出的实数根是原方程的第15个根,可以提取该根,代入方程检验,得出的误差为1.8441×10−39。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P42_29775.jpg?sign=1739339853-Wz6jXJ9nmqdsRprHrf15ukIKFUgbqYMD-0-00aef4b97cef2bad444ceb5deaaff323)
例2-31 试用准解析解方法求解例2-19中方程的全部根。
解 给出下面的命令即可求出方程的全部20个根,其中有8个实根,其余为共轭复数根,求解过程耗时为36.75s。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P42_29777.jpg?sign=1739339853-CBEuqvdVXwURjhA95mmawADoPtGrufe0-0-05ccc07d10fb432363b7761378665dac)
前面介绍了Riccati方程的求解方法,如果将Riccati方程中AT项替换成一个自由矩阵D,则可以引出广义Riccati方程。
定义2-9 广义Riccati代数方程的数学形式为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P42_29779.jpg?sign=1739339853-Hvda7tvUgVG102YdiCaFWukq5UziP544-0-1b8735ed6df8318b546fd974619f9131)
式中,各个矩阵都是n×n矩阵。
广义Riccati方程没有现有的MATLAB函数直接求解,仍可尝试vpasolve()函数直接求解,得出方程全部的根。
例2-32 若已知如下矩阵,试求解广义Riccati方程。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P42_29782.jpg?sign=1739339853-ACsv5762Mk09MaZ5fGHW9jLMJ67RIgsp-0-8e727db437b3946c92a53128f7df1731)
解 和以前一样,先输入几个矩阵,然后由符号表达式的方式描述方程,再给出求解命令就可以直接求解方程了。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P42_29785.jpg?sign=1739339853-iV0b1eojI8CCdZNAs0Y2qf43TAjBDJWV-0-77561c276293989d497c600035a68c7f)
经过25s的等待,由上述求解语句可以直接得出方程的20个根,其中,8个根为实数矩阵,其余的为共轭复数矩阵。
例2-33 本丛书卷III例5-42曾探讨了一个高次矩阵方程的求解问题。
AX3+X4D−X2BX+CX−I=0
其中,已知的矩阵为
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P43_29788.jpg?sign=1739339853-24mMdat3n8AQyqrJTBAGMr0M9DicDL0i-0-3373f34e5eb4f2e0e1050b6ca7211c35)
试用这里给出的方法求取该方程的解矩阵。
解 很自然地,可以给出下面的求解命令,不幸的是,经过1843.8s的长时间等待,只得出了方程的一个根,并给出警告信息“Solutions might be lost”(根可能丢失了),说明用这样的方法也不能确保得出方程所有的根。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P43_29792.jpg?sign=1739339853-G77oqUD3uyqDVVuX8HnVd2lTE4cf7ETA-0-2e3edb41bebda70b26810039e05994b0)
例2-34 试求解含有复数矩阵的Riccati方程的准解析解。
解 很自然地可以考虑使用下面的语句直接求解需要的复系数Riccati方程,同样的步骤和语句,由于涉及复系数,求解过程极其耗时,大约379s才能得出结果(实系数方程耗时23.04s,相差16倍)。可以得出方程的20个根,全部为复数根。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P43_29794.jpg?sign=1739339853-KtSiq8pxyL9uYJD1c6EUf0ytNJ82puhj-0-ab2cf7695d214635d50f94bf095bba3e)
2.4.4 非线性代数方程的准解析解
如果用符号表达式可以描述出非线性联立方程组,则可以由vpasolve()函数直接求解方程,得出方程的解。与多项式类方程不同,这样得出的解很可能是众多解中的一个,如果原始方程含有多个解,则用户可以自己选择一个搜索的初值,从该初值x0出发直接搜索准解析解。相应的函数调用格式为
x=vpasolve(eqn1,eqn2,···,eqnn,x1,x2,···,x,n,x0)
式中,x0为未知量向量的初始搜索点。如果原方程是多项式型的联立方程,则x0对求解结果没有影响。该函数的另一种调用格式为
x=vpasolve(eqn1,eqn2,···,eqnn,x1,x2,···,xn,xm,xM)
式中,xm与xM为未知数向量x的下界与上界向量。
例2-35 试求解例2-11给出的代数方程的根,可以选择初始搜索点(2,2)。
解 利用下面自然的方式可以直接求解非线性代数方程。
![](https://epubservercos.yuewen.com/2E5615/16499866905000206/epubprivate/OEBPS/Images/Figure-P44_29800.jpg?sign=1739339853-YHsi671bpdoaVgFcfmKCI4ylJ0a2bzMQ-0-e86ff38ec5d59b5504a5dde980c004b0)
得出方程的解如下,代入原方程则误差的范数为2.0755×10−37。由此可见,方程解的精度远高于前面介绍的数值解法精度。
x0=3.0029898235869693047992458712192
y0=−6.2769296697194948789764344182923
从给出的例子可见,尽管这里给出的方法能得出方程的高精度解,但仍然有一个问题尚未解决,就是如何一次性地求出如图2-6所示的所有交点坐标,即联立方程在感兴趣区域内所有的解,这将是2.5节需要解决的问题。