├── .gitattributes ├── .gitignore ├── README.md ├── practice-app ├── doc │ ├── img │ │ ├── error.png │ │ └── plot.png │ ├── practice-app-doc.pdf │ └── practice-app-doc.tex ├── problem │ └── practice-app.pdf └── src │ └── approx │ ├── main.m │ ├── myLagrangeInterp.m │ ├── myLagrangeUniformApprox.m │ ├── myLegendreSquareApprox.m │ ├── myTchebychevUniformApprox.m │ └── sampleFunction.m ├── practice-eig ├── doc │ ├── img │ │ └── compare_time.png │ ├── practice-eig-doc.pdf │ └── practice-eig-doc.tex ├── problem │ └── practice-eig.pdf └── src │ └── eigen │ ├── QRForHessenberg.m │ ├── givensForJiacobi.m │ ├── inversePowerMethod.m │ ├── main.m │ ├── myJacobiClassic.m │ ├── myJacobiThreshold.m │ ├── myQR.m │ └── plotTime.m ├── practice-interp ├── doc │ ├── img │ │ ├── compare.png │ │ └── runge.png │ ├── practice-interp-doc.pdf │ └── practice-interp-doc.tex ├── problem │ └── practice-interp.pdf └── src │ └── interp │ ├── main.m │ ├── myLagrangeInterp.m │ ├── myLinearInterp.m │ ├── mySplineInterp.m │ ├── plotRunge.m │ └── sampleFunction.m ├── practice-ls ├── doc │ ├── img │ │ ├── gmres20.png │ │ ├── gmres200.png │ │ ├── iterations.png │ │ ├── relative_error.png │ │ └── time.png │ ├── practice-ls-doc.pdf │ └── practice-ls-doc.tex ├── problem │ └── practice-ls.pdf └── src │ └── linear │ ├── GMRESfromWeb.m │ ├── myCG.m │ ├── myCholesky.m │ ├── myGMRESm.m │ ├── myGauss.m │ ├── myPCG.m │ ├── myTikhonov.m │ ├── plotError.m │ ├── plotGMRES.m │ ├── plotIterations.m │ └── plotTime.m ├── practice-nls ├── doc │ ├── img │ │ ├── plot3.png │ │ └── plot5.png │ ├── practice-nls-doc.pdf │ └── practice-nls-doc.tex ├── problem │ └── practice-nls.pdf └── src │ └── nlinear │ ├── main.m │ ├── myFixedPoint.m │ ├── myNewton.m │ └── mySteffensen.m ├── practice-ode ├── doc │ ├── practice-ode-doc.pdf │ └── practice-ode-doc.tex ├── problem │ └── practice-ode.pdf └── src │ └── ode │ ├── main.m │ ├── max_error.m │ ├── myRungeKutta24.m │ └── myRungeKutta44.m └── practice-quad ├── doc ├── img │ ├── gauss.png │ └── romberg.png ├── practice-quad-doc.pdf └── practice-quad-doc.tex ├── problem └── practice-quad.pdf └── src └── quadrature ├── main.m ├── myCompositeGaussLegendre.m ├── myGaussLegendre.m └── myRomberg.m /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.lof 4 | *.log 5 | *.lot 6 | *.fls 7 | *.out 8 | *.toc 9 | *.fmt 10 | *.fot 11 | *.cb 12 | *.cb2 13 | .*.lb 14 | 15 | ## Intermediate documents: 16 | *.dvi 17 | *.xdv 18 | *-converted-to.* 19 | # these rules might exclude image files for figures etc. 20 | # *.ps 21 | # *.eps 22 | # *.pdf 23 | 24 | ## Generated if empty string is given at "Please type another file name for output:" 25 | .pdf 26 | 27 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 28 | *.bbl 29 | *.bcf 30 | *.blg 31 | *-blx.aux 32 | *-blx.bib 33 | *.run.xml 34 | 35 | ## Build tool auxiliary files: 36 | *.fdb_latexmk 37 | *.synctex 38 | *.synctex(busy) 39 | *.synctex.gz 40 | *.synctex.gz(busy) 41 | *.pdfsync 42 | 43 | ## Build tool directories for auxiliary files 44 | # latexrun 45 | latex.out/ 46 | 47 | ## Auxiliary and intermediate files from other packages: 48 | # algorithms 49 | *.alg 50 | *.loa 51 | 52 | # achemso 53 | acs-*.bib 54 | 55 | # amsthm 56 | *.thm 57 | 58 | # beamer 59 | *.nav 60 | *.pre 61 | *.snm 62 | *.vrb 63 | 64 | # changes 65 | *.soc 66 | 67 | # comment 68 | *.cut 69 | 70 | # cprotect 71 | *.cpt 72 | 73 | # elsarticle (documentclass of Elsevier journals) 74 | *.spl 75 | 76 | # endnotes 77 | *.ent 78 | 79 | # fixme 80 | *.lox 81 | 82 | # feynmf/feynmp 83 | *.mf 84 | *.mp 85 | *.t[1-9] 86 | *.t[1-9][0-9] 87 | *.tfm 88 | 89 | #(r)(e)ledmac/(r)(e)ledpar 90 | *.end 91 | *.?end 92 | *.[1-9] 93 | *.[1-9][0-9] 94 | *.[1-9][0-9][0-9] 95 | *.[1-9]R 96 | *.[1-9][0-9]R 97 | *.[1-9][0-9][0-9]R 98 | *.eledsec[1-9] 99 | *.eledsec[1-9]R 100 | *.eledsec[1-9][0-9] 101 | *.eledsec[1-9][0-9]R 102 | *.eledsec[1-9][0-9][0-9] 103 | *.eledsec[1-9][0-9][0-9]R 104 | 105 | # glossaries 106 | *.acn 107 | *.acr 108 | *.glg 109 | *.glo 110 | *.gls 111 | *.glsdefs 112 | 113 | # gnuplottex 114 | *-gnuplottex-* 115 | 116 | # gregoriotex 117 | *.gaux 118 | *.gtex 119 | 120 | # htlatex 121 | *.4ct 122 | *.4tc 123 | *.idv 124 | *.lg 125 | *.trc 126 | *.xref 127 | 128 | # hyperref 129 | *.brf 130 | 131 | # knitr 132 | *-concordance.tex 133 | # TODO Comment the next line if you want to keep your tikz graphics files 134 | *.tikz 135 | *-tikzDictionary 136 | 137 | # listings 138 | *.lol 139 | 140 | # luatexja-ruby 141 | *.ltjruby 142 | 143 | # makeidx 144 | *.idx 145 | *.ilg 146 | *.ind 147 | 148 | # minitoc 149 | *.maf 150 | *.mlf 151 | *.mlt 152 | *.mtc[0-9]* 153 | *.slf[0-9]* 154 | *.slt[0-9]* 155 | *.stc[0-9]* 156 | 157 | # minted 158 | _minted* 159 | *.pyg 160 | 161 | # morewrites 162 | *.mw 163 | 164 | # nomencl 165 | *.nlg 166 | *.nlo 167 | *.nls 168 | 169 | # pax 170 | *.pax 171 | 172 | # pdfpcnotes 173 | *.pdfpc 174 | 175 | # sagetex 176 | *.sagetex.sage 177 | *.sagetex.py 178 | *.sagetex.scmd 179 | 180 | # scrwfile 181 | *.wrt 182 | 183 | # sympy 184 | *.sout 185 | *.sympy 186 | sympy-plots-for-*.tex/ 187 | 188 | # pdfcomment 189 | *.upa 190 | *.upb 191 | 192 | # pythontex 193 | *.pytxcode 194 | pythontex-files-*/ 195 | 196 | # tcolorbox 197 | *.listing 198 | 199 | # thmtools 200 | *.loe 201 | 202 | # TikZ & PGF 203 | *.dpth 204 | *.md5 205 | *.auxlock 206 | 207 | # todonotes 208 | *.tdo 209 | 210 | # vhistory 211 | *.hst 212 | *.ver 213 | 214 | # easy-todo 215 | *.lod 216 | 217 | # xcolor 218 | *.xcp 219 | 220 | # xmpincl 221 | *.xmpi 222 | 223 | # xindy 224 | *.xdy 225 | 226 | # xypic precompiled matrices 227 | *.xyc 228 | 229 | # endfloat 230 | *.ttt 231 | *.fff 232 | 233 | # Latexian 234 | TSWLatexianTemp* 235 | 236 | ## Editors: 237 | # WinEdt 238 | *.bak 239 | *.sav 240 | 241 | # Texpad 242 | .texpadtmp 243 | 244 | # LyX 245 | *.lyx~ 246 | 247 | # Kile 248 | *.backup 249 | 250 | # KBibTeX 251 | *~[0-9]* 252 | 253 | # auto folder when using emacs and auctex 254 | ./auto/* 255 | *.el 256 | 257 | # expex forward references with \gathertags 258 | *-tags.tex 259 | 260 | # standalone packages 261 | *.sta 262 | 263 | .DS_Store 264 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Numerical Analysis Practice 2 | 3 | 这是数值分析课程的上机作业,使用 Matlab 实现,并将算法原理和算法结果以作业文档的形式呈现。 4 | 5 | 配套教材为《数值分析基础》,各章对应练习内容如下: 6 | 7 | - [第二章 线性代数方程组的直接解法 & 第三章 线性代数方程组的迭代解法](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-ls) 8 | - 直接解法:Gauss 消元法、Cholesky 分解方法、Tikhonov 正则化方法 9 | - 迭代解法:共轭梯度法、GMRES 方法 10 | - [第四章 非线性方程组的数值解法](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-nls) 11 | - 不动点迭代法、Steffensen 迭代法和 Newton 迭代法 12 | - [第五章 矩阵特征值问题的数值方法](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-eig) 13 | - 经典 Jacobi 方法、Jacobi 过关法、QR 算法 14 | - [第六章 插值法](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-interp) 15 | - Lagrange 插值、分段线性插值、三次自然样条插值 16 | - [第七章 函数逼近](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-app) 17 | - 最佳平方逼近:Legendre 多项式 18 | - 近似最佳一致逼近:截断 Tchebychev 级数、插值余项极小化方法 19 | - [第八章 数值微分与数值积分](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-quad) 20 | - 五点 Gauss-Legendre 求积公式的复合求积公式、Romberg 求积方法 21 | - [第九章 常微分方程初值问题的数值解法](https://github.com/Manchery/numerical-analysis-practice/tree/master/practice-ode) 22 | - 古典四级四阶 Runge-Kutta 方法、隐式二级四阶 Runge-Kutta 方法(Gauss 方法) 23 | 24 | 详见各目录下具体习题与作业文档。 25 | 26 | ## 参考 27 | 28 | 关治, & 陆金甫 (Eds.). (2010). 数值分析基础. 高等教育出版社. 29 | -------------------------------------------------------------------------------- /practice-app/doc/img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-app/doc/img/error.png -------------------------------------------------------------------------------- /practice-app/doc/img/plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-app/doc/img/plot.png -------------------------------------------------------------------------------- /practice-app/doc/practice-app-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-app/doc/practice-app-doc.pdf -------------------------------------------------------------------------------- /practice-app/doc/practice-app-doc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | %中文环境设置 4 | \usepackage{xeCJK} 5 | \usepackage{indentfirst} 6 | \setlength{\parindent}{2em} 7 | \usepackage{enumitem} 8 | 9 | \usepackage{abstract} 10 | \renewcommand{\abstractname}{摘要} 11 | \providecommand{\keywords}[1]{\textbf{\textit{关键词}} #1} 12 | 13 | \setCJKmainfont{STSong} % 中文主字体设置 14 | 15 | \usepackage[colorlinks,linkcolor=blue, citecolor=blue]{hyperref} 16 | 17 | % 常用宏包 18 | \usepackage{float} 19 | \usepackage{stfloats} 20 | \usepackage{graphicx} 21 | \usepackage{color} 22 | \usepackage{supertabular} 23 | 24 | % 代码环境设置 25 | \usepackage{listings} 26 | \lstset{ 27 | columns=fullflexible, 28 | frame=single, 29 | breaklines=true, 30 | } 31 | \definecolor{lightgray}{gray}{0.9} 32 | \newcommand{\inlinecode}[2]{\colorbox{lightgray}{\lstinline[language=#1]$#2$}} 33 | 34 | % 页面段落设置 35 | \usepackage{multicol} 36 | \usepackage{geometry} 37 | \geometry{left=3.18cm, right=3.18cm, top=2.54cm, bottom=2.54cm} 38 | \linespread{1.3} 39 | %\setlength{\parskip}{0.5em} 40 | 41 | % 数学环境设置 42 | \usepackage{amsmath} 43 | \usepackage{amssymb} 44 | \usepackage{amsthm} 45 | \usepackage{amsfonts} 46 | \newtheorem{myDef}{Definition} 47 | \newtheorem{myThm}{Theorem} 48 | \newtheorem{myProp}{Property} 49 | 50 | \begin{document} 51 | \title{函数逼近与数据拟合\ 上机习题} 52 | \author{吴佳龙 2018013418} 53 | \date{} 54 | \maketitle 55 | 56 | \begin{abstract} 57 | 结合理论分析和编程计算,运用不同方法求解了一函数的最佳平方逼近和近似最佳一致逼近。求解最佳平方逼近利用了Legendre 多项式,求解近似最佳一致逼近的两种方法分别为截断 Tchebychev 级数和插值余项极小化。 58 | \end{abstract} 59 | 60 | %\keywords{one, two, three, four} 61 | 62 | \begin{multicols}{2} 63 | 64 | \begin{section}{问题} 65 | 66 | 设 $$f(x)=x^{2} \ln (2+x), x \in[-1,1]$$ 67 | 68 | 试求出权函数 $\rho(x)=1$ 的最佳平方逼近三次多项式。另外用 Tchebychev 截断级数的方法和插值余项极小化的方法分别给出近似最佳一致逼近三次多项式,并画图比较。 69 | 70 | \end{section} 71 | 72 | \begin{section}{最佳平方逼近} 73 | 74 | \begin{subsection}{算法原理} 75 | 76 | \begin{subsubsection}{法方程} 77 | 78 | 设 $\left\{\varphi_{j}\right\}_{j=0}^{n} \subset L_{\rho}^{2}[a, b]$ 为线性无关函数,将最佳平方逼近函数表示为:$S_{n}^{*}(x)=\sum_{j=0}^{n} a_{j}^{*} \varphi_{j}(x)$,满足 $$\frac{\partial}{\partial a_{k}}(f-S_{n}^{*})=0 \Longrightarrow \sum_{j=0}^{n} a_{j}\left(\varphi_{j}, \varphi_{k}\right)=\left(f, \varphi_{k}\right)$$ 称为关于 $a$ 的法方程。 79 | 80 | 若取 $\varphi$ 为正交多项式,则 Gram 矩阵成为对角阵,法方程易解。 81 | 82 | \end{subsubsection} 83 | 84 | \begin{subsubsection}{Legendre 多项式} 85 | 86 | Legendre 多项式 $$P_{n}(x)=\frac{1}{n ! 2^{n}} \frac{d^{n}}{d x^{n}}\left[\left(x^{2}-1\right)^{n}\right]$$ 是在区间 $[-1,1]$ 对应权函数 $\varphi(x) = 1$ 的正交多项式,满足: 87 | 88 | \begin{itemize} 89 | \item $\left(P_{n}, P_{m}\right) =\left\{\begin{array}{ll}{0,} & {n \neq m} \\ {\frac{2}{2 n+1},} & {n=m}\end{array}\right.$ 90 | \item $(n+1) P_{n+1}(x)=(2 n+1) x P_{n}(x)-n P_{n-1}(x),\ n=0,1, \cdots $ 91 | \end{itemize} 92 | 93 | 由正交性和法方程,得 $ \alpha_{k}^{*}=\frac{\left(f, \varphi_{k}\right)}{\left(\varphi_{k}, \varphi_{k}\right)} $。具体地,将 Legendre 多项式归一化 $$\varphi_{n}(x)=\frac{1}{n ! 2^{n}} \sqrt{\frac{2 n+1}{2}} \frac{d^{n}}{d x^{n}}\left(x^{2}-1\right)^{n} $$ 得最佳平方逼近为 $$S_{n}^{*}(x)=\sum_{j=0}^{n} \alpha_{j}^{*} \varphi_{j}(x), \ \alpha_{j}^{*}=\int_{-1}^{1} f(x) \varphi_{j}(x) d x $$ 94 | 95 | \end{subsubsection} 96 | 97 | \begin{subsubsection}{误差} 98 | 99 | 误差 $\delta_{n}=f-S_{n}^{*}$ 满足 $$\left(f, S_{n}^{*}\right)=\left(S_{n}^{*}, S_{n}^{*}\right) \Longrightarrow\left\|\delta_{n}\right\|_{2}^{2}=(f, f)-\left(S_{n}^{*}, S_{n}^{*}\right)$$ 100 | 101 | \end{subsubsection} 102 | 103 | \end{subsection} 104 | 105 | \begin{subsection}{算法实现} 106 | 107 | 用 Legendre 多项式求最佳平方逼近的 MATLAB 实现如下: 108 | 109 | \begin{lstlisting}[language=Matlab] 110 | function coeff = myLegendreSquareApprox(f) 111 | % 用Legendre多项式求最佳平方三次逼近 112 | % 返回值 coeff 为 (1,4) 的向量,分别表示从常数项到三次项的系数 113 | 114 | % 归一化的 Legendre 多项式 115 | P0 = @(x)(sqrt(1/2)); 116 | P1 = @(x)(sqrt(3/2).*x); 117 | P2 = @(x)(sqrt(5/8)*3.*(x.^2-1/3)); 118 | P3 = @(x)(sqrt(7/8).*x.*(5*x.^2-3)); 119 | 120 | a0 = integral(@(x)(f(x).*P0(x)),-1,1); 121 | a1 = integral(@(x)(f(x).*P1(x)),-1,1); 122 | a2 = integral(@(x)(f(x).*P2(x)),-1,1); 123 | a3 = integral(@(x)(f(x).*P3(x)),-1,1); 124 | 125 | coeff = [sqrt(1/2)*a0-sqrt(5/8)*a2, sqrt(3/2)*a1-3*sqrt(7/8)*a3, 3*sqrt(5/8)*a2, 5*sqrt(7/8)*a3]; 126 | end 127 | 128 | 129 | \end{lstlisting} 130 | 131 | \end{subsection} 132 | 133 | \begin{subsection}{计算结果} 134 | 135 | 计算得最佳平方逼近: 136 | 137 | \begin{equation} \nonumber 138 | \begin{aligned} S_3^{leg}(x)&=0.554258x^3+0.572954x^2\\ &-0.012249x+0.012489 \end{aligned} 139 | \end{equation} 140 | 141 | 并得到 $$\left\|f-S_3^{leg}\right\|_2 = 0.016549$$ $$\left\|f-S_3^{leg}\right\|_{\infty} = 0.043434$$ 142 | \end{subsection} 143 | 144 | \end{section} 145 | 146 | \begin{section}{近似最佳一致逼近:截断 Tchebychev 级数近似} 147 | 148 | \begin{subsection}{算法原理} 149 | 150 | \begin{subsubsection}{Tchebychev 多项式} 151 | 152 | Tchebychev 多项式 $$T_{n}(x)=\cos (n \arccos x)$$ 是在 $[-1,1]$ 上对应权函数 $\rho(x)=\frac{1}{\sqrt{1-x^{2}}}$ 的正交多项式,满足: 153 | 154 | \begin{itemize} 155 | \item $\left(T_{n}, T_{m}\right)=\left\{\begin{array}{ll}{0,} & {n \neq m} \\ {\frac{\pi}{2},} & {n=m \neq 0} \\ {\pi,} & {n=m=0}\end{array}\right.$ 156 | \item $T_{n+1}=2 x T_{n}-T_{n-1}$ 157 | \item 在 $(-1,1)$ 上有 $n$ 个不同的零点 $x_{k}=\cos \frac{2 k-1}{2 n} \pi, k=1, \cdots, n$ 158 | \item 在 $(-1,1)$ 上有 $n+1$ 个极值点 $x_{k}^{*}=\cos \frac{k}{n} \pi, k=0, \cdots, n$ 159 | \end{itemize} 160 | 161 | \end{subsubsection} 162 | 163 | \begin{subsubsection}{截断 Tchebychev 级数} 164 | 165 | $f$ 对应 Tchebychev 多项式展开的广义 Fourier 级数(Tchebychev 级数)为 $$f \sim \frac{c_{0}}{2}+\sum_{k=1}^{+\infty} c_{k} T_{k}(x), \ c_{k}=\frac{2}{\pi} \int_{-1}^{1} \frac{f(x) T_{k}(x)}{\sqrt{1-x^{2}}} d x$$ 166 | 167 | 取前 $n+1$ 项部分和 $$S_{n}^{*}(x)=\frac{c_{0}}{2}+\sum_{k=1}^{n} c_{k} T_{k}(x)$$ 对于 $f \in C^{(r)}[-1,1](r \geq 2)$ 计算可得 $$f(x)-S_{n}^{*}(x)=c_{n+1} T_{n+1}(x)+\mathcal{O}\left(\frac{1}{(n+1)^{r-1}}\right)$$ 168 | 169 | 而 $T_{n+1}(x)$ 恰有 $n+2$ 个轮流为 $\pm 1$ 的极值点,根据 Tchebychev 定理,$S_{n}^{*}$ 可以作为 $f$ 的近似最佳一致逼近多项式。 170 | 171 | \end{subsubsection} 172 | 173 | \end{subsection} 174 | 175 | \begin{subsection}{算法实现} 176 | 177 | 用截断 Tchebychev 级数的方法近似最佳一致逼近多项式的 MATLAB 实现如下: 178 | 179 | \begin{lstlisting}[language=Matlab] 180 | function coeff = myTchebychevUniformApprox(f) 181 | % 截断 Tchebychev 级数近似最佳一致三次逼近 182 | % 返回值 coeff 为 (1,4) 的向量,分别表示从常数项到三次项的系数 183 | 184 | % Tchebychev 多项式 185 | T0 = @(x)(1); 186 | T1 = @(x)(x); 187 | T2 = @(x)(2*x.^2-1); 188 | T3 = @(x)(4*x.^3-3.*x); 189 | 190 | c0 = 2/pi*integral(@(x)(f(x).*T0(x)./sqrt(1-x.^2)),-1,1); 191 | c1 = 2/pi*integral(@(x)(f(x).*T1(x)./sqrt(1-x.^2)),-1,1); 192 | c2 = 2/pi*integral(@(x)(f(x).*T2(x)./sqrt(1-x.^2)),-1,1); 193 | c3 = 2/pi*integral(@(x)(f(x).*T3(x)./sqrt(1-x.^2)),-1,1); 194 | 195 | coeff = [c0/2 - c2, c1-3*c3, 2*c2, 4*c3]; 196 | end 197 | \end{lstlisting} 198 | 199 | \end{subsection} 200 | 201 | \begin{subsection}{计算结果} 202 | 203 | 计算得近似最佳一致逼近: 204 | 205 | \begin{equation} \nonumber 206 | \begin{aligned} S_3^{tche}(x)&=0.562101x^3+0.550725x^2\\&-0.016446x+0.018594 \end{aligned} 207 | \end{equation} 208 | 209 | 并得到偏差 $$\left\|f-S_3^{tche}\right\|_{\infty} = 0.023663$$ 210 | 211 | \end{subsection} 212 | 213 | \end{section} 214 | 215 | 216 | \begin{section}{近似最佳一致逼近:Lagrange 插值余项极小化} 217 | 218 | \begin{subsection}{算法原理} 219 | 220 | 在 $x_{1}, \cdots, x_{n}$ 上插值,由插值余项公式:$$\left\|R_{n-1}\right\|_{\infty} \leq \frac{M_{n}}{n !}\left\|\omega_{n}\right\|_{\infty}, \ M_{n}=\left\|f^{(n)}\right\|_{\infty}$$ 221 | 222 | 由于 $2^{1-n} T_{n}(x)$ 是 $[-1,1]$ 上模最小的首一多项式,极小化 $\left\|\omega_{n} \right\|_{\infty}$,也就是令 $\omega_{n}(x)=2^{1-n} T_{n}(x)$,也就是取 $$x_{k}=\cos \frac{2 k-1}{2 n} \pi$$ 为插值节点。 223 | 224 | 这样有 $$\left\|R_{n-1}\right\|_{\infty} \leq \frac{M_{n}}{n !2^{n-1}}$$ 且余项近似有轮流为正负的偏差点,可看做 $f$ 的近似最佳一致逼近。 225 | 226 | \end{subsection} 227 | 228 | \begin{subsection}{算法实现} 229 | 230 | 用Lagrange 插值余项极小化的方法近似最佳一致逼近多项式的 MATLAB 实现如下: 231 | 232 | \begin{lstlisting}[language=Matlab] 233 | function coeff = myLagrangeUniformApprox(f) 234 | % 插值余项极小化 近似最佳一致三次逼近 235 | % 返回值 coeff 为 (1,4) 的向量,分别表示从常数项到三次项的系数 236 | 237 | n = 4; 238 | % Tchebychev 多项式零点 239 | x = cos((2*(1:n)-1)/2/n*pi); 240 | coeff = myLagrangeInterp(x, f(x)); 241 | end 242 | \end{lstlisting} 243 | 244 | Lagrange 插值的实现可参见插值法的实验报告。 245 | 246 | \end{subsection} 247 | 248 | \begin{subsection}{计算结果} 249 | 250 | 计算得近似最佳一致逼近: 251 | 252 | \begin{equation} \nonumber 253 | \begin{aligned} S_3^{lag}(x)&=0.548141x^3+0.552144x^2\\&-0.006136x+0.017918 \end{aligned} 254 | \end{equation} 255 | 256 | 并得到偏差 $$\left\|f-S_3^{lag}\right\|_{\infty} = 0.028058$$ 257 | 258 | \end{subsection} 259 | 260 | \end{section} 261 | 262 | \begin{section}{方法比较} 263 | 264 | \begin{subsection}{图像} 265 | 266 | 将 $f,\ S_3^{leg}(x),\ S_3^{tche}(x),\ S_3^{lag}(x)$ 的图像作出,如图 \ref{plot} 所示。 267 | 268 | 可以看到,三种方法的得到的逼近多项式都与原函数十分接近。 269 | 270 | \begin{figure*}[ht] %h默认参数是可以浮动,不是固定在当前位置。如果要不浮动,你就可以使用大写float宏包的H参数,固定图片在当前位置,禁止浮动。 271 | \centering %使图片居中显示 272 | \includegraphics[width = 0.9\textwidth]{img/plot.png} 273 | \caption{图像} 274 | \label{plot} 275 | \end{figure*} 276 | 277 | \end{subsection} 278 | 279 | \begin{subsection}{误差} 280 | 281 | 将 $S_3^{leg}(x),\ S_3^{tche}(x),\ S_3^{lag}(x)$ 的误差作出,如图 \ref{error} 所示。 282 | 283 | \begin{table}[H] 284 | \begin{tabular}{c|c|c|c} 285 | \hline 286 | & $S_3^{leg}(x)$ & $S_3^{tche}(x)$ & $S_3^{lag}(x)$ \\ \hline 287 | $\left\|f-S_3\right\|_2$ & 0.043434 & 0.023663 & 0.028058 288 | \end{tabular} 289 | \caption{偏差} 290 | \end{table} 291 | 292 | \begin{figure*}[ht] %h默认参数是可以浮动,不是固定在当前位置。如果要不浮动,你就可以使用大写float宏包的H参数,固定图片在当前位置,禁止浮动。 293 | \centering %使图片居中显示 294 | \includegraphics[width = 0.9\textwidth]{img/error.png} 295 | \caption{误差} 296 | \label{error} 297 | \end{figure*} 298 | 299 | 可以看到,近似最佳一致逼近 $S_3^{tche}(x),\ S_3^{lag}(x)$ 都有五个近似的偏差点,偏差比 $S_3^{leg}(x)$ 较小。 300 | 301 | \end{subsection} 302 | 303 | 304 | \end{section} 305 | 306 | \begin{section}{总结} 307 | 308 | 本次实验对于求解最佳平方逼近和近似最佳一致逼近的方法进行了理论分析和编程计算,作出图像并比较 了它们的结果。 309 | 310 | 计算结果符合预期,观察到近似最佳一致逼近的五个近似的偏差点,加深了对正交多项式以及 Tchebychev 定理等的理解。 311 | 312 | \end{section} 313 | 314 | \end{multicols} 315 | 316 | %\bibliographystyle{unsrt} 317 | %\bibliography{ref.bib} 318 | 319 | %\begin{thebibliography}{99} %参考文献开始 320 | % \bibitem{ml}周志华. 机器学习[M]. 清华大学出版社, 2016. 321 | %\end{thebibliography} 322 | 323 | \end{document} 324 | 325 | -------------------------------------------------------------------------------- /practice-app/problem/practice-app.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-app/problem/practice-app.pdf -------------------------------------------------------------------------------- /practice-app/src/approx/main.m: -------------------------------------------------------------------------------- 1 | hold on; 2 | 3 | density = 100; 4 | sx = (0:density)*2/density-1; 5 | sy = f(sx); 6 | plot(sx,sy); 7 | 8 | coeff_leg = myLegendreSquareApprox(@f); 9 | fprintf("Legendre: %fx^3+%fx^2+%fx+%f\n", coeff_leg(4), coeff_leg(3), coeff_leg(2), coeff_leg(1)); 10 | [sx, sy] = sampleFunction([-1,1], coeff_leg, density); 11 | plot(sx,sy); 12 | % plot(sx,f(sx)-sy); 13 | fprintf("Legendre error: %f\n", compute_error(sx,sy)) 14 | fprintf("Legendre l2 error: %f\n", compute_l2_error(@f, @(x)(coeff_leg(1)+coeff_leg(2).*x+coeff_leg(3).*x.^2+coeff_leg(4).*x.^3), @(x)(1))); 15 | 16 | coeff_tche = myTchebychevUniformApprox(@f); 17 | fprintf("Tchebychev: %fx^3+%fx^2+%fx+%f\n", coeff_tche(4), coeff_tche(3), coeff_tche(2), coeff_tche(1)); 18 | [sx, sy] = sampleFunction([-1,1], coeff_tche, density); 19 | plot(sx,sy); 20 | % plot(sx,f(sx)-sy); 21 | fprintf("Tchebychev error: %f\n", compute_error(sx,sy)) 22 | 23 | coeff_lag = myLagrangeUniformApprox(@f); 24 | fprintf("Lagrange: %fx^3+%fx^2+%fx+%f\n", coeff_lag(4), coeff_lag(3), coeff_lag(2), coeff_lag(1)); 25 | [sx, sy] = sampleFunction([-1,1], coeff_lag, density); 26 | plot(sx,sy); 27 | % plot(sx,f(sx)-sy); 28 | fprintf("Lagrange error: %f\n", compute_error(sx,sy)) 29 | 30 | lgd = legend('f','Legendre', 'Tchebychev', 'Lagrange'); 31 | lgd.Location = 'northwest'; 32 | 33 | % lgd = legend('Legendre', 'Tchebychev', 'Lagrange'); 34 | % lgd.Location = 'south'; 35 | 36 | function y=f(x) 37 | y = (x.^2).*log(2+x); 38 | end 39 | 40 | function d = compute_error(sx, sy) 41 | y = f(sx); 42 | d = max(abs(y-sy)); 43 | end 44 | 45 | function d = compute_l2_error(f,g,rho) 46 | d = integral(@(x)(rho(x).*(f(x)-g(x)).^2), -1, 1)^0.5; 47 | end 48 | 49 | -------------------------------------------------------------------------------- /practice-app/src/approx/myLagrangeInterp.m: -------------------------------------------------------------------------------- 1 | function coeff = myLagrangeInterp(x,y) 2 | % lagrange 插值法 3 | % 返回格式:coeff 为 (1,n+1) 大小的向量,分别表示从常数项到最高次项的系数 4 | 5 | [~,n] = size(x); 6 | n = n-1; 7 | 8 | coeff = zeros(1,n+1); 9 | 10 | l = zeros(n+1,n+1); % 基函数 11 | 12 | for i = 1:n+1 13 | l(i,1) = 1; prod = 1; 14 | for j = 1:n+1 15 | if (i==j) 16 | continue 17 | end 18 | l(i,:) = [0, l(i, 1:end-1)] - x(j)*l(i,:); 19 | prod = prod*(x(i)-x(j)); 20 | end 21 | coeff = coeff + y(i)*l(i,:)/prod; 22 | end 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /practice-app/src/approx/myLagrangeUniformApprox.m: -------------------------------------------------------------------------------- 1 | function coeff = myLagrangeUniformApprox(f) 2 | % 插值余项极小化 近似最佳一致三次逼近 3 | % 返回值 coeff 为 (1,4) 的向量,分别表示从常数项到三次项的系数 4 | 5 | n = 4; 6 | % Tchebychev 多项式零点 7 | x = cos((2*(1:n)-1)/2/n*pi); 8 | coeff = myLagrangeInterp(x, f(x)); 9 | 10 | end 11 | 12 | -------------------------------------------------------------------------------- /practice-app/src/approx/myLegendreSquareApprox.m: -------------------------------------------------------------------------------- 1 | function coeff = myLegendreSquareApprox(f) 2 | % 用Legendre多项式求最佳平方三次逼近 3 | % 返回值 coeff 为 (1,4) 的向量,分别表示从常数项到三次项的系数 4 | 5 | % 归一化的 Legendre 多项式 6 | P0 = @(x)(sqrt(1/2)); 7 | P1 = @(x)(sqrt(3/2).*x); 8 | P2 = @(x)(sqrt(5/8)*3.*(x.^2-1/3)); 9 | P3 = @(x)(sqrt(7/8).*x.*(5*x.^2-3)); 10 | 11 | a0 = integral(@(x)(f(x).*P0(x)),-1,1); 12 | a1 = integral(@(x)(f(x).*P1(x)),-1,1); 13 | a2 = integral(@(x)(f(x).*P2(x)),-1,1); 14 | a3 = integral(@(x)(f(x).*P3(x)),-1,1); 15 | 16 | coeff = [sqrt(1/2)*a0-sqrt(5/8)*a2, sqrt(3/2)*a1-3*sqrt(7/8)*a3, 3*sqrt(5/8)*a2, 5*sqrt(7/8)*a3]; 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /practice-app/src/approx/myTchebychevUniformApprox.m: -------------------------------------------------------------------------------- 1 | function coeff = myTchebychevUniformApprox(f) 2 | % 截断 Tchebychev 级数近似最佳一致三次逼近 3 | % 返回值 coeff 为 (1,4) 的向量,分别表示从常数项到三次项的系数 4 | 5 | % Tchebychev 多项式 6 | T0 = @(x)(1); 7 | T1 = @(x)(x); 8 | T2 = @(x)(2*x.^2-1); 9 | T3 = @(x)(4*x.^3-3.*x); 10 | 11 | c0 = 2/pi*integral(@(x)(f(x).*T0(x)./sqrt(1-x.^2)),-1,1); 12 | c1 = 2/pi*integral(@(x)(f(x).*T1(x)./sqrt(1-x.^2)),-1,1); 13 | c2 = 2/pi*integral(@(x)(f(x).*T2(x)./sqrt(1-x.^2)),-1,1); 14 | c3 = 2/pi*integral(@(x)(f(x).*T3(x)./sqrt(1-x.^2)),-1,1); 15 | 16 | coeff = [c0/2 - c2, c1-3*c3, 2*c2, 4*c3]; 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /practice-app/src/approx/sampleFunction.m: -------------------------------------------------------------------------------- 1 | function [sx, sy] = sampleFunction(x, coeff, density) 2 | 3 | [~,n] = size(x); 4 | n=n-1; 5 | 6 | [~,m] = size(coeff); 7 | 8 | sx = []; 9 | sy = []; 10 | 11 | for i = 1:n 12 | for j = 0:density 13 | cur_x = x(i)+(x(i+1)-x(i))/density*j; 14 | cur_y = 0; 15 | for k = 1:m 16 | cur_y = cur_y*cur_x+coeff(i,m-k+1); 17 | end 18 | sx = [sx cur_x]; 19 | sy = [sy cur_y]; 20 | end 21 | end 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /practice-eig/doc/img/compare_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-eig/doc/img/compare_time.png -------------------------------------------------------------------------------- /practice-eig/doc/practice-eig-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-eig/doc/practice-eig-doc.pdf -------------------------------------------------------------------------------- /practice-eig/doc/practice-eig-doc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | %中文环境设置 4 | \usepackage{xeCJK} 5 | \usepackage{indentfirst} 6 | \setlength{\parindent}{2em} 7 | \usepackage{enumitem} 8 | 9 | \usepackage{abstract} 10 | \renewcommand{\abstractname}{摘要} 11 | \providecommand{\keywords}[1]{\textbf{\textit{关键词}} #1} 12 | 13 | \setCJKmainfont{STSong} % 中文主字体设置 14 | 15 | \usepackage[colorlinks,linkcolor=blue, citecolor=blue]{hyperref} 16 | 17 | % 常用宏包 18 | \usepackage{float} 19 | \usepackage{stfloats} 20 | \usepackage{graphicx} 21 | \usepackage{color} 22 | \usepackage{supertabular} 23 | 24 | % 代码环境设置 25 | \usepackage{listings} 26 | \lstset{ 27 | columns=fullflexible, 28 | frame=single, 29 | breaklines=true, 30 | } 31 | \definecolor{lightgray}{gray}{0.9} 32 | \newcommand{\inlinecode}[2]{\colorbox{lightgray}{\lstinline[language=#1]$#2$}} 33 | 34 | % 页面段落设置 35 | \usepackage{multicol} 36 | \usepackage{geometry} 37 | \geometry{left=3.18cm, right=3.18cm, top=2.54cm, bottom=2.54cm} 38 | \linespread{1.3} 39 | %\setlength{\parskip}{0.5em} 40 | 41 | % 数学环境设置 42 | \usepackage{amsmath} 43 | \usepackage{amsthm} 44 | \usepackage{amsfonts} 45 | \newtheorem{myDef}{Definition} 46 | \newtheorem{myThm}{Theorem} 47 | \newtheorem{myProp}{Property} 48 | 49 | \begin{document} 50 | \title{矩阵特征值问题实验题} 51 | \author{吴佳龙 2018013418} 52 | \date{} 53 | \maketitle 54 | 55 | \begin{abstract} 56 | 结合理论分析和编程计算,运用不同算法求解矩阵特征值和特征向量的数值解。运用的算法分别为经典Jacobi方法、Jacobi过关法、QR算法。 57 | \end{abstract} 58 | 59 | %\keywords{one, two, three, four} 60 | 61 | \begin{multicols}{2} 62 | 63 | \begin{section}{问题} 64 | 65 | 计算以下三对角矩阵的特征值,要求达到三位有效数字。 66 | $$A=\left(\begin{array}{ccccc}{2} & {-1} & {} & {} & {} \\ {-1} & {2} & {-1} & {} & {} \\ {} & {\ddots} & {\ddots} & {\ddots} & {} \\ {} & {} & {-1} & {2} & {-1} \\ {} & {} & {} & {-1} & {2}\end{array}\right)$$ 67 | 68 | \end{section} 69 | 70 | \begin{section}{Jacobi方法} 71 | 72 | \begin{subsection}{算法原理} 73 | 74 | 对于实对称阵 $A$,记 $N(A)=\sum_{i \neq j}\left|a_{i j}\right|^{2}$,通过一系列 Givens 变换 $J(k,l;\theta)$,使 $N(A)$ 下降,最终收敛于对角阵,从而得到其所有特征值。 75 | 76 | 其中,Givens 变换的参数 $k,l,\theta$ 的确定:令 $B = J^{-1}AJ$,则有 $$N(B) = N(A)+2\left|b_{k l}\right|^{2}-2\left|a_{k l}\right|^{2}$$,使得 $N(B)$ 尽量小,选取 $a_{kl}$ 为 $A$ 中非对角的绝对值最大的元素,并令 $b_{k l}=a_{k l} \cos 2 \theta+\frac{1}{2}\left(a_{l l}-a_{k k}\right) \sin 2 \theta=0$,解得 $$ 77 | \{\begin{array}{l} { \text{if } a_{k k} \neq a_{l l} , \quad \tan {2\theta} = {2 a_{k l}\over a_{k k}-a_{l l}} } \\ {\text{if } a_{k k}=a_{l l} , \quad \cos 2 \theta=0 \Longrightarrow \theta={ \pi \over 4} } \end{array}$$ 78 | 79 | \end{subsection} 80 | 81 | \begin{subsection}{算法描述} 82 | 83 | \begin{subsubsection}{经典Jacobi方法} 84 | 经典 Jacobi 方法的算法描述如下: 85 | 86 | 记 $A^{(1)} = A$,选取 $\varepsilon$,对 $m=1,2,\dots$ 87 | 88 | \begin{enumerate} 89 | \item 选取绝对值最大元素 $\left|a_{k l}^{(m)}\right|=\max _{i \neq j}\left|a_{i j}^{(m)}\right|$ 90 | \item 若 $\left|a_{k l}^{(m)}\right|<\varepsilon $,则结束迭代;否则 91 | \item 确定 $J(k,l,\theta)$,做变换 $A^{(m+1)}=J A^{(m)} J^{-1}$ 92 | \end{enumerate} 93 | \end{subsubsection} 94 | 95 | \begin{subsubsection}{Jacobi过关法} 96 | 97 | 在扫描到为了提高扫描的效率,可采用 Jacobi 过关法,算法描述如下: 98 | 99 | 确定一个阈值 $\delta_1 > 0$,例如 $\delta_1 = {\sqrt{N(A)}\over n}$,记 $m=1$ 并选取一个 $\varepsilon > 0$。 100 | 101 | \begin{enumerate} 102 | \item 循环扫描 $A$ 的所有非对角元,只要 $|a_{ij}|>\delta_m (i\neq j)$,就确定 $J(i,j,\theta)$,做相似变换 $JAJ^{-1}$。 103 | \item 直到 $A$ 的所有非对角元的绝对值都不超过 $\delta_m$,令 $\delta_{m+1} = \delta_m / n, m=m+1$ 104 | \item 若 $\delta_m < \varepsilon$ 则退出。 105 | \end{enumerate} 106 | 107 | 108 | 109 | \end{subsubsection} 110 | 111 | \end{subsection} 112 | 113 | \begin{subsection}{收敛性分析} 114 | 115 | 可以证明,在经典 Jacobi 算法中 $$ N(B)=N(A)-2\left|a_{k l}\right|^{2} \leq q \cdot N(A) $$ 其中 $q=1-\frac{2}{n(n-1)} \in[0,1)$。因此,$N\left(A^{(m+1)}\right) \leq q^{m} N(A) \rightarrow 0$,经典 Jacobi算法收敛。 116 | 117 | \end{subsection} 118 | 119 | \begin{subsection}{算法实现} 120 | 121 | 经典 Jacobi 方法的 MATLAB 实现如下: 122 | 123 | \begin{lstlisting}[language=Matlab] 124 | function [lambda, Q] = myJacobiClassic(A, eps) 125 | % 经典Jacobi方法 126 | % eps: 非对角元素绝对值小于eps,则终止 127 | % lambda: 特征值 128 | % Q: 对应特征值的特征向量 129 | % 满足 inv(Q)*A*Q = diag(lambda) 130 | [n,~] = size(A); 131 | Q = eye(n); 132 | while (true) 133 | C = abs(A - diag(diag(A))); 134 | val = max(max(C)); % 非对角元素的最大模 135 | if (valeps) 161 | while (true) 162 | mapped = false; 163 | % 过关扫描 164 | for i = 1:n 165 | for j = i+1:n 166 | if (abs(A(i,j))>delta) 167 | % givens 变换 168 | J = givensForJiacobi(A, i, j); 169 | A = J*A*J'; 170 | Q = Q*J'; 171 | mapped = true; 172 | end 173 | end 174 | end 175 | % 所有元素都绝对值小于阈值 176 | if (~mapped) 177 | break 178 | end 179 | end 180 | delta = delta/n; 181 | end 182 | lambda = diag(A); 183 | end 184 | \end{lstlisting} 185 | 186 | 其中,求解 Givens 变换矩阵的函数实现如下: 187 | 188 | \begin{lstlisting}[language=Matlab] 189 | function [J] = givensForJacobi(A,k_,l_) 190 | % Jacobi方法中的givens变换矩阵 191 | k = min(k_,l_); l = max(k_,l_); 192 | [n,~] = size(A); 193 | if (A(k,k) ~= A(l,l)) 194 | ct2 = (A(k,k)-A(l,l))/2/A(k,l); 195 | t = sign(ct2)/(abs(ct2) + sqrt(1+ct2^2)); 196 | c = 1/sqrt(1+t^2); s = c*t; 197 | else 198 | c = cos(pi/4); s = sin(pi/4); 199 | end 200 | J = eye(n); 201 | J(k,k) = c; J(l,l) = c; 202 | J(k,l) = s; J(l,k) = -s; 203 | end 204 | \end{lstlisting} 205 | 206 | \end{subsection} 207 | 208 | \begin{subsection}{计算结果} 209 | 210 | \begin{subsubsection}{经典 Jacobi 方法} 211 | 212 | 对于不同的 $n$,调用函数 \inlinecode{Matlab}{myJacobiClassic(A, 1e-7)},并观察计算时间和计算结果的精度。 213 | 214 | 其中,当 $n=3$ 时,由 MATLAB 内置 \inlinecode{Matlab}{eig} 函数给出特征值 $$0.585786437626905$$$$2.000000000000000$$$$3.414213562373095$$ 由实现的经典 Jacobi 方法计算得特征值为 $$0.585786437626905$$$$3.414213562373095$$$$2.000000000000000$$ 对应的特征向量构成的矩阵 215 | $$\left( 216 | \begin{matrix} 217 | 0.5000 & -0.5000 & -0.7071 \\ 218 | 0.7071 & 0.7071 & 0.0000 \\ 219 | 0.5000 & -0.5000 & 0.7071 220 | \end{matrix} 221 | \right)$$ 222 | 223 | 计算结果符合实际,且具有较高的精度。 224 | 225 | 选取更多 $n$ 后,给出结果如下: 226 | 227 | \begin{table}[H] 228 | \begin{tabular}{c|c|c} 229 | \hline 230 | & 特征值有效位数 & 计算时间(s) \\ \hline 231 | $n=3$ & 15位 & 0.000358 \\ 232 | $n=5$ & 14位 & 0.000821 \\ 233 | $n=10$ & 13位 & 0.003996 \\ 234 | $n=15$ & 13位 & 0.008564 \\ \hline 235 | \end{tabular} 236 | \end{table} 237 | 238 | \end{subsubsection} 239 | 240 | \begin{subsubsection}{Jacobi 过关法} 241 | 242 | 对于不同的 $n$,调用函数 \inlinecode{Matlab}{myJacobiThreshold(A, 1e-7)},并观察计算时间和计算结果的精度。 243 | 244 | 计算结果基本与经典 Jacobi 方法一致,具体如下: 245 | 246 | \begin{table}[H] 247 | \begin{tabular}{c|c|c} 248 | \hline 249 | & 特征值有效位数 & 计算时间(s) \\ \hline 250 | $n=3$ & 14位 & 0.000244 \\ 251 | $n=5$ & 15位 & 0.000442 \\ 252 | $n=10$ & 13位 & 0.004956 \\ 253 | $n=15$ & 12位 & 0.002785 \\ \hline 254 | \end{tabular} 255 | \end{table} 256 | 257 | \end{subsubsection} 258 | 259 | \end{subsection} 260 | 261 | \end{section} 262 | 263 | 264 | \begin{section}{QR算法} 265 | 266 | \begin{subsection}{算法原理} 267 | 268 | 对于 $\forall A \in \mathbb{C}^{n \times n}$,可对 $A$,进行 QR 分解 $A=QR$。记 $B=RQ$ ,则有 $B = Q^HAQ$ 与 $A$ 相似。 269 | 270 | 由此,QR算法的算法描述如下:令 $A_1 = A$,对 $k=1,2,\dots$ 271 | 272 | \begin{itemize} 273 | \item 分解 $A_k = Q_k R_k$ 274 | \item 令 $A_{k+1} = R_k Q_k, k=k+1$ 275 | \item 若 $A_k$ 的非对角元素绝对值小于阈值,则结束 276 | \end{itemize} 277 | 278 | 对于 QR 算法的收敛性有如下定理: 279 | 280 | \begin{myThm} 281 | 282 | 设 $A \in \mathbb{R}^{n \times n}$,特征值分别为 $|\lambda_1| > \cdots > |\lambda_n| >0$,对应的特征向量为 $x^{(i)}$,记 $X = [x^( 1), \cdots, x^(n)]$ 并设存在LU分解 $X^{-1}=LU$,则 QR 算法产生的 $\left\{A_{k}\right\}_{k=1}^{+\infty}$ 基本收敛到上三角阵 $$\lim _{k \rightarrow+\infty} a_{i i}^{(k)}=\lambda_{i}, i=1, \cdots, n$$ 283 | 284 | \end{myThm} 285 | 286 | \begin{subsubsection}{上 Hessenberg 矩阵} 287 | 288 | 利用 Household 变换或者 Givens 变换都能将矩阵相似变换为上 Hessenberg 矩阵。 289 | 290 | 在 QR 算法中,若先将 $A$ 相似变换到上 Hessenberg 矩阵 $H$,则可以证明在 QR 算法的过程中 $A_k$ 的形式保持为上 Hessenberg 矩阵不变,这可以减少算法的运算量,提高效率。 291 | 292 | \end{subsubsection} 293 | 294 | \end{subsection} 295 | 296 | 297 | \begin{subsection}{算法实现} 298 | 299 | QR算法的 MATLAB 实现如下: 300 | 301 | \begin{lstlisting}[language=Matlab] 302 | function [lambda, X] = myQR(A, eps) 303 | % QR算法求解特征值 304 | % eps: 下对角元素绝对值小于eps,则终止 305 | % lambda: 特征值 306 | % X: 对应特征值的特征向量 307 | % 满足 inv(X)*A*X = diag(lambda) 308 | [n,~] = size(A); 309 | % 为了减少运算量,可将A先转化为上Hessenberg阵 310 | % 在本次作业中 A 已经为该形式 311 | % H = toHessenberg(A); 312 | H = A; 313 | while (max(max( tril( abs( H-diag(diag(H)) )) ))>eps) 314 | [U,R] = QRForHessenberg(H); 315 | H = R*U; 316 | end 317 | lambda = diag(H); 318 | % 特征向量可用反幂法求得 319 | X = zeros(n,n); 320 | for i=1:n 321 | [lambda(i), X(:,i)] = inversePowerMethod(A, lambda(i)+(1e-5*randn()), eps); 322 | end 323 | end 324 | \end{lstlisting} 325 | 326 | 其中,利用 Givens 变换对上 Hessenberg 矩阵进行QR分解的实现如下: 327 | 328 | \begin{lstlisting}[language=Matlab] 329 | function [U, R] = QRForHessenberg(H) 330 | % 上Hessenberg矩阵的QR分解 331 | % 结果满足 H = UR 332 | [n,~] = size(H); 333 | Ut = eye(n); 334 | for i=1:n-1 335 | t = H(i+1,i)/H(i,i); 336 | c = 1/sqrt(1+t^2); 337 | s = t*c; 338 | % givens 变换 339 | H(i,:) = H(i,:)*c + H(i+1,:)*s; 340 | H(i+1,:) = (c+s^2/c)*H(i+1,:) - s/c*H(i,:); 341 | Ut(i,:) = Ut(i,:)*c + Ut(i+1,:)*s; 342 | Ut(i+1,:) = (c+s^2/c)*Ut(i+1,:) - s/c*Ut(i,:); 343 | end 344 | U = Ut'; 345 | R = H; 346 | end 347 | \end{lstlisting} 348 | 349 | 反幂法实现如下: 350 | 351 | \begin{lstlisting}[language=Matlab] 352 | function [lambda, v] = inversePowerMethod(A, q, eps) 353 | % 原点位移的反幂法求解特征值和特征向量 354 | % eps: 相邻两次迭代结果小于eps,则终止 355 | [n,~] = size(A); 356 | A = A-q*eye(n); 357 | v = ones(n, 1); 358 | k=0; 359 | while (true) 360 | k = k+1; 361 | z = A\v; 362 | [~,pos] = max(abs(z)); 363 | m = z(pos); % 最大模元素 364 | v = z/m; 365 | if (k>1 && abs(1/m-1/last_m)1 && abs(1/m-1/last_m)eps) 15 | while (true) 16 | mapped = false; 17 | % 过关扫描 18 | for i = 1:n 19 | for j = i+1:n 20 | if (abs(A(i,j))>delta) 21 | % givens 变换 22 | J = givensForJiacobi(A, i, j); 23 | A = J*A*J'; 24 | Q = Q*J'; 25 | mapped = true; 26 | end 27 | end 28 | end 29 | % 所有元素都绝对值小于阈值 30 | if (~mapped) 31 | break 32 | end 33 | end 34 | delta = delta/n; 35 | end 36 | 37 | lambda = diag(A); 38 | 39 | end 40 | 41 | -------------------------------------------------------------------------------- /practice-eig/src/eigen/myQR.m: -------------------------------------------------------------------------------- 1 | function [lambda, X] = myQR(A, eps) 2 | % QR算法求解特征值 3 | % eps: 下对角元素绝对值小于eps,则终止 4 | % lambda: 特征值 5 | % X: 对应特征值的特征向量 6 | % 满足 inv(X)*A*X = diag(lambda) 7 | 8 | [n,~] = size(A); 9 | 10 | % 为了减少运算量,可将A先转化为上Hessenberg阵 11 | % 在本次作业中 A 已经为该形式 12 | % H = toHessenberg(A); 13 | H = A; 14 | 15 | while (max(max( tril( abs( H-diag(diag(H)) )) ))>eps) 16 | [U,R] = QRForHessenberg(H); 17 | H = R*U; 18 | end 19 | 20 | lambda = diag(H); 21 | 22 | % 特征向量可用反幂法求得 23 | X = zeros(n,n); 24 | for i=1:n 25 | [lambda(i), X(:,i)] = inversePowerMethod(A, lambda(i)+(1e-5*randn()), eps); 26 | end 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /practice-eig/src/eigen/plotTime.m: -------------------------------------------------------------------------------- 1 | % 比较运行时间 2 | 3 | t = 3:100; 4 | 5 | times = zeros(3, length(t)); 6 | 7 | for i=1:length(t) 8 | n = i; 9 | A = diag(ones(1,n)*2) +diag(-ones(1,n-1),-1) +diag(-ones(1,n-1),1); 10 | times(:,i) = getTimes(A); 11 | end 12 | 13 | plot(t,times,'LineWidth',1.5); 14 | xlabel('n'); 15 | ylabel('time (s)'); 16 | lgd = legend('Jacobi classic', 'Jacobi threshold', 'QR'); 17 | lgd.Location = 'northwest'; 18 | 19 | function times = getTimes(A) 20 | tic; 21 | myJacobiClassic(A, 1e-7); 22 | time_jacobi_cls = toc; 23 | 24 | tic; 25 | myJacobiThreshold(A, 1e-7); 26 | time_jacobi_thr = toc; 27 | 28 | tic; 29 | myQR(A, 1e-7); 30 | time_qr = toc; 31 | 32 | times = [ 33 | time_jacobi_cls; 34 | time_jacobi_thr; 35 | time_qr 36 | ]; 37 | end -------------------------------------------------------------------------------- /practice-interp/doc/img/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-interp/doc/img/compare.png -------------------------------------------------------------------------------- /practice-interp/doc/img/runge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-interp/doc/img/runge.png -------------------------------------------------------------------------------- /practice-interp/doc/practice-interp-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-interp/doc/practice-interp-doc.pdf -------------------------------------------------------------------------------- /practice-interp/doc/practice-interp-doc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | %中文环境设置 4 | \usepackage{xeCJK} 5 | \usepackage{indentfirst} 6 | \setlength{\parindent}{2em} 7 | \usepackage{enumitem} 8 | 9 | \usepackage{abstract} 10 | \renewcommand{\abstractname}{摘要} 11 | \providecommand{\keywords}[1]{\textbf{\textit{关键词}} #1} 12 | 13 | \setCJKmainfont{STSong} % 中文主字体设置 14 | 15 | \usepackage[colorlinks,linkcolor=blue, citecolor=blue]{hyperref} 16 | 17 | % 常用宏包 18 | \usepackage{float} 19 | \usepackage{stfloats} 20 | \usepackage{graphicx} 21 | \usepackage{color} 22 | \usepackage{supertabular} 23 | 24 | % 代码环境设置 25 | \usepackage{listings} 26 | \lstset{ 27 | columns=fullflexible, 28 | frame=single, 29 | breaklines=true, 30 | } 31 | \definecolor{lightgray}{gray}{0.9} 32 | \newcommand{\inlinecode}[2]{\colorbox{lightgray}{\lstinline[language=#1]$#2$}} 33 | 34 | % 页面段落设置 35 | \usepackage{multicol} 36 | \usepackage{geometry} 37 | \geometry{left=3.18cm, right=3.18cm, top=2.54cm, bottom=2.54cm} 38 | \linespread{1.3} 39 | %\setlength{\parskip}{0.5em} 40 | 41 | % 数学环境设置 42 | \usepackage{amsmath} 43 | \usepackage{amssymb} 44 | \usepackage{amsthm} 45 | \usepackage{amsfonts} 46 | \newtheorem{myDef}{Definition} 47 | \newtheorem{myThm}{Theorem} 48 | \newtheorem{myProp}{Property} 49 | 50 | \begin{document} 51 | \title{插值法实验题} 52 | \author{吴佳龙 2018013418} 53 | \date{} 54 | \maketitle 55 | 56 | \begin{abstract} 57 | 结合理论分析和编程计算,运用不同算法对一特定函数进行插值,并观察了 Runge 现象。运用的插值方法分别为 Lagrange 插值、分段线性插值、三次自然样条插值。 58 | \end{abstract} 59 | 60 | %\keywords{one, two, three, four} 61 | 62 | \begin{multicols}{2} 63 | 64 | \begin{section}{问题} 65 | 66 | 设 $$f(x)=\frac{1}{1+25 x^{2}}, x \in[-1,1]$$ 取 $x_{j}=-1+\frac{2 j}{n}, j=0,1, \cdots, n$。 67 | 68 | 取适当的 $n$,试求出 $n$ 次 Lagrange 插值多项式 $L_n(x)$、分段线性插值函数 $I_1^h(x)$ 和三次样条插值函数 $S_3^h(x)$ (采用自然边界条件),画出他们的图像,并对结果做一个比较说明。 69 | 70 | \end{section} 71 | 72 | \begin{section}{Lagrange 插值} 73 | 74 | \begin{subsection}{算法原理} 75 | 76 | 取基函数 $$l_{k}(x)=\prod_{i=0, i \neq k}^{n} \frac{x-x_{i}}{x_{k}-x_{i}}, \quad k=0,1, \cdots, n$$ 77 | 78 | 令 $$p_{n}(x)=\sum_{k=0}^{n} y_{k} l_{k}(x)$$ 其中 $y_{k}=f\left(x_{k}\right)$。 79 | 80 | 容易验证 $p_{n}\left(x_{i}\right)=y_{i}=f\left(x_{i}\right)$ 且 $n$ 次插值多项式具有唯一性。 81 | 82 | \begin{subsubsection}{误差估计} 83 | 84 | \begin{myThm} 85 | 86 | 记步长 $ h=\max _{1 \leq j \leq n}\left|x_{j}-x_{j-1}\right| $,则插值余项满足 $$\left\|R_{n}(f)\right\|_{\infty} \equiv\left\|f-L_{n}(f)\right\|_{\infty} \leq \frac{h^{n+1} \left\|f^{(n+1)}\right\|_{\infty}}{4(n+1)}$$ 87 | 88 | \end{myThm} 89 | 90 | \end{subsubsection} 91 | 92 | \begin{subsubsection}{收敛性} 93 | 94 | 由以上定理可知:若被插值函数的任意阶导数一致有界,那么插值多项式可以收敛到被插值函数。 95 | 96 | 一般情况下,这种条件难以达到。例如本次实验中的被插值函数就是 Runge 于 1901 年所研究的例子,插值多项式在区间端点附近的振荡现象被称为 Runge 现象。 97 | 98 | \end{subsubsection} 99 | 100 | \end{subsection} 101 | 102 | \begin{subsection}{算法实现} 103 | 104 | Lagrange 插值的 MATLAB 实现如下: 105 | 106 | \begin{lstlisting}[language=Matlab] 107 | function coeff = myLagrangeInterp(x,y) 108 | % lagrange 插值法 109 | % 返回格式:coeff 为 (1,n+1) 大小的向量,分别表示从常数项到最高次项的系数 110 | [~,n] = size(x); 111 | n = n-1; 112 | coeff = zeros(1,n+1); 113 | l = zeros(n+1,n+1); % 基函数 114 | for i = 1:n+1 115 | l(i,1) = 1; prod = 1; 116 | for j = 1:n+1 117 | if (i==j) 118 | continue 119 | end 120 | l(i,:) = [0, l(i, 1:end-1)] - x(j)*l(i,:); 121 | prod = prod*(x(i)-x(j)); 122 | end 123 | coeff = coeff + y(i)*l(i,:)/prod; 124 | end 125 | end 126 | \end{lstlisting} 127 | 128 | \end{subsection} 129 | 130 | \end{section} 131 | 132 | \begin{section}{分段线性插值} 133 | 134 | \begin{subsection}{算法原理} 135 | 136 | 令 $$I_h(x) = y_j {x_{j+1}-x\over h_j} + y_{j+1} {x-x_j\over h_j}, x\in [x_j, x_{j+1}]$$ 则 $I_h(x)$ 为 $f(x)$ 的分段线性插值函数,满足: 137 | 138 | \begin{itemize} 139 | \item $I_h \in C[a,b]$ 140 | \item $I_h(x_j) = f(x_j)$ 141 | \item 在 $[x_j, x_{j+1}]$ 上是线性多项式 142 | \end{itemize} 143 | 144 | \begin{subsubsection}{误差估计} 145 | 146 | \begin{myThm} 147 | 148 | 设 $f\in C^2[a,b]$,那么有 $$\left\|f-I_h\right\|_{\infty} \leq {h^2\over 8} \left\|f^{\prime \prime}\right\|_{\infty}$$ 149 | 150 | \end{myThm} 151 | 152 | \end{subsubsection} 153 | 154 | \begin{subsubsection}{收敛性} 155 | 156 | 利用连续模的性质,可得收敛性定理: 157 | 158 | \begin{myThm} 159 | 160 | 设 $f\in C[a,b]$,那么当 $h \rightarrow 0$ 时,$I_{h} \rightrightarrows f$ . 161 | 162 | \end{myThm} 163 | 164 | 165 | \end{subsubsection} 166 | 167 | 168 | \end{subsection} 169 | 170 | \begin{subsection}{算法实现} 171 | 172 | 分段线性插值的 MATLAB 实现如下: 173 | 174 | \begin{lstlisting}[language=Matlab] 175 | function coeff = myLinearInterp(x,y) 176 | % 分段线性插值 177 | % 返回值 coeff 为 (n,2) 的矩阵,分别表示 n 段的常数项和一次项系数 178 | [~,n] = size(x); 179 | n = n-1; 180 | coeff = zeros(n,2); 181 | for i = 1:n 182 | h = x(i+1)-x(i); 183 | coeff(i,1) = (y(i)*x(i+1)-y(i+1)*x(i))/h; 184 | coeff(i,2) = (y(i+1)-y(i))/h; 185 | end 186 | \end{lstlisting} 187 | 188 | \end{subsection} 189 | 190 | \end{section} 191 | 192 | \begin{section}{三次样条插值} 193 | 194 | \begin{subsection}{算法原理} 195 | 196 | 若函数 $S_(x)$ 满足: 197 | 198 | \begin{itemize} 199 | \item $S\in C^2[a,b]$ 200 | \item $S$ 在 $[x_j,x_{j+1}]$ 上是三次多项式 201 | \end{itemize} 202 | 则称 $S$ 是一个\textbf{三次样条函数}。 203 | 204 | 若 $S$ 满足 $S(x_j) = f(x_j)$ ,则称 $S$ 为 $f$ 的 \textbf{三次样条插值函数}。更进一步地,$S$ 满足\textbf{自然边界条件} $$S^{\prime\prime}(x_0) = S^{\prime\prime}(x_n) = 0$$ 则称为\textbf{自然样条函数}。 205 | 206 | 三次样条插值函数可以通过转角方程、三弯矩方程、B-样条函数等方法求解。 207 | 208 | \begin{subsubsection}{转角方程} 209 | 210 | 假定 $S^{\prime \prime}(x_j) = M_j$ 已知,则通过插值条件 $S(x_j) = f(x_j)$ 可以得到: 211 | 212 | $$\begin{aligned} S(x)=& M_{j} \frac{\left(x_{j+1}-x\right)^{3}}{6 h_{j}}+M_{j+1} \frac{\left(x-x_{j}\right)^{3}}{6 h_{j}}\\&+\left(f\left(x_{j}\right)-\frac{M_{j} h_{j}^{2}}{6}\right) \frac{x_{j+1}-x}{h_{j}} \\ &+\left(f\left(x_{j+1}\right)-\frac{M_{j+1} h_{j}^{2}}{6}\right) \frac{x-x_{j}}{h_{j}}, \quad x \in\left[x_{j}, x_{j+1}\right] \end{aligned}$$ 213 | 214 | 为确定 $M_j$,可利用 $S^{\prime}$ 的连续性,得到线性方程组:$$\mu_{i} M_{j-1}+2 M_{j}+\lambda_{j} M_{j+1}=d_{j}, \quad j=1,2 \cdots, n-1$$ 其中 $$\begin{aligned} \mu_{j}&=\frac{h_{j-1}}{h_{j-1}+h_{j}}, \\ \quad \lambda_{j}&=1-\mu_{j}=\frac{h_{j}}{h_{j-1}+h_{j}} \\ \quad d_{j}&=6 f\left[x_{j-1}, x_{j}, x_{j+1}\right] \end{aligned}$$ 215 | 216 | 增加自然边界条件 $M_0 = M_n = 0$,方程组变为: 217 | 218 | \begin{tiny} 219 | $$\left[\begin{array}{ccccc}{2} & {\lambda_{1}} & {} & {} & {} \\ {\mu_{2}} & {2} & {\lambda_{2}} & {} & {} \\ {} & {\ddots} & {\ddots} & {\ddots} & {} \\ {} & {} & {\mu_{n-2}} & {2} & {\lambda_{n-2}} \\ {} & {} & {} & {\mu_{n-1}} & {2}\end{array}\right]\left[\begin{array}{c}{M_{1}} \\ {M_{2}} \\ {\vdots} \\ {M_{n-2}} \\ {M_{n-1}}\end{array}\right]=\left[\begin{array}{c}{d_{1}} \\ {d_{2}} \\ {\vdots} \\ {d_{n-2}} \\ {d_{n-1}}\end{array}\right]$$ 220 | \end{tiny} 221 | 222 | \end{subsubsection} 223 | 224 | \end{subsection} 225 | 226 | \begin{subsection}{算法实现} 227 | 228 | 三次自然样条插值的 MATLAB 实现如下: 229 | 230 | \begin{lstlisting}[language=Matlab] 231 | function coeff = mySplineInterp(x,y) 232 | % 三次自然样条插值 233 | % 返回值 coeff 为 (n,4) 的矩阵,分别表示 n 段的常数项到三次项系数 234 | [~,n] = size(x); 235 | n = n-1; 236 | coeff = zeros(n,4); 237 | h = x(2:end) - x(1:end-1); 238 | mu = h(1:end-1)./(h(1:end-1)+h(2:end)); 239 | lambda = 1-mu; 240 | df = (y(2:end)-y(1:end-1))./(x(2:end)-x(1:end-1)); 241 | d = 6*(df(2:end)-df(1:end-1))./(x(3:end)-x(1:end-2)); 242 | % 转角方程 243 | A = 2*eye(n-1)+diag(mu(2:end), 1)+diag(lambda(1:end-1), -1); 244 | b = d; 245 | M = [ 0; A\(b'); 0]; 246 | for j = 1:n 247 | coeff(j,:) = coeff(j,:) + [x(j+1)^3, -3*x(j+1)^2, 3*x(j+1), -1]*M(j)/6/h(j); 248 | coeff(j,:) = coeff(j,:) + [-x(j)^3, 3*x(j)^2, -3*x(j), 1]*M(j+1)/6/h(j); 249 | coeff(j,:) = coeff(j,:) + [x(j+1), -1, 0, 0]*(y(j)-M(j)*h(j)^2 / 6) / h(j); 250 | coeff(j,:) = coeff(j,:) + [-x(j), 1, 0, 0]*(y(j+1)-M(j+1)*h(j)^2 / 6) / h(j); 251 | end 252 | end 253 | \end{lstlisting} 254 | 255 | \end{subsection} 256 | 257 | \end{section} 258 | 259 | \begin{section}{方法比较} 260 | 261 | \begin{subsection}{误差} 262 | 263 | 选取不同的 $n$,计算不同插值函数的误差 $\left\|f-\right\|_{\infty}$ 如下: 264 | 265 | \begin{table}[H] 266 | \begin{tabular}{c|c|c|l} 267 | \hline 268 | & $L_{n}(f)$ & $I_h(f)$ & $S(f)$ \\ \hline 269 | $n=5$ & 0.432692 & 0.500000 & 0.423482 \\ 270 | $n=10$ & 0.326236 & 0.067431 & 0.010959 \\ 271 | $n=15$ & 0.249218 & 0.100000 & 0.030891 \\ 272 | $n=20$ & 58.278126 & 0.041538 & 0.002310 \\ 273 | \multicolumn{1}{l|}{$n=100$} & \multicolumn{1}{l|}{1e42} & \multicolumn{1}{l|}{0.002457} & 0.000025 \\ 274 | \multicolumn{1}{l|}{$n=1000$} & \multicolumn{1}{l|}{NaN} & \multicolumn{1}{l|}{0.000006} & 0.000000 \\ \hline 275 | \end{tabular} 276 | \end{table} 277 | 278 | \end{subsection} 279 | 280 | \begin{subsection}{图像} 281 | 282 | 选取 $n=10$,绘制原函数和插值函数的图像如图 \ref{compare} 所示。 283 | 284 | \begin{figure*}[ht] 285 | \centering 286 | \includegraphics[width = 0.9\textwidth]{img/compare.png} 287 | \caption{原函数和插值函数的图像 $n=10$} 288 | \label{compare} 289 | \end{figure*} 290 | 291 | \begin{subsubsection}{Runge 现象} 292 | 293 | 分别选取 $n=6, 10, 14$,绘制 $L_n(x)$ 的图像,观察 Runge 现象如图 \ref{runge} 所示。 294 | 295 | \begin{figure*}[ht] 296 | \centering 297 | \includegraphics[width = 0.9\textwidth]{img/runge.png} 298 | \caption{Runge 现象 $n=6,10,14$} 299 | \label{runge} 300 | \end{figure*} 301 | 302 | \end{subsubsection} 303 | 304 | \end{subsection} 305 | 306 | \begin{subsection}{结论} 307 | 308 | 随着 $n$ 的增加,Lagrange 插值多项式对于本次实验中的被插值函数不收敛,且出现了 Runge 现象。 309 | 310 | 分段线性插值函数和三次自然样条插值函数都收敛到被插值函数,但是分段线性插值函数的导数在采样点是不连续的,且三次样条插值函数的误差和收敛速度都由于分段线性插值函数。 311 | 312 | \end{subsection} 313 | 314 | \end{section} 315 | 316 | \begin{section}{总结} 317 | 318 | 本次实验对于几种不同的插值方法的算法进行了理论分析和编程计算,作出图像并比较了它们的结果。 319 | 320 | 结果符合预期:观察到 Lagrange 插值法的Runge现象;分段线性插值函数和三次样条插值函数都收敛到被插值函数,且三次样条插值函数的表现优于分段线性插值函数。 321 | 322 | \end{section} 323 | 324 | \end{multicols} 325 | 326 | 327 | 328 | %\bibliographystyle{unsrt} 329 | %\bibliography{ref.bib} 330 | 331 | %\begin{thebibliography}{99} %参考文献开始 332 | % \bibitem{ml}周志华. 机器学习[M]. 清华大学出版社, 2016. 333 | %\end{thebibliography} 334 | 335 | \end{document} 336 | 337 | -------------------------------------------------------------------------------- /practice-interp/problem/practice-interp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-interp/problem/practice-interp.pdf -------------------------------------------------------------------------------- /practice-interp/src/interp/main.m: -------------------------------------------------------------------------------- 1 | n = 10; 2 | fprintf("n = %d\n", n); 3 | x = (0:n)*2/n-1; 4 | y = f(x); 5 | 6 | hold on; 7 | 8 | sx = (0:100)*2/100-1; 9 | sy = f(sx); 10 | plot(sx, sy); 11 | 12 | coeff_lagrange = myLagrangeInterp(x, y); 13 | % disp(coeff_lagrange); 14 | [sx, sy] = sampleFunction([-1, 1], coeff_lagrange, 100); 15 | plot(sx, sy); 16 | fprintf("Lagrange error: %f\n", compute_error(sx,sy)) 17 | 18 | coeff_linear = myLinearInterp(x, y); 19 | % disp(coeff_linear); 20 | [sx, sy] = sampleFunction(x, coeff_linear, 10); 21 | plot(sx, sy); 22 | fprintf("Linear error: %f\n", compute_error(sx,sy)) 23 | 24 | coeff_spline = mySplineInterp(x, y); 25 | % disp(coeff_spline); 26 | [sx, sy] = sampleFunction(x, coeff_spline, 10); 27 | plot(sx, sy); 28 | fprintf("Spline error: %f\n", compute_error(sx,sy)) 29 | 30 | xlabel('x'); 31 | ylabel('y'); 32 | lgd = legend('f(x)', 'L_{n}(x)', 'I_h(x)', 'S_3(x)'); 33 | lgd.Location = 'southeast'; 34 | 35 | function y=f(x) 36 | y = 1./(1+25*x.^2); 37 | end 38 | 39 | function d = compute_error(sx, sy) 40 | y = f(sx); 41 | d = max(y-sy); 42 | end -------------------------------------------------------------------------------- /practice-interp/src/interp/myLagrangeInterp.m: -------------------------------------------------------------------------------- 1 | function coeff = myLagrangeInterp(x,y) 2 | % lagrange 插值法 3 | % 返回格式:coeff 为 (1,n+1) 大小的向量,分别表示从常数项到最高次项的系数 4 | 5 | [~,n] = size(x); 6 | n = n-1; 7 | 8 | coeff = zeros(1,n+1); 9 | 10 | l = zeros(n+1,n+1); % 基函数 11 | 12 | for i = 1:n+1 13 | l(i,1) = 1; prod = 1; 14 | for j = 1:n+1 15 | if (i==j) 16 | continue 17 | end 18 | l(i,:) = [0, l(i, 1:end-1)] - x(j)*l(i,:); 19 | prod = prod*(x(i)-x(j)); 20 | end 21 | coeff = coeff + y(i)*l(i,:)/prod; 22 | end 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /practice-interp/src/interp/myLinearInterp.m: -------------------------------------------------------------------------------- 1 | function coeff = myLinearInterp(x,y) 2 | % 分段线性插值 3 | % 返回值 coeff 为 (n,2) 的矩阵,分别表示 n 段的常数项和一次项系数 4 | 5 | [~,n] = size(x); 6 | n = n-1; 7 | 8 | coeff = zeros(n,2); 9 | 10 | for i = 1:n 11 | h = x(i+1)-x(i); 12 | coeff(i,1) = (y(i)*x(i+1)-y(i+1)*x(i))/h; 13 | coeff(i,2) = (y(i+1)-y(i))/h; 14 | 15 | end 16 | 17 | -------------------------------------------------------------------------------- /practice-interp/src/interp/mySplineInterp.m: -------------------------------------------------------------------------------- 1 | function coeff = mySplineInterp(x,y) 2 | % 三次自然样条插值 3 | % 返回值 coeff 为 (n,4) 的矩阵,分别表示 n 段的常数项到三次项系数 4 | 5 | [~,n] = size(x); 6 | n = n-1; 7 | 8 | coeff = zeros(n,4); 9 | 10 | h = x(2:end) - x(1:end-1); 11 | mu = h(1:end-1)./(h(1:end-1)+h(2:end)); 12 | lambda = 1-mu; 13 | df = (y(2:end)-y(1:end-1))./(x(2:end)-x(1:end-1)); 14 | d = 6*(df(2:end)-df(1:end-1))./(x(3:end)-x(1:end-2)); 15 | 16 | % 转角方程 17 | A = 2*eye(n-1)+diag(mu(2:end), 1)+diag(lambda(1:end-1), -1); 18 | b = d; 19 | 20 | M = [ 0; A\(b'); 0]; 21 | 22 | for j = 1:n 23 | coeff(j,:) = coeff(j,:) + [x(j+1)^3, -3*x(j+1)^2, 3*x(j+1), -1]*M(j)/6/h(j); 24 | coeff(j,:) = coeff(j,:) + [-x(j)^3, 3*x(j)^2, -3*x(j), 1]*M(j+1)/6/h(j); 25 | coeff(j,:) = coeff(j,:) + [x(j+1), -1, 0, 0]*(y(j)-M(j)*h(j)^2 / 6) / h(j); 26 | coeff(j,:) = coeff(j,:) + [-x(j), 1, 0, 0]*(y(j+1)-M(j+1)*h(j)^2 / 6) / h(j); 27 | end 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /practice-interp/src/interp/plotRunge.m: -------------------------------------------------------------------------------- 1 | hold on; 2 | 3 | sx = (0:100)*2/100-1; 4 | sy = f(sx); 5 | plot(sx, sy); 6 | 7 | n = 6; 8 | x = (0:n)*2/n-1; y = f(x); 9 | coeff_lagrange = myLagrangeInterp(x, y); 10 | [sx, sy] = sampleFunction([-1, 1], coeff_lagrange, 100); 11 | plot(sx, sy); 12 | 13 | n = 10; 14 | x = (0:n)*2/n-1; y = f(x); 15 | coeff_lagrange = myLagrangeInterp(x, y); 16 | [sx, sy] = sampleFunction([-1, 1], coeff_lagrange, 100); 17 | plot(sx, sy); 18 | 19 | n = 14; 20 | x = (0:n)*2/n-1; y = f(x); 21 | coeff_lagrange = myLagrangeInterp(x, y); 22 | [sx, sy] = sampleFunction([-1, 1], coeff_lagrange, 100); 23 | plot(sx, sy); 24 | 25 | xlabel('x'); 26 | ylabel('y'); 27 | lgd = legend('f(x)', 'L_{6}(x)', 'L_{10}(x)', 'L_{14}(x)'); 28 | lgd.Location = 'north'; 29 | 30 | function y=f(x) 31 | y = 1./(1+25*x.^2); 32 | end -------------------------------------------------------------------------------- /practice-interp/src/interp/sampleFunction.m: -------------------------------------------------------------------------------- 1 | function [sx, sy] = sampleFunction(x, coeff, density) 2 | 3 | [~,n] = size(x); 4 | n=n-1; 5 | 6 | [~,m] = size(coeff); 7 | 8 | sx = []; 9 | sy = []; 10 | 11 | for i = 1:n 12 | for j = 0:density 13 | cur_x = x(i)+(x(i+1)-x(i))/density*j; 14 | cur_y = 0; 15 | for k = 1:m 16 | cur_y = cur_y*cur_x+coeff(i,m-k+1); 17 | end 18 | sx = [sx cur_x]; 19 | sy = [sy cur_y]; 20 | end 21 | end 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /practice-ls/doc/img/gmres20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ls/doc/img/gmres20.png -------------------------------------------------------------------------------- /practice-ls/doc/img/gmres200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ls/doc/img/gmres200.png -------------------------------------------------------------------------------- /practice-ls/doc/img/iterations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ls/doc/img/iterations.png -------------------------------------------------------------------------------- /practice-ls/doc/img/relative_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ls/doc/img/relative_error.png -------------------------------------------------------------------------------- /practice-ls/doc/img/time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ls/doc/img/time.png -------------------------------------------------------------------------------- /practice-ls/doc/practice-ls-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ls/doc/practice-ls-doc.pdf -------------------------------------------------------------------------------- /practice-ls/doc/practice-ls-doc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | %中文环境设置 4 | \usepackage{xeCJK} 5 | \usepackage{indentfirst} 6 | \setlength{\parindent}{2em} 7 | \usepackage{enumitem} 8 | 9 | \usepackage{abstract} 10 | \renewcommand{\abstractname}{摘要} 11 | \providecommand{\keywords}[1]{\textbf{\textit{关键词}} #1} 12 | 13 | \setCJKmainfont{STSong} % 中文主字体设置 14 | 15 | \usepackage[colorlinks,linkcolor=blue, citecolor=blue]{hyperref} 16 | 17 | % 常用宏包 18 | \usepackage{float} 19 | \usepackage{stfloats} 20 | \usepackage{graphicx} 21 | \usepackage{color} 22 | 23 | % 代码环境设置 24 | \usepackage{listings} 25 | \lstset{ 26 | columns=fullflexible, 27 | frame=single, 28 | breaklines=true, 29 | } 30 | \definecolor{lightgray}{gray}{0.9} 31 | \newcommand{\inlinecode}[2]{\colorbox{lightgray}{\lstinline[language=#1]$#2$}} 32 | 33 | % 页面段落设置 34 | \usepackage{multicol} 35 | \usepackage{geometry} 36 | \geometry{left=3.18cm, right=3.18cm, top=2.54cm, bottom=2.54cm} 37 | \linespread{1.3} 38 | %\setlength{\parskip}{0.5em} 39 | 40 | % 数学环境设置 41 | \usepackage{amsmath} 42 | \usepackage{amsthm} 43 | \usepackage{amsfonts} 44 | \newtheorem{myDef}{Definition} 45 | \newtheorem{myThm}{Theorem} 46 | \newtheorem{myProp}{Property} 47 | 48 | \begin{document} 49 | \title{线性方程组部分上机习题} 50 | \author{吴佳龙 2018013418} 51 | \date{} 52 | \maketitle 53 | 54 | \begin{abstract} 55 | 通过理论分析和编程计算,运用不同算法分别求解系数矩阵为 Hilbert阵的病态线性方程组 $Hx=b$,比较他们的异同与优劣。运用的直接接法和迭代解法分别为:Gauss 消元法、Cholesky 分解方法、Tikhonov正则化改进的 Gauss 消元法和 Cholesky 方法;共轭梯度法和GMRES方法。 56 | \end{abstract} 57 | 58 | %\keywords{one, two, three, four} 59 | 60 | \begin{multicols}{2} 61 | 62 | \begin{section}{问题} 63 | 64 | 设 $H_{n}=\left[h_{i j}\right] \in \mathbb{R}^{n \times n}$ 是 Hilbert 矩阵,即 $$h_{i j}=\frac{1}{i+j-1}$$,取 $x=\left(\begin{array}{c}{1} \\ {\vdots} \\ {1}\end{array}\right) \in \mathbb{R}^{n}$,令 $b_n = H_nx$。再利用不同的数值方法求解病态线性方程组 $H_nx=b_n$。 65 | 66 | \end{section} 67 | 68 | \begin{section}{直接解法:Gauss 消元法和 Cholesky 分解方法} 69 | 70 | \begin{subsection}{列主元的 Gauss 消元法} 71 | 72 | \begin{subsubsection}{算法原理} 73 | 74 | 对于线性方程组 $Ax=b$,若 $A$ 可逆且 $A$ 的顺序主子式都不为 $0$,则可将 $A$ 的每一列依次做初等变换 $L_n \cdots L_2 L_1A = \tilde{L}A = U$ 为上三角阵。由此可将 $Ax=b$ 转化为求解 $Ux = \tilde{L}b = \tilde{b}$ ,其中系数矩阵为上三角阵,可在 $O(n^2)$ 的复杂度内通过简单递推求得 $x$: 75 | 76 | $$x_i = (\tilde{b}_i - \sum_{j=i+1}^n U_{ij} x_{j}) / U_{ii}$$ 77 | 78 | 若 $A$ 的顺序主子式不全为 $0$,或者消元过程中主元 $|A_{ii}^{(i-1)}|$ 过小容易带来较大误差,可采用选取列主元的 Gauss 消元法。具体地,每次选取 79 | 80 | $$pivot = \mathop{\arg\min}_{j\ge i} |A_{ji}^{(i-1)}|$$ 81 | 82 | 作为主元,交换行 $pivot$ 和行 $i$ 后再进行初等变换消元。该算法的矩阵表示为分解 $\tilde{L} P A = U$,将 $Ax=b$ 转化为求解 $Ux=\tilde{L}Pb$。 83 | 84 | Gauss消元法和选取列主元的Gauss消元法的总复杂度都为 $O(n^3)$ 85 | 86 | \end{subsubsection} 87 | 88 | \begin{subsubsection}{误差分析} 89 | 90 | 根据课本定理 4.4,可分析列主元的 Gauss 消元法的误差: 91 | 92 | \begin{myThm} 93 | 94 | 设用列主元的Gauss消元法解 $Ax=b$,其计算解 $\tilde{x}$ 满足 $(A+\delta A)\tilde{x} = b$,并设 $nu\leq 0.01$,则有 95 | 96 | \begin{small} 97 | $$\frac{\|x-\tilde{x}\|_{\infty}}{\|x\|_{\infty}} \leq \frac{\operatorname{cond}(A)_{\infty}}{1-\left\|A^{-1}\right\|_{\infty}\|\delta A\|_{\infty}}\left[1.01\left(n^{3}+3 n^{2}\right) \rho u\right]$$ 98 | \end{small} 99 | 100 | \end{myThm} 101 | 102 | 定理中 $u$ 是机器精度,$\rho = \max_{1\leq i,j,k\leq n} |a^{(k)}_{ij}| / \|A\|_{\infty}$ 称为列主元 Gauss 消元法的增长因子。 103 | 104 | 根据定理,计算解 $\tilde{x}$ 的相对误差受 $cond(A)$ 的影响很大。 105 | 106 | \end{subsubsection} 107 | 108 | \begin{subsubsection}{算法实现} 109 | 110 | 列主元的 Gauss 消元法的 MATLAB 实现如下: 111 | 112 | \begin{lstlisting}[language=Matlab] 113 | function [x] = myGauss(A, b) 114 | % 选取列主元的高斯消元法 Ax=b 115 | % 假定参数的size满足 A: [n,n], b: [n,1] 116 | [n,~] = size(A); 117 | A = [A, b]; % 增广矩阵 118 | % 选取列主元的高斯消元 119 | for i = 1:n 120 | [~, pivot] = max(abs(A(i:end, i))); 121 | pivot = pivot + i - 1; % 列主元 122 | A([i,pivot],:) = A([pivot,i],:); 123 | scale = A(i+1:end, i) / A(i,i); 124 | A(i+1:end, :) = A(i+1:end, :) - scale * A(i, :); 125 | end 126 | % 解 Ux=b1 127 | x = zeros(n,1); 128 | x(n) = A(n,end) / A(n,n); 129 | for i = n-1:-1:1 130 | x(i) = (A(i, end) - A(i, i+1:end-1) * x(i+1:end)) / A(i,i); 131 | end 132 | end 133 | 134 | \end{lstlisting} 135 | 136 | \end{subsubsection} 137 | 138 | \end{subsection} 139 | 140 | \begin{subsection}{Cholesky 分解方法} 141 | 142 | \begin{subsubsection}{算法原理} 143 | 144 | 对于系数矩阵对称正定的方程组 $Ax=b$,可将系数矩阵分解为下三角及其转置的乘积: 145 | 146 | $$A = LL^T$$ 147 | 148 | 根据系数关系可得 $L$ 各元素的计算公式: 149 | 150 | $$l_{jj} = (a_{jj}-\sum_{k=1}^{j-1}l_{jk}^2)^{1\over 2}$$ 151 | $$l_{ij} = {1\over l_{jj}} (a_{ij} - \sum_{k=1}^{j-1}l_{ik}l_{jk}), i=j+1,\cdots,n$$ 152 | 153 | 该分解将 $Ax=b$ 转化为求解 $Ly=b$ 和 $L^Tx=y$ 两个方程组,他们的系数矩阵分别为下三角和上三角。 154 | 155 | 该算法的复杂度为 $O(n^3)$。相比 Gauss 消元法,该算法的时间和空间复杂度的常数较小。 156 | 157 | \end{subsubsection} 158 | 159 | \begin{subsubsection}{误差分析} 160 | 161 | 该分解方法是 Gauss 消元法的变形,其误差也直接受到系数矩阵条件数 $cond(A)$ 的影响。 162 | 163 | \end{subsubsection} 164 | 165 | \begin{subsubsection}{算法实现} 166 | 167 | Cholesky 分解方法求解线性方程组的 MATLAB 实现如下: 168 | 169 | \begin{lstlisting}[language=Matlab] 170 | function [x] = myCholesky(A, b) 171 | % cholesky分解方法求解 Ax=LL'x=b 172 | % 假定参数的size满足 A: [n,n], b: [n,1] 173 | [n,~] = size(A); 174 | % Cholesky 分解 175 | L = zeros(n,n); 176 | for j = 1:n 177 | L(j,j) = sqrt(A(j,j) - sum(L(j, 1:j-1).^2)); 178 | L(j+1:n, j) = ( A(j+1:n,j) - L(j+1:n,1:j-1)*L(j,1:j-1)') / L(j,j); 179 | end 180 | % Ly=b 181 | y = zeros(n,1); 182 | y(1) = b(1) / L(1,1); 183 | for i = 2:n 184 | y(i) = (b(i) - L(i,1:i-1)*y(1:i-1)) / L(i,i); 185 | end 186 | % L'x=y 187 | x = zeros(n,1); 188 | L_t = L'; 189 | x(n) = y(n) / L_t(n,n); 190 | for i = n-1:-1:1 191 | x(i) = (y(i) - L_t(i, i+1:end) * x(i+1:end)) / L_t(i,i); 192 | end 193 | end 194 | \end{lstlisting} 195 | 196 | \end{subsubsection} 197 | 198 | \end{subsection} 199 | 200 | \end{section} 201 | 202 | \begin{section}{Tikhonov 正则化方法改进系数矩阵条件数} 203 | 204 | \begin{subsection}{算法原理} 205 | 206 | 对于病态的方程组,做某些预处理,可以降低系数矩阵的条件数,其中最有效的是 Tikhonov 正则化方法。 207 | 208 | 该方法将 $Ax=b$ 转化为求解 209 | 210 | $$(\alpha I+A^HA)x_{\alpha} = A^Hb$$ 211 | 212 | 该方程可用直接解法(Gauss 消元法等)求解,但是其系数矩阵的行列式 $$cond_2(\alpha I+A^HA) = {\frac{\alpha+\mu_{1}^{2}}{\alpha+\mu_{n}^{2}}}$$ 当 $\alpha > \mu_1\mu_n$ 时小于原矩阵条件数 $\mu_1\over\mu_n$。 213 | 214 | 又, 215 | \begin{align*} 216 | \left\|\mathbf{x}_{\alpha}-\mathbf{x}\right\|_{2} &\leq\left\|\left(\alpha I+A^{H} A\right)^{-1} A^{H}\right\|_{2} \cdot \delta \\ 217 | &+\left\|\left(\alpha I+A^{H} A\right)^{-1} A^{H} \mathbf{b}-A^{+} \mathbf{b}\right\|_{2} 218 | \end{align*} 219 | 220 | 其中 $\delta$ 表示 $b$ 的扰动带来的误差。若让上式右端两项量级大致相同,可取 221 | 222 | $$\mu_{1} \mu_{n}<\alpha \sim \mathcal{O}\left(\mu_{1}^{2} \delta\right)$$ 223 | 224 | \end{subsection} 225 | 226 | \begin{subsubsection}{算法实现} 227 | 228 | Tikhonov 正则化方法的 MATLAB 实现如下: 229 | 230 | \begin{lstlisting}[language=Matlab] 231 | function [x] = myTikhonov(A, b, delta, directMethod) 232 | % Tikhonov正则化方法改进条件数求解 Ax=b 233 | % 假定参数的size满足 A: [n,n], b: [n,1] 234 | % directMethod为直接解法的函数指针 235 | % 如 @myGauss @myCholesky 236 | [n,~] = size(A); 237 | eigen = eig(A); 238 | miu1 = eigen(end); 239 | alpha = miu1^2*delta; 240 | % 调用直接解法求解改进后的方程组 241 | x = directMethod(alpha*eye(n)+A'*A, A'*b); 242 | end 243 | 244 | \end{lstlisting} 245 | 246 | \end{subsubsection} 247 | 248 | \end{section} 249 | 250 | \begin{section}{迭代解法:共轭梯度法和 GMRES 方法} 251 | 252 | \begin{subsection}{共轭梯度法及预处理共轭梯度法} 253 | 254 | \begin{subsubsection}{算法原理} 255 | 256 | 对于对称正定阵 $A$,方程组 $Ax^{*}=b$ 等价于变分问题 257 | 258 | $$\varphi(x^*) = \min_{x\in \mathbb{R}^n} \varphi(x)$$ 259 | 260 | 我们可以用最速下降法求解该最小化问题,但是当 $A$ 的条件数很大时,最速下降法收敛很慢。 261 | 262 | 我们可以构造一组 $A$-共轭向量组 $\{p^{(i)}\}$,满足 $(Ap^{(i)},p^{(j)})=0, i\ne j$,且具有较好的性质:依次对 $p^{(1)},\cdots,p^{(l)}$ 进行一维极小搜索后的结果就是在 $\text{span}\{p^{(1)},\cdots,p^{(l)}\}$ 上的最小值。该算法称为共轭梯度法(CG算法)。 263 | 264 | 课本95页给出CG算法产生的序列有如下性质: 265 | 266 | \begin{myProp} 267 | $A$ 对称正定,记 $K = cond_2(A)$,则 268 | $$\left\|\mathbf{x}^{(k)}-\mathbf{x}^{*}\right\|_{A} \leq 2\left(\frac{\sqrt{K}-1}{\sqrt{K}+1}\right)^{k}\left\|\mathbf{x}^{(0)}-\mathbf{x}^{*}\right\|_{A}$$ 269 | \end{myProp} 270 | 271 | 可见当 $A$ 病态时,CG算法仍然收敛很慢,预先设法降低条件数,就是预处理的共轭梯度法(PCG算法)。 272 | 273 | PCG算法选取一个对称正定阵 $M=SS^T$,将 $Ax=b$ 改写为等价方程组: 274 | 275 | $$S^{-1}AS^{-T}u = S^{-1}b,\ x=S^{-T}u$$ 276 | 277 | 然后用CG法求解第一个方程。这样,在解的迭代序列仍满足上述性质中,不过其中 $K=cond(M^{-1}A)_2$。 278 | 279 | $M$ 的常见选取有:$A$ 的不完全Cholesky分解、Jacobi迭代法的分裂矩阵 $M=D$、SSOR法的分裂矩阵等。 280 | 281 | \end{subsubsection} 282 | 283 | \begin{subsubsection}{算法描述} 284 | 285 | CG算法的描述如下: 286 | 287 | \begin{enumerate} 288 | \item 任取 $x^{(0)} \in \mathbb{R}^{n}$ 289 | \item $r^{(0)}=b-A x^{(0)}, p^{(0)}=r^{(0)}$ 290 | \item 对 $k=0,1,\cdots,$ $$\begin{array}{l}{\alpha_{k}=\frac{\left({r}^{(k)}, {r}^{(k)}\right)}{\left({p}^{(k)}, {A} {p}^{(k)}\right)}} \\ {{x}^{(k+1)}={x}^{(k)}+{\alpha}_{k} {p}^{(k)}} \\ {{r}^{(k+1)}={r}^{(k)}-{\alpha}_{k} {A} {p}^{(k)}} \\ {{\beta}_{k}=\frac{\left({r}^{(k+1)}, {r}^{(k+1)}\right)}{\left({r}^{(k)}, {r}^{(k)}\right)}} \\ {{p}^{(k+1)}={r}^{(k+1)}+{\beta}_{k} {p}^{(k)}}\end{array}$$ 291 | \end{enumerate} 292 | 293 | PCG算法的描述如下: 294 | 295 | \begin{enumerate} 296 | \item 任取 $x^{(0)} \in \mathbb{R}^{n}$ 297 | \item $r^{(0)}=b-A x^{(0)}, z^{(0)}=M^{-1} r^{(0)}, p^{(0)}=z^{(0)}$ 298 | \item 对 $k=0,1,\cdots,$ $$\begin{array}{l}{\alpha_{k}=\frac{\left(z^{(k)}, r^{(k)}\right)}{\left(p^{(k)}, A p^{(k)}\right)}} \\ {x^{(k+1)}=x^{(k)}+\alpha_{k} p^{(k)}} \\ {r^{(k+1)}=r^{(k)}-\alpha_{k} A p^{(k)}} \\ {M z^{(k+1)}=r^{(k+1)}} \\ {\beta_{k}=\frac{\left(z^{(k+1)}, r^{(k+1)}\right)}{\left(z^{(k)}, r^{(k)}\right)}} \\ {p^{(k+1)}=z^{(k+1)}+\beta_{k} p^{(k)}}\end{array}$$ 299 | \end{enumerate} 300 | 301 | \end{subsubsection} 302 | 303 | \begin{subsubsection}{算法实现} 304 | 共轭梯度法(CG算法)的 MATLAB 实现如下: 305 | 306 | \begin{lstlisting}[language=Matlab] 307 | function [x, iters] = myCG(A, b, kmax, eps) 308 | % 共轭梯度法 Ax=b 309 | % 假定参数的size满足 A: [n,n], b: [n,1] 310 | % 返回值 iter 表示收敛时迭代次数 311 | [n,~] = size(A); 312 | x = zeros(n,1); 313 | r = b-A*x; p = r; 314 | for k = 1:kmax 315 | alpha = (r'*r)/(p'*(A*p)); 316 | x = x+alpha*p; 317 | last_r = r; r = r-alpha*A*p; 318 | beta = (r'*r)/(last_r'*last_r); 319 | p = r*beta+p; 320 | if norm(r)/norm(b) < eps 321 | iters = k; 322 | return; 323 | end 324 | end 325 | iters = kmax; 326 | end 327 | \end{lstlisting} 328 | 329 | 预处理共轭梯度法(PCG算法)的 MATLAB 实现如下: 330 | 331 | \begin{lstlisting}[language=Matlab] 332 | function [x, iters] = myPCG(A, b, kmax, eps) 333 | % 预处理的共轭梯度法 Ax=b 334 | % 假定参数的size满足 A: [n,n], b: [n,1] 335 | % 返回值 iter 表示收敛时迭代次数 336 | [n,~] = size(A); 337 | M = diag(diag(A)); % Jacobi迭代的分裂矩阵 338 | x = zeros(n,1); 339 | r = b-A*x; z = M\r; p = z; 340 | for k = 1:kmax 341 | alpha = (z'*r)/(p'*(A*p)); 342 | x = x+alpha*p; 343 | last_r = r; r = r-alpha*A*p; 344 | last_z = z; z = M\r; 345 | beta = (z'*r)/(last_z'*last_r); 346 | p = z+beta*p; 347 | 348 | if norm(r)/norm(b) < eps 349 | iters = k; 350 | return; 351 | end 352 | end 353 | iters = kmax; 354 | end 355 | \end{lstlisting} 356 | 357 | \end{subsubsection} 358 | 359 | \end{subsection} 360 | 361 | \begin{subsection}{GMRES 方法} 362 | 363 | \begin{subsubsection}{算法原理} 364 | 365 | 关于线性方程组,有Galerkin原理:$K_m$ 和 $L_m$ 是 $\mathbb{R}^n$ 中的两个 $m$ 维子空间,他们的基分别为 $\{v_i\}, \{w_i\}$,并记 $V_m = (v_1,\cdots,v_m), W_m = {w_1,\cdots,w_m}$。对于方程组 $Az=r_0$,在子空间 $K_m$ 中可以找到近似解$z_m$ 使得 $r_0-Az_m \perp L_m$。将 $z_m$ 表示为 $z_m = V_m y_m$,若 $W_m^TAVm$ 非奇异,解得 366 | $$z_m = V_m(W_m^TAV_m)^{-1}W_m^Tr0$$ 367 | 368 | 在 GMRES 算法中,取 $K_m = \text{span}\{r_0,\cdots, A^{m-1}r_0\}$,$ L_m=AK_m=\{Ar_0, \cdots, A^mr_0\}$,可以证明此时 $W_m^TAV_m$ 非奇异,且求解 $z_m$ 等价于在 $K_m$ 中极小化 $R(x)=\|\mathbf{b}-A \mathbf{x}\|_{2}^2$,即 $$R(\mathbf{x}_{0}+z_m)=\min _{\mathbf{x} \in \mathbf{x}_{0}+K_{m}} R(\mathbf{x})$$ 369 | 370 | 另外,可以证明,取 $\mathbf{v}_{1}=\mathbf{r}_{0} /\left\|\mathbf{r}_{0}\right\|_{2}$ 通过 Arnoldi 过程,可以将 $A$ 分解为 $$AV = VH$$,其中 $H$ 是上Hessenberg阵,$V = (v_1, \cdots, v_n)$ 是正交阵,且 $V_m = (v_1,\cdots,v_m)$ 是 $K_m$ 的一组标准正交基。 371 | 372 | 有了上述 $A$ 的分解式,可以证明极小化残差 $R(x_0+z_m) = \|r_0-Az_m\|^2$ 等价于极小化 $\| \beta \mathbf{e}_{1}-\widetilde{H}_{m} \mathbf{y}_{m}\|$,其中 $\beta = \|r_0\|$, $\tilde{H}_{m}=\left(\begin{array}{c}{H_{m}} \\ {h_{m+1, m} \mathbf{e}_{m}^{T}}\end{array}\right)$。 373 | 374 | \end{subsubsection} 375 | 376 | \begin{subsubsection}{算法描述} 377 | 378 | GMRES算法描述如下: 379 | 380 | \begin{enumerate} 381 | \item 选取适当的 $m, \mathbf{x}_0$,记 $\mathbf{r}_0 = \mathbf{b}-A\mathbf{x}_0, \beta = \|\mathbf{r}_0\|, \mathbf{v}_1 = \mathbf{r}_0/\beta$ 382 | \item 用Arnoldi过程求出 $V_m$ 和 $\widetilde{H}_{m}$ 383 | \item 求解最小二乘问题 $$\min _{\mathbf{y}_{m} \in \mathbb{R}^{m}}\left\|\beta \mathbf{e}_{1}-\widetilde{H}_{m} \mathbf{y}_{m}\right\|$$ 得到 $y_m$ 384 | \item 计算 $\mathbf{x}_{m}=\mathbf{x}_{0}+V_{m} \mathbf{y}_{m}, \mathbf{r}_{m}=\mathbf{b}-A \mathbf{x}_{m}$ 385 | \item 若 $\left\|\mathbf{r}_{m}\right\|<\varepsilon$ 则停止迭代,否则 $\mathbf{x}_{0}=\mathbf{x}_{m}, \mathbf{r}_{0}=\mathbf{r}_{m}, \mathbf{v}_{1}=\mathbf{r}_{m} /\left\|\mathbf{r}_{m}\right\|$,转第 2 步 386 | \end{enumerate} 387 | 388 | \end{subsubsection} 389 | 390 | \begin{subsubsection}{算法实现} 391 | 392 | GMRES算法的 MATLAB 实现如下: 393 | 394 | \begin{lstlisting}[language=Matlab] 395 | function [x, iters] = myGMRESm(A, b, m, kmax, eps) 396 | % GMRES算法求解 Ax=b 397 | % 假定参数的size满足 A: [n,n], b: [n,1] 398 | [n,~] = size(A); 399 | m = min(m,n); 400 | x0 = zeros(n,1); 401 | % x0 = randn(n,1)*0.0001; 402 | for k = 1:kmax 403 | r0 = b-A*x0; 404 | v1 = r0/norm(r0); 405 | % Arnoldi过程 406 | Vm = zeros(n,m+1); Vm(:,1) = v1; 407 | Hm = zeros(m+1,m); 408 | success = true; 409 | for i = 1:m 410 | for j = 1:i 411 | Hm(j,i) = dot(A*Vm(:,i), Vm(:,j)) / dot(Vm(:,j),Vm(:,j)); 412 | end 413 | ri = A*Vm(:,i) - Vm(:,1:i)*Hm(1:i,i); 414 | if ~any(ri(:)) 415 | success = false; 416 | break 417 | end % ri==0,中断 418 | if iepsi 26 | 27 | V=zeros(n,(m+1)*s); 28 | H=zeros(m+1,m); 29 | V(:,1:s)=R0/norm(R0,'fro'); 30 | for j=1:m 31 | W=A*V(:,(j-1)*s+1:j*s); 32 | for i=1:j 33 | H(i,j)=trace(W'*V(:,(i-1)*s+1:i*s)); 34 | W=W-H(i,j)*V(:,(i-1)*s+1:i*s); 35 | end 36 | H(j+1,j)=norm(W,'fro'); 37 | if H(j+1,j)==0 38 | break 39 | end 40 | V(:,j*s+1:(j+1)*s)=W/H(j+1,j); 41 | end 42 | y=H\(norm(R0,'fro')*speye(m+1,1)); 43 | V1=V(:,1:m*s); 44 | X=X0+V1*kron(y,I); 45 | X0=X; 46 | R0=B-A*X0; 47 | r=norm(R0,'fro'); 48 | e=r; 49 | % R=[R,log10(r)]; %�˴����Ա���ͼ 50 | t=t+1; 51 | 52 | end 53 | % t1=1:t; 54 | % plot(t1, R, 'r*--'); 55 | 56 | toc 57 | end 58 | -------------------------------------------------------------------------------- /practice-ls/src/linear/myCG.m: -------------------------------------------------------------------------------- 1 | function [x, iters] = myCG(A, b, kmax, eps) 2 | % 共轭梯度法 Ax=b 3 | % 假定参数的size满足 A: [n,n], b: [n,1] 4 | % 返回值 iter 表示收敛时迭代次数 5 | 6 | [n,~] = size(A); 7 | 8 | x = zeros(n,1); 9 | r = b-A*x; p = r; 10 | 11 | for k = 1:kmax 12 | alpha = (r'*r)/(p'*(A*p)); 13 | x = x+alpha*p; 14 | last_r = r; r = r-alpha*A*p; 15 | beta = (r'*r)/(last_r'*last_r); 16 | p = r*beta+p; 17 | 18 | if norm(r)/norm(b) < eps 19 | iters = k; 20 | return; 21 | end 22 | end 23 | 24 | iters = kmax; 25 | 26 | end -------------------------------------------------------------------------------- /practice-ls/src/linear/myCholesky.m: -------------------------------------------------------------------------------- 1 | function [x] = myCholesky(A, b) 2 | % cholesky分解方法求解 Ax=LL'x=b 3 | % 假定参数的size满足 A: [n,n], b: [n,1] 4 | 5 | [n,~] = size(A); 6 | 7 | % Cholesky 分解 8 | L = zeros(n,n); 9 | for j = 1:n 10 | L(j,j) = sqrt(A(j,j) - sum(L(j, 1:j-1).^2)); 11 | L(j+1:n, j) = ( A(j+1:n,j) - L(j+1:n,1:j-1)*L(j,1:j-1)') / L(j,j); 12 | end 13 | 14 | % Ly=b 15 | y = zeros(n,1); 16 | y(1) = b(1) / L(1,1); 17 | for i = 2:n 18 | y(i) = (b(i) - L(i,1:i-1)*y(1:i-1)) / L(i,i); 19 | end 20 | 21 | % L'x=y 22 | x = zeros(n,1); 23 | L_t = L'; 24 | x(n) = y(n) / L_t(n,n); 25 | for i = n-1:-1:1 26 | x(i) = (y(i) - L_t(i, i+1:end) * x(i+1:end)) / L_t(i,i); 27 | end 28 | 29 | end -------------------------------------------------------------------------------- /practice-ls/src/linear/myGMRESm.m: -------------------------------------------------------------------------------- 1 | function [x, iters] = myGMRESm(A, b, m, kmax, eps) 2 | % GMRES算法求解 Ax=b 3 | % 假定参数的size满足 A: [n,n], b: [n,1] 4 | 5 | [n,~] = size(A); 6 | m = min(m,n); 7 | x0 = zeros(n,1); 8 | % x0 = randn(n,1)*0.0001; 9 | 10 | for k = 1:kmax 11 | r0 = b-A*x0; 12 | v1 = r0/norm(r0); 13 | 14 | % Arnoldi过程 15 | Vm = zeros(n,m+1); Vm(:,1) = v1; 16 | Hm = zeros(m+1,m); 17 | success = true; 18 | 19 | for i = 1:m 20 | for j = 1:i 21 | Hm(j,i) = dot(A*Vm(:,i), Vm(:,j)) / dot(Vm(:,j),Vm(:,j)); 22 | end 23 | ri = A*Vm(:,i) - Vm(:,1:i)*Hm(1:i,i); 24 | if ~any(ri(:)) 25 | success = false; 26 | break 27 | end % ri==0,中断 28 | if i1)$ 阶收敛的,则 Steffensen 方法是 $2p-1$ 阶收敛的。 185 | \end{myThm} 186 | 187 | 这说明,Steffensen 方法可以把不收敛的不动点迭代法改进为二阶收敛的方法。 188 | 189 | \end{subsection} 190 | 191 | \begin{subsection}{算法实现} 192 | 193 | Steffensen加速方法的 MATLAB 实现如下: 194 | 195 | \begin{lstlisting}[language=Matlab] 196 | function [x, x_series] = mySteffensen(x0, phi, eps, kmax) 197 | % Steffensen加速方法 解 x=phi(x) 198 | % kmax: 最大迭代次数 199 | % eps: 相邻两次迭代结果小于eps,则终止 200 | 201 | x = x0; 202 | x_series = [x0]; 203 | for k = 1:kmax 204 | last_x = x; 205 | y = phi(x); 206 | z = phi(y); 207 | x = x- (y-x)^2/(z-2*y+x); 208 | x_series = [x_series x]; 209 | if abs(x-last_x) < eps 210 | break 211 | end 212 | end 213 | end 214 | \end{lstlisting} 215 | 216 | \end{subsection} 217 | 218 | \begin{subsection}{计算结果} 219 | 220 | 对于 $\varphi_1$ 和 $\varphi_2$ 分别调用 221 | \begin{lstlisting}[language=Matlab] 222 | mySteffensen(1, @(x)(20-2*x^2-x^3)/10.0, 1e-8, 50) 223 | \end{lstlisting} 和 224 | \begin{lstlisting}[language=Matlab] 225 | mySteffensen(1, @(x)nthroot(20-10*x-2*x^2,3), 1e-8, 50) 226 | \end{lstlisting} 计算。产生的迭代序列如表 \ref{table_steff} 所示。 227 | 228 | \begin{table}[H] 229 | \caption{Steffensen 迭代法} 230 | \centering 231 | \label{table_steff} 232 | \begin{tabular}{l|l|l} 233 | \hline 234 | & $\varphi_1$ \ref{func1} + Steffensen & $\varphi_2$ \ref{func2} + Steffensen \\ \hline 235 | $x_0$ & 1.0 & 1.0 \\ 236 | $x_1$ & 1.2 & 1.33349213911 \\ 237 | $x_2$ & 1.27374039955 & 1.36841543911 \\ 238 | $x_3$ & 1.30830003901 & 1.36880805831 \\ 239 | $x_4$ & 1.34727521974 & 1.36880810782 \\ 240 | $x_5$ & 1.36672391381 & 1.36880810782 \\ 241 | $x_6$ & 1.36878928488 & \\ 242 | $x_7$ & 1.36880810629 & \\ 243 | $x_8$ & 1.36880810782 & 244 | \end{tabular} 245 | \end{table} 246 | 247 | 可以看到,Steffensen 方法将原来不收敛的不动点迭代法改进为收敛的算法,且是二阶收敛。 248 | 249 | \end{subsection} 250 | 251 | \end{section} 252 | 253 | \begin{section}{Newton 迭代法} 254 | 255 | \begin{subsection}{算法原理} 256 | 257 | 为求解方程 $f(x)=0$,等价于求函数 $f(x)$ 的零点,Newton 法对曲线上的点 $(x_k, f(x_k))$ 作切线,切线与 x 轴的焦点作为新的近似值。 258 | 259 | $$x_{k+1} = x_k - {f(x_k)\over f^\prime(x_{k})}$$ 260 | 261 | \end{subsection} 262 | 263 | \begin{subsection}{收敛性分析} 264 | 265 | 有课本上定理 4.1 : 266 | 267 | \begin{myThm} 268 | 设 $f(x^*)=0,f^\prime(x^*) \neq 0$,且 $f$ 在包含 $x^*$ 的一个区间上有二阶连续导数,则 Newton 迭代法局部收敛到 $x^*$,且至少二阶收敛,并有 269 | 270 | $$\lim_{k \rightarrow \infty} {x_{k+1}-x^*\over (x_k-x^*)^2} = {f^{\prime\prime}(x^*) \over 2f^\prime(x^*)}$$ 271 | \end{myThm} 272 | 273 | \end{subsection} 274 | 275 | \begin{subsection}{算法实现} 276 | 277 | Newton 法的 MATLAB 实现如下: 278 | 279 | \begin{lstlisting}[language=Matlab] 280 | function [x, x_series] = myNewton(x0, f, df, eps, kmax) 281 | % Newton法 解 f(x)=0 282 | % df: f的导函数 283 | % kmax: 最大迭代次数 284 | % eps: 相邻两次迭代结果小于eps,则终止 285 | 286 | x = x0; 287 | x_series = [x0]; 288 | for k = 1:kmax 289 | last_x = x; 290 | x = x-f(x)/df(x); 291 | x_series = [x_series x]; 292 | if abs(x-last_x) < eps 293 | break 294 | end 295 | end 296 | end 297 | \end{lstlisting} 298 | 299 | \end{subsection} 300 | 301 | \begin{subsection}{计算结果} 302 | 303 | 调用 304 | \begin{lstlisting}[language=Matlab] 305 | f = @(x)x^3+2*x^2+10*x-20; 306 | df = @(x)3*x^2+4*x+10; 307 | myNewton(1, f, df, 1e-8, 50) 308 | \end{lstlisting} 产生的迭代序列如表 \ref{table_newton} 所示。 309 | 310 | \begin{table}[H] 311 | \caption{Newton 迭代法} 312 | \centering 313 | \label{table_newton} 314 | \begin{tabular}{l|l} 315 | \hline 316 | & Newton \\ \hline 317 | $x_0$ & 1.0 \\ 318 | $x_1$ & 1.41176470588 \\ 319 | $x_2$ & 1.36933647059 \\ 320 | $x_3$ & 1.36880818862 \\ 321 | $x_4$ & 1.36880810782 \\ 322 | $x_5$ & 1.36880810782 323 | \end{tabular} 324 | \end{table} 325 | 326 | 可以看到 Newton 快速地收敛到解。 327 | 328 | \end{subsection} 329 | 330 | \end{section} 331 | 332 | \begin{section}{方法比较} 333 | 334 | 将不同算法迭代产生的序列作图 \ref{plot}。 335 | 336 | 可以看到未改进的不动点迭代法产生的迭代序列产生剧烈的振动,结果不收敛。而 Steffensen 迭代法和 Newton 迭代法都是二阶收敛算法,都能在很少的迭代次数时收敛到较精确的解。不同的 $\varphi$ 选取也会对收敛速度产生影响。 337 | 338 | \begin{figure*}[ht] %h默认参数是可以浮动,不是固定在当前位置。如果要不浮动,你就可以使用大写float宏包的H参数,固定图片在当前位置,禁止浮动。 339 | \centering %使图片居中显示 340 | \includegraphics[width = \textwidth]{img/plot3.png} 341 | \includegraphics[width = \textwidth]{img/plot5.png} 342 | \caption{不同算法的迭代序列} 343 | \label{plot} 344 | \end{figure*} 345 | 346 | \end{section} 347 | 348 | \begin{section}{总结} 349 | 350 | 本次实验分别采用不动点迭代法、Steffensen 迭代法和 Newton 迭代法求解非线性方程 \ref{equ},并在使用不动点迭代法和 Steffensen 法时分别选取了两种不同的迭代函数 \ref{func1} \ref{func2}。即通过理论分析迭代法的收敛性,又进行编程计算,观察算法产生的迭代序列,得到了与理论相符合的结果。 351 | 352 | \end{section} 353 | 354 | \end{multicols} 355 | 356 | 357 | 358 | %\bibliographystyle{unsrt} 359 | %\bibliography{ref.bib} 360 | 361 | %\begin{thebibliography}{99} %参考文献开始 362 | % \bibitem{ml}周志华. 机器学习[M]. 清华大学出版社, 2016. 363 | %\end{thebibliography} 364 | 365 | \end{document} 366 | 367 | -------------------------------------------------------------------------------- /practice-nls/problem/practice-nls.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-nls/problem/practice-nls.pdf -------------------------------------------------------------------------------- /practice-nls/src/nlinear/main.m: -------------------------------------------------------------------------------- 1 | % main 2 | 3 | phi1 = @(x)(20-2*x^2-x^3)/10.0; 4 | phi2 = @(x)nthroot(20-10*x-2*x^2,3); 5 | f = @(x)x^3+2*x^2+10*x-20; 6 | df = @(x)3*x^2+4*x+10; 7 | 8 | [x_fp1, xs_fp1] = myFixedPoint(1, phi1, 1e-8, 50); 9 | [x_fp2, xs_fp2] = myFixedPoint(1, phi2, 1e-8, 50); 10 | 11 | [x_steff1, xs_steff1] = mySteffensen(1, phi1, 1e-8, 50); 12 | [x_steff2, xs_steff2] = mySteffensen(1, phi2, 1e-8, 50); 13 | [x_newton, xs_newton] = myNewton(1, f, df, 1e-8, 50); 14 | 15 | disp('x series fp1:'); disp(vpa(xs_fp1,12)); 16 | disp('x series fp2:'); disp(vpa(xs_fp2,12)); 17 | disp('x series steff1:'); disp(vpa(xs_steff1,12)); 18 | disp('x series steff2:'); disp(vpa(xs_steff2,12)); 19 | disp('x series newton:'); disp(vpa(xs_newton,12)); 20 | 21 | hold on; 22 | % plot(1:length(xs_fp1), xs_fp1, 'LineWidth',1.5); 23 | % plot(1:length(xs_fp2), xs_fp2, 'LineWidth',1.5); 24 | plot(1:length(xs_steff1), xs_steff1, 'LineWidth',1.5); 25 | plot(1:length(xs_steff2), xs_steff2, 'LineWidth',1.5); 26 | plot(1:length(xs_newton), xs_newton, 'LineWidth',1.5); 27 | 28 | legend('steff1', 'steff2', 'newton'); 29 | % legend('fp1', 'fp2', 'steff1', 'steff2', 'newton'); 30 | 31 | xlabel('k'); 32 | ylabel('x_k'); -------------------------------------------------------------------------------- /practice-nls/src/nlinear/myFixedPoint.m: -------------------------------------------------------------------------------- 1 | function [x, x_series] = myFixedPoint(x0, phi, eps, kmax) 2 | % 不动点迭代法 解 x=phi(x) 3 | % kmax: 最大迭代次数 4 | % eps: 相邻两次迭代结果小于eps,则终止 5 | 6 | x = x0; 7 | x_series = [x0]; 8 | for k = 1:kmax 9 | last_x = x; 10 | x = phi(last_x); 11 | x_series = [x_series x]; 12 | if abs(x-last_x) < eps 13 | break 14 | end 15 | end 16 | 17 | end 18 | 19 | -------------------------------------------------------------------------------- /practice-nls/src/nlinear/myNewton.m: -------------------------------------------------------------------------------- 1 | function [x, x_series] = myNewton(x0, f, df, eps, kmax) 2 | % Newton法 解 f(x)=0 3 | % df: f的导函数 4 | % kmax: 最大迭代次数 5 | % eps: 相邻两次迭代结果小于eps,则终止 6 | 7 | x = x0; 8 | x_series = [x0]; 9 | for k = 1:kmax 10 | last_x = x; 11 | x = x-f(x)/df(x); 12 | x_series = [x_series x]; 13 | if abs(x-last_x) < eps 14 | break 15 | end 16 | end 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /practice-nls/src/nlinear/mySteffensen.m: -------------------------------------------------------------------------------- 1 | function [x, x_series] = mySteffensen(x0, phi, eps, kmax) 2 | % Steffensen加速方法 解 x=phi(x) 3 | % kmax: 最大迭代次数 4 | % eps: 相邻两次迭代结果小于eps,则终止 5 | 6 | x = x0; 7 | x_series = [x0]; 8 | for k = 1:kmax 9 | last_x = x; 10 | y = phi(x); 11 | z = phi(y); 12 | x = x- (y-x)^2/(z-2*y+x); 13 | x_series = [x_series x]; 14 | if abs(x-last_x) < eps 15 | break 16 | end 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /practice-ode/doc/practice-ode-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ode/doc/practice-ode-doc.pdf -------------------------------------------------------------------------------- /practice-ode/doc/practice-ode-doc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | %中文环境设置 4 | \usepackage{xeCJK} 5 | \usepackage{indentfirst} 6 | \setlength{\parindent}{2em} 7 | \usepackage{enumitem} 8 | 9 | \usepackage{abstract} 10 | \renewcommand{\abstractname}{摘要} 11 | \providecommand{\keywords}[1]{\textbf{\textit{关键词}} #1} 12 | 13 | \setCJKmainfont{STSong} % 中文主字体设置 14 | 15 | \usepackage[colorlinks,linkcolor=blue, citecolor=blue]{hyperref} 16 | 17 | % 常用宏包 18 | \usepackage{float} 19 | \usepackage{stfloats} 20 | \usepackage{graphicx} 21 | \usepackage{color} 22 | \usepackage{supertabular} 23 | 24 | % 代码环境设置 25 | \usepackage{listings} 26 | \lstset{ 27 | columns=fullflexible, 28 | frame=single, 29 | breaklines=true, 30 | } 31 | \definecolor{lightgray}{gray}{0.9} 32 | \newcommand{\inlinecode}[2]{\colorbox{lightgray}{\lstinline[language=#1]$#2$}} 33 | 34 | % 页面段落设置 35 | \usepackage{multicol} 36 | \usepackage{geometry} 37 | \geometry{left=3.18cm, right=3.18cm, top=2.54cm, bottom=2.54cm} 38 | \linespread{1.3} 39 | %\setlength{\parskip}{0.5em} 40 | 41 | % 数学环境设置 42 | \usepackage{amsmath} 43 | \usepackage{amssymb} 44 | \usepackage{amsthm} 45 | \usepackage{amsfonts} 46 | \usepackage{mathrsfs} 47 | \newtheorem{myDef}{Definition} 48 | \newtheorem{myThm}{Theorem} 49 | \newtheorem{myProp}{Property} 50 | 51 | \begin{document} 52 | \title{常微分方程数值解实验题} 53 | \author{吴佳龙 2018013418} 54 | \date{} 55 | \maketitle 56 | 57 | \begin{abstract} 58 | 结合理论分析和编程计算,运用不同方法计算了一常微分方程初值问题的数值解,并与精确解比较。运用的方法分别为:古典四级四阶 Runge-Kutta 方法和隐式二级四阶 Runge-Kutta 方法(Gauss 方法)。 59 | \end{abstract} 60 | 61 | %\keywords{one, two, three, four} 62 | 63 | \begin{multicols}{2} 64 | 65 | \begin{section}{问题} 66 | 67 | 求解:$$\left\{\begin{array}{l}{\frac{d u}{d t}=-2000 u(t)+999.75 v(t)+1000.25} \\ {\frac{d v}{d t}=u(t)-v(t)}\end{array}\right.$$ 初始条件为 $u(0)=0, v(0)=-2$。其精确解为 $$\left\{\begin{array}{l}{u(t)=-1.499875 e^{-0.5 t}+0.499875 e^{-2000.5 t}+1} \\ {v(t)=-2.99975 e^{-0.5 t}-0.00025 e^{-2000.5 t}+1}\end{array}\right.$$ 68 | 69 | 分别用古典四级四阶 Runge-Kutta 方法和隐式二级四阶 Runge-Kutta 方法计算,计算区间取成 $[0,20]$,并与精确解比较。 70 | 71 | \end{section} 72 | 73 | \begin{section}{古典四级四阶 Runge-Kutta 方法} 74 | 75 | \begin{subsection}{算法原理} 76 | 77 | \begin{subsubsection}{用 Taylor 展开构造高阶数值方法} 78 | 79 | 取 $y(x+h) \approx y(x)+hy^\prime(x)$ 得到单步法,即 1 阶 Euler 方法 $$y_{n+1} = y_{n}+hf(x_n,y_n)$$ 80 | 81 | 取 $y(x+h) \approx y(x)+hy^\prime(x) + {1\over 2}h^2y^{\prime\prime}(x)$ 得到 2 阶单步法 \begin{align} 82 | \nonumber 83 | y_{n+1}&=y_{n}+h f\left(x_{n}, y_{n}\right)\\ &+\frac{h^{2}}{2}\left[\frac{\partial f}{\partial x}+f \frac{\partial f}{\partial y}\right]\left(x_{n}, y_{n}\right) 84 | \label{taylor} 85 | \end{align} 86 | 87 | 如此构造下去,可得到三阶方法以及更高阶的方法,但是该类方法需要计算很多偏导数,并不实用。 88 | 89 | \end{subsubsection} 90 | 91 | \begin{subsubsection}{Runge-Kutta 方法} 92 | 93 | Runge-Kutta 方法采用了不同点上函数值的不同组合来提高精度同时避免函数 $f$ 的偏导数的计算。其一般形式为 94 | 95 | $$y_{n+1}=y_{n}+h \varphi\left(x_{n}, y_{n} ; h\right)$$ $$\varphi\left(x_{n}, y_{n} ; h\right)=\sum_{i=1}^{s} b_{i} k_{i}$$ $$k_{i}=f\left(x_{n}+c_{i} h, y_{n}+h \sum_{j=1}^{s} a_{i j} k_{j}\right)$$ $$c_{i}=\sum_{j=1}^{s} a_{i j}, \quad i=1,2, \cdots, s$$ 96 | 97 | 例如,在二级方法中,将 $k_2$ 进行 Taylor 展开,并将 $k_1, k_2$ 代入 $\varphi$,要求 $\varphi$ 的前三项与公式 \ref{taylor} 中的增量函数相等,即可解得 $a, b, c$ (详见课本 P361) 98 | 99 | \end{subsubsection} 100 | 101 | \begin{subsubsection}{古典四级四阶 Runge-Kutta 方法} 102 | 103 | 将 RK 方法用 RK 表描述 $$ \begin{array}{c|c}{c} & {A} \\ \hline & {b^{\top}}\end{array} $$ 104 | 105 | 古典四级四阶 Runge-Kutta 方法对应的 RK 表为 $$ 106 | \begin{array}{c|cccc}{0} & {} & {} & {} & {} \\ {\frac{1}{2}} & {\frac{1}{2}} & {} & {} & {} \\ 107 | {\frac{1}{2}} & {0} & {\frac{1}{2}} & {} & {} \\ 108 | {1} & {0} & {0} & {1} & {} \\ \hline 109 | {} & {1\over 6} & {1\over 3} & {1\over 3} & {1\over 6} \end{array} 110 | $$ 具体计算格式 $$ 111 | \left\{\begin{array}{l}{y_{n+1}=y_{n}+\frac{1}{6} h\left(k_{1}+2 k_{2}+2 k_{3}+k_{4}\right)} \\ {k_{1}=f\left(x_{n}, y_{n}\right)} \\ {k_{2}=f\left(x_{n}+\frac{1}{2} h, y_{n}+\frac{1}{2} h k_{1}\right)} \\ {k_{3}=f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{1}{2} h k_{2}\right)} \\ {k_{4}=f\left(x_{n}+h, y_{n}+h k_{3}\right)}\end{array}\right. $$ 112 | 113 | \end{subsubsection} 114 | 115 | \end{subsection} 116 | 117 | \begin{subsection}{算法实现} 118 | 119 | 古典四级四阶 Runge-Kutta 方法的 MATLAB 实现如下: 120 | 121 | \begin{lstlisting}[language=Matlab] 122 | function y = myRungeKutta44(f, y0, a, b, h) 123 | % 古典四级四阶 Runge-Kutta 方法 124 | % 求解微分方程 dy/dx = f(x, y), x in [a,b]; y(a) = y0 125 | % h 为步长 126 | n = floor((b-a)/h); 127 | x = a + h*(0:n); 128 | y = y0; 129 | yn = y0; 130 | for i = 1:n 131 | xn = x(i); 132 | k1 = f(xn, yn); 133 | k2 = f(xn + h/2, yn + h/2*k1); 134 | k3 = f(xn + h/2, yn + h/2*k2); 135 | k4 = f(xn + h, yn + h*k3); 136 | yn1 = yn + h/6*(k1+2*k2+2*k3+k4); 137 | y = [y yn1]; yn = yn1; 138 | end 139 | end 140 | \end{lstlisting} 141 | 142 | \end{subsection} 143 | 144 | \end{section} 145 | 146 | \begin{section}{隐式二级四阶 Runge-Kutta 方法(Gauss 方法)} 147 | 148 | \begin{subsection}{算法原理} 149 | 150 | \begin{subsubsection}{隐式二级四阶 Runge-Kutta 方法} 151 | 152 | 隐式二级四阶 Runge-Kutta 方法对应的 RK 表为 $$\begin{array}{c|cc}{\frac{1}{2}-\frac{\sqrt{3}}{6}} & {\frac{1}{4}} & {\frac{1}{4}-\frac{\sqrt{3}}{6}} \\ {\frac{1}{2}+\frac{\sqrt{3}}{6}} & {\frac{1}{4}+\frac{\sqrt{3}}{6}} & {\frac{1}{4}} \\ \hline & {\frac{1}{2}} & {\frac{1}{2}}\end{array}$$ 具体计算格式 $$\begin{array}{l}{y_{n+1}=y_{n}+h\left(\frac{1}{2} k_{1}+\frac{1}{2} k_{2}\right)} \\ {k_{1}=f\left(x_{n}+\left(\frac{1}{2}-\frac{\sqrt{3}}{6}\right) h, y_{n}+\frac{1}{4} h k_{1}+\left(\frac{1}{4}-\frac{\sqrt{3}}{6}\right) h k_{2}\right)} \\ {k_{2}=f\left(x_{n}+\left(\frac{1}{2}+\frac{\sqrt{3}}{6}\right) h, y_{n}+\left(\frac{1}{4}+\frac{\sqrt{3}}{6}\right) h k_{1}+\frac{1}{4} h k_{2}\right)}\end{array}$$ 153 | 154 | 155 | \end{subsubsection} 156 | 157 | \begin{subsubsection}{隐式方法的迭代计算} 158 | 159 | 可用迭代的方法求解隐式方法,具体地,先给出 $k_1, k_2$ 的近似值 $k_1^{(0)}, k_2^{(0)}$,然后用显式迭代 $$\begin{array}{l}{k_{1}^{(s+1)}=f\left(x_{n}+\left(\frac{1}{2}-\frac{\sqrt{3}}{6}\right) h, y_{n}+\frac{1}{4} h k_{1}^{(s)}+\left(\frac{1}{4}-\frac{\sqrt{3}}{6}\right) h k_{2}^{(s)}\right)} \\ {k_{2}^{(s+1)}=f\left(x_{n}+\left(\frac{1}{2}+\frac{\sqrt{3}}{6}\right) h, y_{n}+\left(\frac{1}{4}+\frac{\sqrt{3}}{6}\right) h k_{1}^{(s)}+\frac{1}{4} h k_{2}^{(s)}\right)}\end{array}$$ 直至 $||k_1^{(s)} -k_1^{(s+1)}||<\varepsilon, ||k_2^{(s)} -k_2^{(s+1)}||<\varepsilon$ 160 | 161 | 该方法可由 Gauss 求积公式导出,因此也称 Gauss 方法。 162 | 163 | \end{subsubsection} 164 | 165 | \end{subsection} 166 | 167 | \begin{subsection}{算法实现} 168 | 169 | 隐式二级四阶 Runge-Kutta 方法的 MATLAB 实现如下: 170 | 171 | \begin{lstlisting}[language=Matlab] 172 | function y = myRungeKutta24(f, y0, a, b, h, eps) 173 | % 隐式二级四阶 Runge-Kutta 方法 174 | % 求解微分方程 dy/dx = f(x, y), x in [a,b]; y(a) = y0 175 | % h 为步长 176 | c1 = 1/2-sqrt(3)/6; c2 = 1/2+sqrt(3)/6; 177 | b1 = 1/2; b2 = 1/2; 178 | a11 = 1/4; a12 = 1/4-sqrt(3)/6; 179 | a21 = 1/4+sqrt(3)/6; a22 = 1/4; 180 | 181 | n = floor((b-a)/h); 182 | x = a + h*(0:n); 183 | y = y0; 184 | yn = y0; 185 | for i = 1:n 186 | xn = x(i); 187 | k1 = f(xn, yn); k2 = k1; 188 | while true % 迭代 189 | new_k1 = f(xn+c1*h, yn + a11*h*k1 + a12*h*k2); 190 | new_k2 = f(xn+c2*h, yn + a21*h*k1 + a22*h*k2); 191 | if (max_error(k1, new_k1)< eps && max_error(k2, new_k2)< eps) 192 | break 193 | end 194 | k1 = new_k1; k2 = new_k2; 195 | end 196 | yn1 = yn + h*(b1*k1+b2*k2); 197 | y = [y yn1]; yn = yn1; 198 | end 199 | end 200 | \end{lstlisting} 201 | 202 | \end{subsection} 203 | 204 | \end{section} 205 | 206 | \begin{section}{计算结果与方法比较} 207 | 208 | \begin{subsection}{误差} 209 | 210 | 选取步长 $h=0.001$ ,隐式二级四阶 RK 方法中的 $eps = 10^{-7}$,以上两种方法的计算结果和误差见表 \ref{error_44} 和表 \ref{error_24}。 211 | 212 | 可以看到两种方法都能得到较精确的数值解,但精度有差异,隐式二级四阶 RK 方法比古典四级四阶 RK 方法精度好。 213 | 214 | \end{subsection} 215 | 216 | \begin{subsection}{方法的阶和步长的影响} 217 | 218 | 以上实现的两种方法都是4阶方法,取隐式二级四阶 RK 方法中的 $eps = 10^{-12}$,修改不同的步长 $h$ 得到计算结果如表 \ref{error_h}。 219 | 220 | 其中平均误差定义为 $\text{mean}\{|y_n - y(x_n)|\}, {n = 0,1,\cdots}$,最大误差定义为 $\max\{|y_n - y(x_n)|\}, {n = 0,1,\cdots}$ 221 | 222 | 可以看到,随着 $h$ 减少 1 个数量级,误差的大小减少约 4 个数量级,这符合方法是 4 阶的。 223 | 224 | \end{subsection} 225 | 226 | \end{section} 227 | 228 | \begin{section}{总结} 229 | 230 | 本次实验对古典四级四阶 RK 方法和隐式二级四阶 RK 方法进行了理论分析和编程计算,得到了一常微分方程初值问题的数值解,并比较了他们的计算误差。 231 | 232 | 本次实验还探究了步长 $h$ 对误差的影响,结果符合预期,与两种方法为四阶方法的事实相符。 233 | 234 | \end{section} 235 | 236 | \end{multicols} 237 | 238 | \begin{table*}[ht] 239 | \centering 240 | \caption{古典四级四阶 Runge-Kutta 方法的计算结果和误差} 241 | \label{error_44} 242 | \begin{tabular}{c|c|cc} 243 | \hline 244 | $x_n$ & $y(x_n)$ & $y_n$ (RK44) & $y(x_n)-y_n $ (误差) \\ \hline 245 | 5 & (-0.4967, -1.9938) & (-0.4907, -1.9938) & $(6.0163\times 10^{-3}, -3.0089\times 10^{-6})$\\ 246 | 10 & (-0.4931, -1.9863) & (-0.4931, -1.9863) & $(2.5503\times 10^{-5}, -1.2755\times 10^{-8})$\\ 247 | 15 & (-0.4894, -1.9788) & (-0.4894, -1.9788) & $(1.0525\times 10^{-7}, -5.2636\times 10^{-11})$\\ 248 | 20 & (-0.4857, -1.9714) & (-0.4857, -1.9714) & $(4.3420\times 10^{-10}, -2.1672\times 10^{-13})$ 249 | \\ \hline 250 | \end{tabular} 251 | \end{table*} 252 | 253 | \begin{table*}[ht] 254 | \centering 255 | \caption{隐式二级四阶 Runge-Kutta 方法的计算结果和误差} 256 | \label{error_24} 257 | \begin{tabular}{c|c|cc} 258 | \hline 259 | $x_n$ & $y(x_n)$ & $y_n$ (RK24) & $y(x_n)-y_n $ (误差) \\ \hline 260 | 5 & (-0.4967, -1.9938) & (-0.4967, -1.9938) & $(4.0484\times 10^{-5}, -2.0247\times 10^{-8})$ \\ 261 | 10 & (-0.4931, -1.9863) & (-0.4931, -1.9863) & $(4.7797\times 10^{-9}, -2.3901\times 10^{-12})$ \\ 262 | 15 & (-0.4894, -1.9788) & (-0.4894, -1.9788) & $(3.1969\times 10^{-12}, 1.3989\times 10^{-14})$ \\ 263 | 20 & (-0.4857, -1.9714) & (-0.4857, -1.9714) & $(1.2546\times 10^{-14}, 5.4401\times 10^{-14})$ \\ \hline 264 | \end{tabular} 265 | \end{table*} 266 | 267 | \begin{table*}[ht] 268 | \centering 269 | \caption{步长 $h$ 对误差的影响} 270 | \label{error_h} 271 | \begin{tabular}{c|cc|cc} 272 | \hline 273 | $h$ & 平均误差(RK44) & 最大误差(RK44) & 平均误差(RK24) & 最大误差(RK24) \\ \hline 274 | $10^{-3}$ & $4.300212\times 10^{-6}$ & $9.909147\times 10^{-2}$ & $1.367054\times 10^{-7}$ & $3.763211\times 10^{-3}$ \\ 275 | $10^{-4}$ & $9.826336\times 10^{-11}$ & $2.900773\times 10^{-6}$ & $1.395697\times 10^{-11}$ & $4.100364\times 10^{-7}$ \\ 276 | $10^{-5}$ & $1.551279\times 10^{-14}$ & $2.495640\times 10^{-10}$ & $8.662294\times 10^{-14}$ & $4.090728\times 10^{-11}$ \\ \hline 277 | \end{tabular} 278 | \end{table*} 279 | 280 | %\bibliographystyle{unsrt} 281 | %\bibliography{ref.bib} 282 | 283 | %\begin{thebibliography}{99} %参考文献开始 284 | % \bibitem{ml}周志华. 机器学习[M]. 清华大学出版社, 2016. 285 | %\end{thebibliography} 286 | 287 | \end{document} 288 | 289 | -------------------------------------------------------------------------------- /practice-ode/problem/practice-ode.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-ode/problem/practice-ode.pdf -------------------------------------------------------------------------------- /practice-ode/src/ode/main.m: -------------------------------------------------------------------------------- 1 | a = 0; b = 20; h = 0.00001; 2 | y0 = [0; -2]; 3 | n = floor((b-a)/h); 4 | 5 | x = a + h*(0:n); 6 | y_true = sol(x); 7 | 8 | y_44 = myRungeKutta44(@f, y0, a, b, h); 9 | y_24 = myRungeKutta24(@f, y0, a, b, h, 1e-12); 10 | 11 | fprintf('max_ae y_44 %e\n', max_error(y_44, y_true)); 12 | fprintf('max_ae y_24 %e\n', max_error(y_24, y_true)); 13 | 14 | fprintf('mae y_44 %e\n', mae(y_44 - y_true)); 15 | fprintf('mae y_24 %e\n', mae(y_24 - y_true)); 16 | 17 | print_y(y_true, a, b, 4, 'y_true'); 18 | print_y(y_44, a, b, 4, 'y_44'); 19 | print_y(y_44-y_true, a, b, 4, 'y_44 - y_true'); 20 | print_y(y_24, a, b, 4, 'y_24'); 21 | print_y(y_24-y_true, a, b, 4, 'y_24 - y_true'); 22 | 23 | function res = f(x,y) 24 | u = y(1); v = y(2); 25 | du = -2000*u + 999.75*v + 1000.25; 26 | dv = u - v; 27 | res = [du; dv]; 28 | end 29 | 30 | function y = sol(x) 31 | u = - 1.499875*exp(-0.5*x) + 0.499875*exp(-2000.5*x) + 1; 32 | v = - 2.99975*exp(-0.5*x) - 0.00025*exp(-2000.5*x) + 1; 33 | y = [u; v]; 34 | end 35 | 36 | function print_y(y, a, b, n, label) 37 | disp(label); 38 | res = y(:, a+(b-a)/n); 39 | for i = 2:n 40 | res = [res, y(:, a+(b-a)*i/n)]; 41 | end 42 | disp(res) 43 | end -------------------------------------------------------------------------------- /practice-ode/src/ode/max_error.m: -------------------------------------------------------------------------------- 1 | function r = max_error(y1, y2) 2 | % 最大绝对误差 3 | A = abs(y1-y2); 4 | r = max(reshape(A,numel(A),1)); 5 | end 6 | -------------------------------------------------------------------------------- /practice-ode/src/ode/myRungeKutta24.m: -------------------------------------------------------------------------------- 1 | function y = myRungeKutta24(f, y0, a, b, h, eps) 2 | % 隐式二级四阶 Runge-Kutta 方法 3 | % 求解微分方程 dy/dx = f(x, y), x in [a,b]; y(a) = y0 4 | % h 为步长 5 | 6 | c1 = 1/2-sqrt(3)/6; c2 = 1/2+sqrt(3)/6; 7 | b1 = 1/2; b2 = 1/2; 8 | a11 = 1/4; a12 = 1/4-sqrt(3)/6; 9 | a21 = 1/4+sqrt(3)/6; a22 = 1/4; 10 | 11 | n = floor((b-a)/h); 12 | x = a + h*(0:n); 13 | y = y0; 14 | yn = y0; 15 | for i = 1:n 16 | xn = x(i); 17 | k1 = f(xn, yn); k2 = k1; 18 | while true % 迭代 19 | new_k1 = f(xn+c1*h, yn + a11*h*k1 + a12*h*k2); 20 | new_k2 = f(xn+c2*h, yn + a21*h*k1 + a22*h*k2); 21 | if (max_error(k1, new_k1)< eps && max_error(k2, new_k2)< eps) 22 | break 23 | end 24 | k1 = new_k1; k2 = new_k2; 25 | end 26 | yn1 = yn + h*(b1*k1+b2*k2); 27 | y = [y yn1]; yn = yn1; 28 | end 29 | 30 | end 31 | 32 | -------------------------------------------------------------------------------- /practice-ode/src/ode/myRungeKutta44.m: -------------------------------------------------------------------------------- 1 | function y = myRungeKutta44(f, y0, a, b, h) 2 | % 古典四级四阶 Runge-Kutta 方法 3 | % 求解微分方程 dy/dx = f(x, y), x in [a,b]; y(a) = y0 4 | % h 为步长 5 | 6 | n = floor((b-a)/h); 7 | x = a + h*(0:n); 8 | y = y0; 9 | yn = y0; 10 | for i = 1:n 11 | xn = x(i); 12 | k1 = f(xn, yn); 13 | k2 = f(xn + h/2, yn + h/2*k1); 14 | k3 = f(xn + h/2, yn + h/2*k2); 15 | k4 = f(xn + h, yn + h*k3); 16 | yn1 = yn + h/6*(k1+2*k2+2*k3+k4); 17 | y = [y yn1]; yn = yn1; 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /practice-quad/doc/img/gauss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-quad/doc/img/gauss.png -------------------------------------------------------------------------------- /practice-quad/doc/img/romberg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-quad/doc/img/romberg.png -------------------------------------------------------------------------------- /practice-quad/doc/practice-quad-doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Manchery/numerical-analysis-practice/91bdbca5461221d5580bd63610bdafebf730b7c6/practice-quad/doc/practice-quad-doc.pdf -------------------------------------------------------------------------------- /practice-quad/doc/practice-quad-doc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{article} 2 | 3 | %中文环境设置 4 | \usepackage{xeCJK} 5 | \usepackage{indentfirst} 6 | \setlength{\parindent}{2em} 7 | \usepackage{enumitem} 8 | 9 | \usepackage{abstract} 10 | \renewcommand{\abstractname}{摘要} 11 | \providecommand{\keywords}[1]{\textbf{\textit{关键词}} #1} 12 | 13 | \setCJKmainfont{STSong} % 中文主字体设置 14 | 15 | \usepackage[colorlinks,linkcolor=blue, citecolor=blue]{hyperref} 16 | 17 | % 常用宏包 18 | \usepackage{float} 19 | \usepackage{stfloats} 20 | \usepackage{graphicx} 21 | \usepackage{color} 22 | \usepackage{supertabular} 23 | 24 | % 代码环境设置 25 | \usepackage{listings} 26 | \lstset{ 27 | columns=fullflexible, 28 | frame=single, 29 | breaklines=true, 30 | } 31 | \definecolor{lightgray}{gray}{0.9} 32 | \newcommand{\inlinecode}[2]{\colorbox{lightgray}{\lstinline[language=#1]$#2$}} 33 | 34 | % 页面段落设置 35 | \usepackage{multicol} 36 | \usepackage{geometry} 37 | \geometry{left=3.18cm, right=3.18cm, top=2.54cm, bottom=2.54cm} 38 | \linespread{1.3} 39 | %\setlength{\parskip}{0.5em} 40 | 41 | % 数学环境设置 42 | \usepackage{amsmath} 43 | \usepackage{amssymb} 44 | \usepackage{amsthm} 45 | \usepackage{amsfonts} 46 | \usepackage{mathrsfs} 47 | \newtheorem{myDef}{Definition} 48 | \newtheorem{myThm}{Theorem} 49 | \newtheorem{myProp}{Property} 50 | 51 | \begin{document} 52 | \title{数值积分与数值微分\ 实验题} 53 | \author{吴佳龙 2018013418} 54 | \date{} 55 | \maketitle 56 | 57 | \begin{abstract} 58 | 结合理论分析和编程计算,运用不同方法计算了一函数的数值积分。运用的方法分别为:五点 Gauss-Legendre 求积公式的复合求积公式和 Romberg 求积方法。 59 | \end{abstract} 60 | 61 | %\keywords{one, two, three, four} 62 | 63 | \begin{multicols}{2} 64 | 65 | \begin{section}{问题} 66 | 67 | 用不同的数值积分方法计算 $$I(f)=\int_{1}^{3} f(x) d x=\int_{1}^{3} \frac{1}{x^{2}} \sin \frac{2 \pi}{x} d x$$ 准确解为:$I(f)=-0.238732414637843 \cdots$ 68 | 69 | \begin{enumerate} 70 | \item 把 $[1,3]$ 分成 $4$ 个子区间,用五点 Gauss-Legendre 求积公式的复合求积公式计算。 71 | \item 用 Romberg 求积方法计算积分,取 $\varepsilon = 10^{-7}$,并与第一种办法比较。 72 | \end{enumerate} 73 | 74 | \end{section} 75 | 76 | \begin{section}{五点 Gauss-Legendre 求积公式的复合求积公式} 77 | 78 | \begin{subsection}{算法原理} 79 | 80 | \begin{subsubsection}{Gauss 求积公式} 81 | 82 | Newton-Cotes 求积公式 $$\int_{a}^{b} f(x) \mathrm{d} x=(b-a) \sum_{i=1}^{n} c_{i k}^{(n)} f\left(x_{i}^{(n)}\right)+E_{n}(f)$$ 取等距的求积节点 $x_k^{(n)}$。对于 $n+1$ 个等距节点的插值型求积公式,其代数精度至多为 $n+1$。 83 | 84 | 考虑适当选取 $n+1$ 个节点的位置,使得代数精度从 $n $ 或 $n+1$ 增加到 $2n+1$。 85 | 86 | Newton-Cotes 求积公式中余项为 $$E(f)=\frac{1}{(n+1) !} \int_{a}^{b} \rho(x) f^{(n+1)}(\xi(x)) \omega_{n+1}(x) \mathrm{d} x$$ 若要对 $f \in \mathscr{P}_{2 n+1}\Rightarrow f^{(n+1)} \in \mathscr{P}_{n}$ 都有 $E(f)=0$,可取 $\omega_{n+1}(x)$ 为 $[a,b]$ 上的 $n+1$ 次正交多项式,即取插值节点为 $[a,b]$ 上 $n+1$ 次正交多项式的零点。 87 | 88 | 有以下定理: 89 | 90 | \begin{myThm} 91 | 92 | 插值型求积公式具有 $2n+1$ 次代数精度的充分必要条件是求积节点是 $[a,b]$ 上权函数为 $\rho$ 的 $n+1$ 次正交多项式的零点。 93 | 94 | \end{myThm} 95 | 96 | 97 | 该求积公式称为 Gauss 求积公式,相应的求积节点为Gauss 点。 98 | 99 | 与 Newton-Cotes 公式不同,Gauss 求积公式的求积系数都是正数,从而 Gauss 求积是数值稳定的。另外,还可证明,Gauss 求积公式有收敛性: $$\lim _{n \rightarrow \infty} \sum_{k=0}^{n} A_{k}^{(n)} f\left(x_{k}^{(n)}\right) =\int_{a}^{b} \rho(x) f(x) \mathrm{d} x $$ 100 | 101 | \end{subsubsection} 102 | 103 | \begin{subsubsection}{Gauss-Legendre 求积公式} 104 | 105 | 在区间 $[-1,1]$ 上取权函数 $\rho(x) = 1$ 对应的 Gauss 求积公式称为 Gauss-Legendre 求积公式。 106 | 107 | 其误差为 108 | 109 | $$E_{n}(f)=\frac{2^{2 n+3}[(n+1) !]^{4}}{(2 n+3)[(2 n+2) !]^{3}} f^{(2 n+2)}(\eta)$$ 110 | 111 | 取 $n=4$,五点 Gauss-Legendre 求积公式的 Gauss点和求积系数如下: 112 | 113 | \begin{table}[H] 114 | \centering 115 | \begin{tabular}{c|c} 116 | \hline 117 | \multicolumn{1}{c|}{$x_k$} & \multicolumn{1}{c}{$A_k$} 118 | \\ \hline 119 | -0.9061798459 & 0.2369268851 \\ 120 | -0.5384693101 & 0.4786286705 \\ 121 | 0 & 0.5688888889 \\ 122 | 0.5384693101 & 0.4786286705 \\ 123 | 0.9061798459 & 0.2369268851 \\ 124 | \hline 125 | \end{tabular} 126 | \end{table} 127 | 128 | 对一般区间 $[a,b]$,将其变换到 $[-1,1]$,有 129 | 130 | $$\int_{a}^{b} f(x) \mathrm{d} x=\frac{b-a}{2} \int_{-1}^{1} f\left[\frac{a+b}{2}+\frac{b-a}{2} t\right] \mathrm{d} t$$ 131 | 132 | \end{subsubsection} 133 | 134 | \begin{subsubsection}{复合求积公式} 135 | 136 | 为提高定积分的精度,将整个积分区间分成若干子区间,然后分别采用低阶求积公式。这种积分方法称为复合求积公式。 137 | 138 | \end{subsubsection} 139 | 140 | \end{subsection} 141 | 142 | \begin{subsection}{算法实现} 143 | 144 | 五点 Gauss-Legendre 求积公式的 MATLAB 实现如下: 145 | 146 | \begin{lstlisting}[language=Matlab] 147 | function I = myGaussLegendre(f,a,b) 148 | % 五点 Gauss-Legendre 求积公式求 f 在 [a,b] 上积分 149 | xk = [-0.9061798459, -0.5384693101, 0, 0.5384693101, 0.9061798459]; 150 | Ak = [0.2369268851, 0.4786286705, 0.5688888889, 0.4786286705, 0.2369268851]; 151 | I = (b-a)/2*sum(f((a+b)/2+(b-a)/2*xk).*Ak); 152 | end 153 | \end{lstlisting} 154 | 155 | 复合的五点 Gauss-Legendre 求积公式的 MATLAB 实现如下: 156 | 157 | \begin{lstlisting}[language=Matlab] 158 | function I = myCompositeGaussLegendre(f,a,b,n) 159 | % 五点 Gauss-Legendre 求积公式复合求 f 在 [a,b] 上积分 160 | % 将 [a,b] 等分成 n 段 161 | I = 0; 162 | for i=0:n-1 163 | ai = a+(b-a)/n*i; 164 | bi = a+(b-a)/n*(i+1); 165 | I = I + myGaussLegendre(f,ai,bi); 166 | end 167 | end 168 | \end{lstlisting} 169 | 170 | 171 | \end{subsection} 172 | 173 | \begin{subsection}{计算结果} 174 | 175 | 调用函数 \inlinecode{Matlab}{myCompositeGaussLegendre(@f,1,3,4)},得到数值解为 $$I(f)\approx -0.238732340355842$$ 176 | 177 | \end{subsection} 178 | 179 | \end{section} 180 | 181 | \begin{section}{Romberg 求积方法} 182 | 183 | \begin{subsection}{算法原理} 184 | 185 | \begin{subsubsection}{Euler-Maclaurin 公式} 186 | 187 | 令 $B_k$ 为 Bernoulli 数,有Euler-Maclaurin 求和公式 188 | 189 | \begin{align} 190 | \nonumber 191 | &\int_{a}^{b} f(x) \mathrm{d} x-T_{n}(f) = \\ 192 | \nonumber 193 | &-\sum_{i=1}^{m} \frac{B_{2 l}}{(2 l) !}\left[f^{(2 l-1)}(b)-f^{(2 l-1)}(a)\right] h^{2 l}+r_{m+1} 194 | \end{align} 195 | 196 | 其中 $T_n(f)$ 为复合梯形求积公式,$r_{m+1}$ 为余项。 197 | 198 | \end{subsubsection} 199 | 200 | \begin{subsubsection}{Richardason 外推方法} 201 | 202 | 用 $(T_1f)(h)$ 来表示 $T_n(f)$,由 Euler-Maclaurin 公式 $$I(f)-(T_1f)(h) = \alpha_2h^2 + O(h^4)$$ 将 $h$ 缩小一半,有 $$I(f)-(T_1f)({h\over 2}) = \alpha_2({h\over 2})^2+O(h^4)$$ 令 $$\left(T_{2} f\right)(h)=\frac{4\left(T_{1} f\right)\left(\frac{h}{2}\right)-\left(T_{1} f\right)(h)}{3}$$ 则 $$I(f)-(T_2f)(h) = O(h^4)$$ 将误差从 $O(h^2)$ 提高到了 $O(h^4)$。 203 | 204 | 这种方法称为 Richardason 外推方法,详细描述与证明见课本。 205 | 206 | \end{subsubsection} 207 | 208 | \begin{subsubsection}{Romberg 求积方法} 209 | 210 | 将 Euler-Maclaurin 公式 和 Richardason 外推方法结合,在外推算法中取 $q={1\over 2}, p_k = 2k$,得到 Romberg 求积方法。 211 | 212 | \begin{align} 213 | \nonumber 214 | \left(T_{1} f\right)(h)&=\frac{h}{2} \sum_{m=1}^{n}\left[f\left(x_{m-1}\right)+f\left(x_{m}\right)\right] \\ 215 | \nonumber 216 | \left(T_{j+1} f\right)(h)&=\frac{4^{j}\left(T_{j} f\right)\left(\frac{h}{2}\right)-\left(T_{j} f\right)(h)}{4^{j}-1} 217 | \end{align} 218 | 误差 $$\int_{a}^{b} f(x) d x - \left(T_{j+1} f\right)(h)=O\left(h^{2(j+1)}\right)$$ 219 | 引入记号 $$T_{j}^{k} f=\left(T_{j} f\right)\left(\frac{h}{2^{k}}\right)$$上式写作 $$T_{j+1}^{k} f=\frac{4^{j} T_{j}^{k+1} f-T_{j}^{k} f}{4^{j}-1}$$ 220 | 221 | Romberg 求积方法的机器实现描述如下: 222 | 223 | \begin{enumerate} 224 | \item 令 $l=1$, 求 $T_1^0 f$ 225 | \item 求 $T_1^l f$,并递推得到 $T_{l+1}^0 f$ 226 | \item 若 $\left|T_{l}^{0} f-T_{l+1}^{0} f\right|<\varepsilon$ 则结束,否则 $l=l+1$,转 2 227 | \end{enumerate} 228 | 229 | \end{subsubsection} 230 | 231 | \end{subsection} 232 | 233 | \begin{subsection}{算法实现} 234 | 235 | Romberg 求积方法的 MATLAB 实现如下: 236 | 237 | \begin{lstlisting}[language=Matlab] 238 | function I = myRomberg(f,a,b,eps) 239 | % Romberg 求积方法, f 在 [a,b] 上积分 240 | % eps 为指定的停止时的误差控制 241 | T = (b-a)/2*(f(a)+f(b)); 242 | l = 2; 243 | while true 244 | T = [T, zeros(l-1,1); zeros(1,l)]; 245 | n = 2^(l-1); 246 | T(l,1) = (f(a)+f(b)+2*sum(f(a+(b-a)/n*(1:n-1))))*(b-a)/n/2; 247 | for j = 2:l 248 | T(l,j) = (4^(j-1)*T(l,j-1)-T(l-1,j-1)) / (4^(j-1)-1); 249 | end 250 | if abs(T(l,l)-T(l-1,l-1))