{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Умножение векторов\n", "\n", "Пусть даны два вектора $x, y \\in \\mathbb{R}^3$. Для них определенны три вида умножения:\n", "- Векторное произведение:\n", "\n", "$$\n", " x \\times y = \n", " \\begin{pmatrix}\n", " x_1 \\\\ x_2 \\\\ x_3\n", " \\end{pmatrix}\n", " \\times\n", " \\begin{pmatrix}\n", " y_1 \\\\ y_2 \\\\ y_3\n", " \\end{pmatrix}\n", " = \\begin{pmatrix}\n", " x_2 * y_3 - x_3 * y_2 \\\\\n", " x_3 * y_1 - x_1 * y_3 \\\\\n", " x_1 * y_2 - x_2 * y_1 \n", " \\end{pmatrix}.\n", "$$\n", "\n", "- Скалярное умножение:\n", "\n", "$$\n", " x \\cdot y = \\sum_{i=1}^n x_i y_i.\n", "$$\n", "\n", "- Внешнее произведение:\n", "\n", "$$\n", " x \\wedge y = \n", " \\begin{pmatrix}\n", " x_1 y_1 & x_1 y_2 & x_1 y_3 \\\\\n", " x_2 y_1 & x_2 y_2 & x_2 y_3 \\\\\n", " x_3 y_1 & x_3 y_2 & x_3 y_3 \\\\\n", " \\end{pmatrix}.\n", "$$\n", "\n", "\n", "```{note}\n", "Векторное произведение определенно для векторов из трехмерного пространства, скалярное произведение можно определить для двух векторов из одного пространства любой размерности, а внешнее произведение можно определить для любых двух векторов, необязательно одной длинны.\n", "```\n", "\n", "Вычисление каждого их этих произведений векторизуется.\n", "\n", "## 1. Векторное произведение\n", "\n", "За векторное произведение отвечает функция [np.cross](https://numpy.org/doc/stable/reference/generated/numpy.cross.html)." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-3, 6, -3])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "\n", "x = [1, 2, 3]\n", "y = [4, 5, 6]\n", "np.cross(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если необходимо произвести несколько векторных умножений, то лучше избегать циклы и использовать векторизацию." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-3, 6, -3],\n", " [ 3, -6, 3]])" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = [[1, 2, 3], [4, 5, 6]]\n", "y = [[4, 5, 6], [1, 2, 3]]\n", "np.cross(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Можно прибегать и к *бродкастингу*. Например, если необходимо векторно умножить один вектор на несколько других. " ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-3, 6, -3],\n", " [ 0, 0, 0]])" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = [1, 2, 3]\n", "y = [[4, 5, 6], [1, 2, 3]]\n", "np.cross(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Скалярное произведение.\n", "\n", "Скалярное произведение можно сделать минимум двумя способами. \n", "\n", "Первый из них --- применить функцию [np.dot](https://numpy.org/doc/stable/reference/generated/numpy.dot.html). \n", "Если оба аргумента одномерные массивы (одинаковой), то результат --- скалярное произведение." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([1, 2])\n", "y = np.array([3, 4])\n", "np.dot(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если хотя бы один из них двухмерный, то выполняется матричное умножение. В этом и заключается второй подход. Матричное умножение вектора строки на вектор столбец эквивалентно скалярному произведению" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[11]\n" ] } ], "source": [ "print(x @ y[:, np.newaxis])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы векторизовать вычисление многих скалярных произведений удобно записать эти вектора в матрицы. \n", "Предположим, мы хотим скалярно умножить вектора\n", "$ \\vec{a} = \\begin{pmatrix}\n", "a_1 & a_2 \\\\\n", "\\end{pmatrix} $\n", "и $ \\vec{b} = \\begin{pmatrix}\n", "b_1 & b_2 \\\\\n", "\\end{pmatrix} $ на вектора $ \\vec{c} = \\begin{pmatrix}\n", "c_1 & c_2 \\\\\n", "\\end{pmatrix} $\n", "и $ \\vec{d} = \\begin{pmatrix}\n", "d_1 & d_2 \\\\\n", "\\end{pmatrix}. $ Для этого умножим матрицы $L$ и $R$, где\n", "\n", "$$\n", "L = \\begin{pmatrix}\n", "a_1 & a_2 \\\\\n", "b_1 & b_2\n", "\\end{pmatrix}\n", "$$\n", "\n", " и\n", "\n", "$$\n", "R = \\begin{pmatrix}\n", "c_1 & d_1 \\\\\n", "c_2 & d_2\n", "\\end{pmatrix}.\n", "$$\n", "\n", "Элементами результирующей матрицы будут искомые скалярные произведения. " ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 1 2]\n", " [-1 -2]]\n", "[[ 3 -3]\n", " [ 4 -4]]\n", "[[ 11 -11]\n", " [-11 11]]\n" ] } ], "source": [ "a = np.array([1, 2])\n", "b = np.array([-1, -2])\n", "c = np.array([3, 4])\n", "d = np.array([-3, -4])\n", "\n", "L = np.vstack([a, b])\n", "print(L)\n", "R = np.vstack([c, d]).T\n", "print(R)\n", "print(L @ R)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n" ] } ], "source": [ "print(np.dot(a, c))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Внешнее произведение\n", "\n", "Внешнее произведение можно посчитать с помощью функции [np.outer](https://numpy.org/doc/stable/reference/generated/numpy.outer.html), используя матричное умножение столбца на строку или используя `broadcasting`." ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2] [3 4]\n" ] } ], "source": [ "print(x, y)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[3, 4],\n", " [6, 8]])" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.outer(x, y)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[3, 4],\n", " [6, 8]])" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:, np.newaxis] * y" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[3, 4],\n", " [6, 8]])" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:, np.newaxis] @ y[ np.newaxis, :] # x и y должны быть матрицами" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1],\n", " [2]])" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:, np.newaxis]" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" } }, "nbformat": 4, "nbformat_minor": 5 }