You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
568tools/tools/rusty-book/algos/math/linear-algebra.html

343 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE HTML>
<html lang="zh-CN" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>线性代数 - Rusty Book(锈书)</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../../highlight.css">
<link rel="stylesheet" href="../../tomorrow-night.css">
<link rel="stylesheet" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../theme/style1.css">
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "../../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../../about.html">Rusty Book</a></li><li class="chapter-item expanded affix "><li class="part-title">Awesome</li><li class="spacer"></li><li class="chapter-item expanded "><a href="../../daily-dev.html">日常开发常用库</a></li><li class="chapter-item expanded "><a href="../../superstar.html">Rust 明星项目</a></li><li class="chapter-item expanded "><a href="../../empowering-js.html">使用 Rust 增强 JS</a></li><li class="chapter-item expanded "><a href="../../games.html">Rust开发的游戏</a></li><li class="chapter-item expanded "><a href="../../gamedev.html">游戏引擎</a></li><li class="chapter-item expanded affix "><li class="part-title">Awesome + Cookbook</li><li class="spacer"></li><li class="chapter-item expanded "><a href="../../algos/awesome.html">实用算法</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../algos/randomness.html">生成随机值</a></li><li class="chapter-item expanded "><a href="../../algos/sorting.html">Vec 排序</a></li><li class="chapter-item expanded "><div>压缩算法</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../algos/compression/tar.html">使用.tar包</a></li></ol></li><li class="chapter-item expanded "><div>密码学</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../algos/cryptography/hashing.html">哈希</a></li><li class="chapter-item "><a href="../../algos/cryptography/encryption.html">加密</a></li></ol></li><li class="chapter-item expanded "><div>数学计算</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../algos/math/linear-algebra.html" class="active">线性代数</a></li><li class="chapter-item "><a href="../../algos/math/trigonometry.html">三角函数</a></li><li class="chapter-item "><a href="../../algos/math/complex.html">复数</a></li><li class="chapter-item "><a href="../../algos/math/statistics.html">统计学</a></li><li class="chapter-item "><a href="../../algos/math/misc.html">杂项</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../datastructures/awesome.html">数据结构</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../datastructures/bitfield.html">位字段</a></li></ol></li><li class="chapter-item expanded "><a href="../../cmd/awesome.html">命令行</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../cmd/parsing.html">参数解析</a></li><li class="chapter-item expanded "><a href="../../cmd/ansi.html">终端输出格式化</a></li></ol></li><li class="chapter-item expanded "><a href="../../os/awesome.html">操作系统</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../os/processor.html">处理器</a></li><li class="chapter-item expanded "><a href="../../os/command.html">调用系统命令</a></li></ol></li><li class="chapter-item expanded "><div>并发</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../cocurrency/threads.html">线程</a></li><li class="chapter-item expanded "><a href="../../cocurrency/parallel.html">使用rayon并行处理数据</a></li></ol></li><li class="chapter-item expanded "><div>数据库</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../database/sqlite.html">SQLite</a></li><li class="chapter-item expanded "><a href="../../database/postgres.html">Postgres</a></li></ol></li><li class="chapter-item expanded "><div>日期和时间</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../datetime/duration.html">时间计算和转换</a></li><li class="chapter-item expanded "><a href="../../datetime/parsing.html">解析和显示</a></li></ol></li><li class="chapter-item expanded "><div>开发者工具</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../devtools/log.html">日志</a></li><li class="chapter-item expanded "><a href="../../devtools/config-log.html">配置日志</a></li><li class="chapter-item expanded "><a href="../../devtools/version.html">版本号</a></li><li class="chapter-item expanded "><a href="../../devtools/build-tools.html">构建时工具</a></li></ol></li><li class="chapter-item expanded "><div>编解码</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../encoding/strings.html">字符编码</a></li><li class="chapter-item expanded "><a href="../../encoding/csv.html">CSV</a></li><li class="chapter-item expanded "><a href="../../encoding/structured.html">结构化数据</a></li></ol></li><li class="chapter-item expanded "><div>错误处理</div></li><li class="chapter-item expanded "><div>文件操作</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../files/read-write.html">文件读写</a></li><li class="chapter-item expanded "><a href="../../files/dir.html">目录访问</a></li></ol></li><li class="chapter-item expanded "><div>内存管理</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../memory/global-vars.html">全局变量</a></li></ol></li><li class="chapter-item expanded "><div>网络协议</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../protocols/tcpip.html">TCP/IP</a></li></ol></li><li class="chapter-item expanded "><div>文本处理</div><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../text/regex.html">正则表达式</a></li><li class="chapter-item expanded "><a href="../../text/string.html">字符串解析</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rusty Book(锈书)</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/studyrs/rusty-book" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/studyrs/rusty-book/edit/main/src/algos/math/linear-algebra.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<!-- Page table of contents -->
<div class="sidetoc"><nav class="pagetoc"></nav></div>
<main>
<h1 id="线性代数"><a class="header" href="#线性代数">线性代数</a></h1>
<h3 id="矩阵相加"><a class="header" href="#矩阵相加">矩阵相加</a></h3>
<p>使用 <a href="https://docs.rs/ndarray/*/ndarray/fn.arr2.html">ndarray::arr2</a> 可以创建二阶矩阵,并计算它们的和。</p>
<pre><pre class="playground"><code class="language-rust editable edition2021">use ndarray::arr2;
fn main() {
let a = arr2(&amp;[[1, 2, 3],
[4, 5, 6]]);
let b = arr2(&amp;[[6, 5, 4],
[3, 2, 1]]);
// 借用 a 和 b求和后生成新的矩阵 sum
let sum = &amp;a + &amp;b;
println!(&quot;{}&quot;, a);
println!(&quot;+&quot;);
println!(&quot;{}&quot;, b);
println!(&quot;=&quot;);
println!(&quot;{}&quot;, sum);
}
</code></pre></pre>
<h3 id="矩阵相乘"><a class="header" href="#矩阵相乘">矩阵相乘</a></h3>
<p><a href="https://docs.rs/ndarray/0.15.4/ndarray/struct.ArrayBase.html#method.dot-1">ndarray::ArrayBase::dot</a> 可以用于计算矩阵乘法。</p>
<pre><pre class="playground"><code class="language-rust editable edition2021">use ndarray::arr2;
fn main() {
let a = arr2(&amp;[[1, 2, 3],
[4, 5, 6]]);
let b = arr2(&amp;[[6, 3],
[5, 2],
[4, 1]]);
println!(&quot;{}&quot;, a.dot(&amp;b));
}
</code></pre></pre>
<h3 id="标量向量矩阵相乘"><a class="header" href="#标量向量矩阵相乘">标量、向量、矩阵相乘</a></h3>
<p><code>ndarry</code>1 阶数组根据上下文既可以作为行向量也可以作为列向量。如果对你来说,这个行或列的方向很重要,可以考虑使用一行或一列的 2 阶数组来表示。</p>
<p>在下面例子中,由于 1 阶数组处于乘号的右边位置,因此 <code>dot</code> 会把它当成列向量来处理。</p>
<pre><pre class="playground"><code class="language-rust editable edition2021">use ndarray::{arr1, arr2, Array1};
fn main() {
let scalar = 4;
let vector = arr1(&amp;[1, 2, 3]);
let matrix = arr2(&amp;[[4, 5, 6],
[7, 8, 9]]);
let new_vector: Array1&lt;_&gt; = scalar * vector;
println!(&quot;{}&quot;, new_vector);
let new_matrix = matrix.dot(&amp;new_vector);
println!(&quot;{}&quot;, new_matrix);
}
</code></pre></pre>
<h3 id="向量比较"><a class="header" href="#向量比较">向量比较</a></h3>
<p>浮点数通常是不精确的,因此比较浮点数不是一件简单的事。<a href="https://docs.rs/approx/*/approx/index.html">approx</a> 提供的 <a href="https://docs.rs/approx/0.5.1/approx/macro.assert_abs_diff_eq.html">assert_abs_diff_eq!</a> 宏提供了方便的按元素比较的方式。为了使用 <code>approx</code> ,你需要在 <code>ndarray</code> 的依赖中开启相应的 feature例如<code>Cargo.toml</code> 中修改 <code>ndarray</code> 的依赖引入为 <code>ndarray = { version = &quot;0.13&quot;, features = [&quot;approx&quot;] }</code></p>
<pre><pre class="playground"><code class="language-rust editable edition2021">use approx::assert_abs_diff_eq;
use ndarray::Array;
fn main() {
let a = Array::from(vec![1., 2., 3., 4., 5.]);
let b = Array::from(vec![5., 4., 3., 2., 1.]);
let mut c = Array::from(vec![1., 2., 3., 4., 5.]);
let mut d = Array::from(vec![5., 4., 3., 2., 1.]);
// 消耗 a 和 b 的所有权
let z = a + b;
// 借用 c 和 d
let w = &amp;c + &amp;d;
assert_abs_diff_eq!(z, Array::from(vec![6., 6., 6., 6., 6.]));
println!(&quot;c = {}&quot;, c);
c[0] = 10.;
d[1] = 10.;
assert_abs_diff_eq!(w, Array::from(vec![6., 6., 6., 6., 6.]));
}
</code></pre></pre>
<h3 id="向量范数-norm-"><a class="header" href="#向量范数-norm-">向量范数( norm )</a></h3>
<p>需要注意的是 <code>Array</code><code>ArrayView</code> 都是 <code>ArrayBase</code> 的别名。因此一个更通用的参数应该是 <code>&amp;ArrayBase&lt;S, Ix1&gt; where S: Data</code>,特别是在你提供一个公共 API 给其它用户时,但由于咱们是内部使用,因此更精准的 <code>ArrayView1&lt;f64&gt;</code> 会更适合。</p>
<pre><pre class="playground"><code class="language-rust editable edition2021">use ndarray::{array, Array1, ArrayView1};
fn l1_norm(x: ArrayView1&lt;f64&gt;) -&gt; f64 {
x.fold(0., |acc, elem| acc + elem.abs())
}
fn l2_norm(x: ArrayView1&lt;f64&gt;) -&gt; f64 {
x.dot(&amp;x).sqrt()
}
fn normalize(mut x: Array1&lt;f64&gt;) -&gt; Array1&lt;f64&gt; {
let norm = l2_norm(x.view());
x.mapv_inplace(|e| e/norm);
x
}
fn main() {
let x = array![1., 2., 3., 4., 5.];
println!(&quot;||x||_2 = {}&quot;, l2_norm(x.view()));
println!(&quot;||x||_1 = {}&quot;, l1_norm(x.view()));
println!(&quot;Normalizing x yields {:?}&quot;, normalize(x));
}
</code></pre></pre>
<h3 id="矩阵的逆变换"><a class="header" href="#矩阵的逆变换">矩阵的逆变换</a></h3>
<p>例子中使用 <a href="https://docs.rs/nalgebra/*/nalgebra/base/type.Matrix3.html">nalgebra::Matrix3</a> 创建一个 3x3 的矩阵,然后尝试对其进行逆变换,获取一个逆矩阵。</p>
<pre><pre class="playground"><code class="language-rust editable edition2021">use nalgebra::Matrix3;
fn main() {
let m1 = Matrix3::new(2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 2.0, 1.0, 2.0);
println!(&quot;m1 = {}&quot;, m1);
match m1.try_inverse() {
Some(inv) =&gt; {
println!(&quot;The inverse of m1 is: {}&quot;, inv);
}
None =&gt; {
println!(&quot;m1 is not invertible!&quot;);
}
}
}
</code></pre></pre>
<h3 id="序列反序列化一个矩阵"><a class="header" href="#序列反序列化一个矩阵">序列/反序列化一个矩阵</a></h3>
<p>下面将展示如何将矩阵序列化为 JSON ,然后再反序列化为原矩阵。</p>
<pre><pre class="playground"><code class="language-rust editable edition2021">extern crate nalgebra;
extern crate serde_json;
use nalgebra::DMatrix;
fn main() -&gt; Result&lt;(), std::io::Error&gt; {
let row_slice: Vec&lt;i32&gt; = (1..5001).collect();
let matrix = DMatrix::from_row_slice(50, 100, &amp;row_slice);
// 序列化矩阵
let serialized_matrix = serde_json::to_string(&amp;matrix)?;
// 反序列化
let deserialized_matrix: DMatrix&lt;i32&gt; = serde_json::from_str(&amp;serialized_matrix)?;
// 验证反序列化后的矩阵跟原始矩阵相等
assert!(deserialized_matrix == matrix);
Ok(())
}
</code></pre></pre>
<div id="giscus-container"></div>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../algos/cryptography/encryption.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../../algos/math/trigonometry.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../algos/cryptography/encryption.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../../algos/math/trigonometry.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="../../ace.js" type="text/javascript" charset="utf-8"></script>
<script src="../../editor.js" type="text/javascript" charset="utf-8"></script>
<script src="../../mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="../../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="../../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="../../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="../../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="../../book.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
var pagePath = "algos/math/linear-algebra.md"
</script>
<!-- Custom JS scripts -->
<script type="text/javascript" src="../../assets/custom1.js"></script>
<script type="text/javascript" src="../../assets/bigPicture.js"></script>
</body>
</html>