编程学习线性代数04 - 向量数量积与夹角

Posted by zihengCat on 2018-03-28

前言

本文讲解向量的数量积与向量夹角,并通过编程实现。

向量数量积

两个向量的数量积(英语: Inner Products)在几何上可以表示为两向量的模长乘以两向量之间夹角的余弦值。向量数量积是一个标量。向量数量积的几何定义可以帮助我们寻找两向量之间的夹角,这个夹角我们一般指:将两向量移至共起点后,取较小的角度。

vector-inner-products

图1: 向量数量积的几何意义

$$ \overrightarrow{v} \cdot \overrightarrow{w} = \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert \cdot \cos(\theta) $$ $$ \begin{align} \theta &= \arccos( \frac{ \overrightarrow{v} \cdot \overrightarrow{w} } { \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert }) \\ &= \arccos( \frac{ 1 } { \lVert \overrightarrow{v} \rVert } \overrightarrow{v} \cdot \frac{ 1 } { \lVert \overrightarrow{w} \rVert } \overrightarrow{w} ) \end{align} $$

向量数量积的几何定义虽然直观明了,但是不好计算,我们再看看向量数量积的代数定义。向量数量积的代数定义指出:两个向量的数量积是两向量各对应维度数值乘积的累加和。这可以帮助我们快速计算出数量积的结果。

$$ \begin{align} \overrightarrow{a} \cdot \overrightarrow{b} &= \sum_{i=1}^{n}a_i \cdot b_i \\ &= a_{1} \cdot b_{1} + a_{2} \cdot b_{2} + ... + a_{n} \cdot b_{n} \end{align} $$ $$ \overrightarrow{v} \begin{bmatrix} a_{1} \\ a_{2} \\ ... \\ a_{n} \end{bmatrix} \cdot \overrightarrow{w} \begin{bmatrix} b_{1} \\ b_{2} \\ ... \\ b_{n} \end{bmatrix} = a_{1} \cdot b_{1} + a_{2} \cdot b_{2} + ... + a_{n} \cdot b_{n} $$

向量数量积的代数定义可以帮助我们快速计算出结果。下面我们来看看向量数量积的几个运算规律。

$$ \overrightarrow{v} \cdot \overrightarrow{w} = \overrightarrow{w} \cdot \overrightarrow{v} \\ (k \cdot \overrightarrow{v}) \cdot \overrightarrow{w} = \overrightarrow{v} \cdot (k \cdot \overrightarrow{w}) \\ c \cdot (\overrightarrow{v} + \overrightarrow{w}) = c \cdot \overrightarrow{v} + c \cdot \overrightarrow{w} $$

向量的方向余弦

这里我们补充一个方向预弦的概念。在三维直角坐标系中,向量与XYZ三个坐标轴形成的夹角称为方向角,该向量与坐标轴形成的余弦值被称为方向余弦。方向余弦的求法: 向量各个维度坐标值除以向量模长
还有一点,**向量方向余弦的平方和为$1$**。

$$ \overrightarrow{v} = \begin{bmatrix} v_{x} \\ v_{y} \\ v_{z} \end{bmatrix} $$ $$ \cos(\alpha) = \frac { v_{x}} {\Vert \overrightarrow{v} \Vert} \ \cos(\beta) = \frac { v_{y}} {\Vert \overrightarrow{v} \Vert} \ \cos(\gamma) = \frac { v_{z}} {\Vert \overrightarrow{v} \Vert} $$ $$ \cos^{2}(\alpha) + \cos^{2}(\beta) + \cos^{2}(\gamma) = 1 $$

向量数量积与向量夹角的关系

我们知道,$\cos(x)$函数的值域是$[-1, 1]$,再结合向量数量积的几何定义,我们就可以得到著名的柯西-施瓦茨不等式。该不等式在数学各领域都有非常广泛的应用。

$$ \overrightarrow{v} \cdot \overrightarrow{w} = \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert \cdot \cos(\theta) , \cos(\theta) \in \lbrack -1, 1 \rbrack $$ $$ - \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert \leq \overrightarrow{v} \cdot \overrightarrow{w} \leq \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert \\ \Updownarrow \\ \vert \overrightarrow{v} \cdot \overrightarrow{w} \vert \leq \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert $$

接下来,我们结合向量数量积的几何定义来考虑一下向量夹角与向量位置关系。我们设两个向量都不是零向量(数量积存在)。

$$ \overrightarrow{v} \cdot \overrightarrow{w} = \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert \cdot \cos(\theta) \\ \cos(\theta) \in \lbrack -1, 1 \rbrack , \overrightarrow{v} \not= \overrightarrow{0} , \overrightarrow{w} \not= \overrightarrow{0} $$
向量数量积关系 $\boldsymbol{\cos(\theta)}$ $\boldsymbol{\theta}$ 向量位置关系
$ \overrightarrow{v} \cdot \overrightarrow{w} = \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert $ $1$ $0$ 平行
$ \overrightarrow{v} \cdot \overrightarrow{w} = - \lVert \overrightarrow{v} \rVert \cdot \lVert \overrightarrow{w} \rVert $ $-1$ $\pi$ 相反
$ \overrightarrow{v} \cdot \overrightarrow{w} = 0 $ $0$ $\pi \over 2$ 正交
$ \overrightarrow{v} \cdot \overrightarrow{v} = {\lVert \overrightarrow{v} \rVert}^{2} $ $1$ $0$ 相同

表1: 向量数量积与向量夹角、向量位置关系

向量数量积的代码实现

在了解向量数量积的概念后,我们考虑它的代码实现。
根据向量数量积的代数定义,我们可以很容易的实现一个求向量数量积的方法。取出两个向量对应维度的数值,相乘求和即可。

...
    def dot(self, v):
        # 列表生成式
        return sum([ x * y for (x, y) in zip(self.coordinates, v.coordinates)])
...

代码清单: 向量数量积的代码实现(Python)

向量夹角的代码实现

接下来我们考虑向量夹角的代码实现。
根据向量数量积的代数定义,我们也可以容易得实现求向量夹角的方法。两向量点乘除以两向量模长乘积,再取反余弦即可。
这里我们还可以额外添加一个弧度转角度的功能。

...
    def angle_with(self, v, in_degrees = False):
        try:
            angle_in_radians = math.acos((self.dot(v)) /
                                         (self.magnitude() * v.magnitude()))
            if in_degrees:
                return angle_in_radians * 180.0 / math.pi
            else:
                return angle_in_radians
        except:
            print("Something error")
            return None
...

代码清单: 向量夹角的代码实现(Python)

相关测试代码

我们来写一些测试代码,看看我们新添加的方法是否可用。

def vector_dot_angle_test():
    v = Vector([0, 0, 1])
    w = Vector([0, 1, 0]
    print(v.dot(w))
    print(v.angle_with(w, True))
    print("-------------------")
    v = Vector([1, 1, 1])
    w = Vector([10, 10, 10])
    print(v.dot(w))
    print(v.angle_with(w))
    print("-------------------")
    v = Vector([2, 0])
    w = Vector([0, 8])
    print(v.dot(w))
    print(v.angle_with(w, True))
    print("-------------------")
    v = Vector([1, 0])
    w = Vector([-1, 0])
    print(v.dot(w))
    print(v.angle_with(w, True))

代码清单: 向量数量积与夹角相关测试代码

参考资料

  • 同济高等数学(第7版)下册, P14 - P17