.. _sec_geometry-linear-algebraic-ops:
Operações de Geometria e Álgebra Linear
=======================================
Em :numref:`sec_linear-algebra`, encontramos os fundamentos da álgebra
linear e vimos como ela poderia ser usada para expressar operações
comuns para transformar nossos dados. A álgebra linear é um dos
principais pilares matemáticos subjacentes a grande parte do trabalho
que fazemos no *deep learning* e no *machine learning* de forma mais
ampla. Embora :numref:`sec_linear-algebra` contenha maquinário
suficiente para comunicar a mecânica dos modelos modernos de aprendizado
profundo, há muito mais sobre o assunto. Nesta seção, iremos mais fundo,
destacando algumas interpretações geométricas de operações de álgebra
linear e introduzindo alguns conceitos fundamentais, incluindo de
autovalores e autovetores.
Geometria Vetorial
------------------
Primeiro, precisamos discutir as duas interpretações geométricas comuns
de vetores, como pontos ou direções no espaço. Fundamentalmente, um
vetor é uma lista de números, como a lista Python abaixo.
.. code:: python
v = [1, 7, 0, 1]
Os matemáticos geralmente escrevem isso como um vetor *coluna* ou
*linha*, ou seja, como
.. math::
\mathbf{x} = \begin{bmatrix}1\\7\\0\\1\end{bmatrix},
ou
.. math::
\mathbf{x}^\top = \begin{bmatrix}1 & 7 & 0 & 1\end{bmatrix}.
Muitas vezes têm interpretações diferentes, onde os exemplos de dados
são vetores de coluna e os pesos usados para formar somas ponderadas são
vetores de linha. No entanto, pode ser benéfico ser flexível. Como
descrevemos em :numref:`sec_linear-algebra`, embora a orientação
padrão de um único vetor seja um vetor coluna, para qualquer matriz que
representa um conjunto de dados tabular, tratando cada exemplo de dados
como um vetor de linha na matriz é mais convencional.
Dado um vetor, a primeira interpretação que devemos dar é como um ponto
no espaço. Em duas ou três dimensões, podemos visualizar esses pontos
usando os componentes dos vetores para definir a localização dos pontos
no espaço comparada a uma referência fixa chamada *origem*. Isso pode
ser visto em :numref:`fig_grid`.
.. _fig_grid:
.. figure:: ../img/grid-points.svg
Uma ilustração da visualização de vetores como pontos no plano. O
primeiro componente do vetor fornece a coordenada :math:`x`, o
segundo componente fornece a coordenada :math:`y`. As dimensões
superiores são análogas, embora muito mais difíceis de visualizar.
Esse ponto de vista geométrico nos permite considerar o problema em um
nível mais abstrato. Não mais confrontado com algum problema
aparentemente intransponível como classificar fotos como gatos ou
cachorros, podemos começar a considerar as tarefas abstratamente como
coleções de pontos no espaço e retratando a tarefa como descobrir como
separar dois grupos distintos de pontos.
Paralelamente, existe um segundo ponto de vista que as pessoas costumam
tomar de vetores: como direções no espaço. Não podemos apenas pensar no
vetor :math:`\mathbf{v} = [3,2]^\top` como a localização :math:`3`
unidades à direita e :math:`2` unidades acima da origem, também podemos
pensar nisso como a própria direção para mover :math:`3` passos para a
direita e :math:`2` para cima. Desta forma, consideramos todos os
vetores da figura :numref:`fig_arrow` iguais.
.. _fig_arrow:
.. figure:: ../img/par-vec.svg
Qualquer vetor pode ser visualizado como uma seta no plano. Nesse
caso, todo vetor desenhado é uma representação do vetor
:math:`(3,2)^\top`.
Um dos benefícios dessa mudança é que podemos dar sentido visual ao ato
de adição de vetores. Em particular, seguimos as instruções dadas por um
vetor, e então siga as instruções dadas pelo outro, como pode ser visto
em :numref:`fig_add-vec`.
.. _fig_add-vec:
.. figure:: ../img/vec-add.svg
Podemos visualizar a adição de vetores seguindo primeiro um vetor e
depois outro.
A subtração de vetores tem uma interpretação semelhante. Considerando a
identidade que
:math:`\mathbf{u} = \mathbf{v} + (\mathbf{u}-\mathbf{v})`, vemos que o
vetor :math:`\mathbf{u}-\mathbf{v}` é a direção que nos leva do ponto
:math:`\mathbf{v}` ao ponto :math:`\mathbf{u}`.
Produto Escalar e Ângulos
-------------------------
Como vimos em :numref:`sec_linear-algebra`, se tomarmos dois vetores
de coluna :math:`\mathbf{u}` and :math:`\mathbf{v}`, podemos formar seu
produto escalar computando:
.. math:: \mathbf{u}^\top\mathbf{v} = \sum_i u_i\cdot v_i.
:label: eq_dot_def
Porque :eq:`eq_dot_def` é simétrico, iremos espelhar a notação de
multiplicação clássica e escrita
.. math::
\mathbf{u}\cdot\mathbf{v} = \mathbf{u}^\top\mathbf{v} = \mathbf{v}^\top\mathbf{u},
para destacar o fato de que a troca da ordem dos vetores produzirá a
mesma resposta.
The dot product :eq:`eq_dot_def` also admits a geometric
interpretation: it is closely related to the angle between two vectors.
Consider the angle shown in :numref:`fig_angle`.
.. _fig_angle:
.. figure:: ../img/vec-angle.svg
Entre quaisquer dois vetores no plano, existe um ângulo bem definido
:math:`\theta`. Veremos que esse ângulo está intimamente ligado ao
produto escalar.
Para começar, vamos considerar dois vetores específicos:
.. math::
\mathbf{v} = (r,0) \; \text{and} \; \mathbf{w} = (s\cos(\theta), s \sin(\theta)).
O vetor :math:`\mathbf{v}` tem comprimento :math:`r` e corre paralelo ao
eixo :math:`x`, e o vetor :math:`\mathbf{w}` tem comprimento :math:`s` e
está no ângulo :math:`\theta` com o eixo :math:`x`. Se calcularmos o
produto escalar desses dois vetores, vemos que
.. math::
\mathbf{v}\cdot\mathbf{w} = rs\cos(\theta) = \|\mathbf{v}\|\|\mathbf{w}\|\cos(\theta).
Com alguma manipulação algébrica simples, podemos reorganizar os termos
para obter
.. math::
\theta = \arccos\left(\frac{\mathbf{v}\cdot\mathbf{w}}{\|\mathbf{v}\|\|\mathbf{w}\|}\right).
Em suma, para esses dois vetores específicos, o produto escalar
combinado com as normas nos informa o ângulo entre os dois vetores. Este
mesmo fato é verdade em geral. Não iremos derivar a expressão aqui, no
entanto, se considerarmos escrever :math:`\|\mathbf{v} - \mathbf{w}\|^2`
de duas maneiras: um com o produto escalar e o outro geometricamente
usando a lei dos cossenos, podemos obter o relacionamento completo. Na
verdade, para quaisquer dois vetores :math:`\mathbf{v}` e
:math:`\mathbf{w}`, o ângulo entre os dois vetores é
.. math:: \theta = \arccos\left(\frac{\mathbf{v}\cdot\mathbf{w}}{\|\mathbf{v}\|\|\mathbf{w}\|}\right).
:label: eq_angle_forumla
Este é um bom resultado, pois nada no cálculo faz referência a duas
dimensões. Na verdade, podemos usar isso em três ou três milhões de
dimensões sem problemas.
Como um exemplo simples, vamos ver como calcular o ângulo entre um par
de vetores:
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
from IPython import display
from mxnet import gluon, np, npx
from d2l import mxnet as d2l
npx.set_np()
def angle(v, w):
return np.arccos(v.dot(w) / (np.linalg.norm(v) * np.linalg.norm(w)))
angle(np.array([0, 1, 2]), np.array([2, 3, 4]))
.. parsed-literal::
:class: output
array(0.41899002)
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import torch
import torchvision
from IPython import display
from torchvision import transforms
from d2l import torch as d2l
def angle(v, w):
return torch.acos(v.dot(w) / (torch.norm(v) * torch.norm(w)))
angle(torch.tensor([0, 1, 2], dtype=torch.float32), torch.tensor([2.0, 3, 4]))
.. parsed-literal::
:class: output
tensor(0.4190)
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import tensorflow as tf
from IPython import display
from d2l import tensorflow as d2l
def angle(v, w):
return tf.acos(tf.tensordot(v, w, axes=1) / (tf.norm(v) * tf.norm(w)))
angle(tf.constant([0, 1, 2], dtype=tf.float32), tf.constant([2.0, 3, 4]))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Não o usaremos agora, mas é útil saber que iremos nos referir a vetores
para os quais o ângulo é :math:`\pi/2` (ou equivalentemente
:math:`90^{\circ}`) como sendo *ortogonal*. Examinando a equação acima,
vemos que isso acontece quando :math:`\theta = \pi/2`, que é a mesma
coisa que :math:`\cos(\theta) = 0`. A única maneira de isso acontecer é
se o produto escalar em si for zero, e dois vetores são ortogonais se e
somente se :math:`\mathbf{v}\cdot\mathbf{w} = 0`. Esta será uma fórmula
útil para compreender objetos geometricamente.
É razoável perguntar: por que calcular o ângulo é útil? A resposta vem
no tipo de invariância que esperamos que os dados tenham. Considere uma
imagem e uma imagem duplicada, onde cada valor de pixel é o mesmo, mas
com :math:`10\%` do brilho. Os valores dos pixels individuais estão
geralmente longe dos valores originais. Assim, se computarmos a
distância entre a imagem original e a mais escura, a distância pode ser
grande. No entanto, para a maioria dos aplicativos de ML, o *conteúdo* é
o mesmo — ainda é uma imagem de um gato no que diz respeito a um
classificador gato / cão. No entanto, se considerarmos o ângulo, não é
difícil ver que para qualquer vetor :math:`\mathbf{v}`, o ângulo entre
:math:`\mathbf{v}` e :math:`0.1\cdot\mathbf{v}` é zero. Isso corresponde
ao fato de que os vetores de escala mantém a mesma direção e apenas
altera o comprimento. O ângulo considera a imagem mais escura idêntica.
Exemplos como este estão por toda parte. No texto, podemos querer que o
tópico seja discutido para não mudar se escrevermos o dobro do tamanho
do documento que diz a mesma coisa. Para algumas codificações (como
contar o número de ocorrências de palavras em algum vocabulário), isso
corresponde a uma duplicação do vetor que codifica o documento, então,
novamente, podemos usar o ângulo.
Semelhança de Cosseno
~~~~~~~~~~~~~~~~~~~~~
Em contextos de ML onde o ângulo é empregado para medir a proximidade de
dois vetores, os profissionais adotam o termo *semelhança de cosseno*
para se referir à porção
.. math::
\cos(\theta) = \frac{\mathbf{v}\cdot\mathbf{w}}{\|\mathbf{v}\|\|\mathbf{w}\|}.
O cosseno assume um valor máximo de :math:`1` quando os dois vetores
apontam na mesma direção, um valor mínimo de :math:`-1` quando apontam
em direções opostas, e um valor de :math:`0` quando os dois vetores são
ortogonais. Observe que se os componentes de vetores de alta dimensão
são amostrados aleatoriamente com :math:`0` médio, seu cosseno será
quase sempre próximo a :math:`0`.
Hiperplanos
-----------
Além de trabalhar com vetores, outro objeto-chave que você deve entender
para ir longe na álgebra linear é o *hiperplano*, uma generalização para
dimensões superiores de uma linha (duas dimensões) ou de um plano (três
dimensões). Em um espaço vetorial :math:`d`-dimensional, um hiperplano
tem :math:`d-1` dimensões e divide o espaço em dois meios-espaços.
Vamos começar com um exemplo. Suponha que temos um vetor coluna
:math:`\mathbf{w}=[2,1]^\top`. Queremos saber, “quais são os pontos
:math:`\mathbf{v}` com :math:`\mathbf{w}\cdot\mathbf{v} = 1`?” Ao
relembrar a conexão entre produtos escalares e ângulos acima
:eq:`eq_angle_forumla`, podemos ver que isso é equivalente a
.. math::
\|\mathbf{v}\|\|\mathbf{w}\|\cos(\theta) = 1 \; \iff \; \|\mathbf{v}\|\cos(\theta) = \frac{1}{\|\mathbf{w}\|} = \frac{1}{\sqrt{5}}.
.. _fig_vector-project:
.. figure:: ../img/proj-vec.svg
Relembrando a trigonometria, vemos que a fórmula
:math:`\|\mathbf{v}\|\cos(\theta)` é o comprimento da projeção do
vetor :math:`\mathbf{v}` na direção de :math:`\mathbf{w}`
Se considerarmos o significado geométrico desta expressão, vemos que
isso é equivalente a dizer que o comprimento da projeção de
:math:`\mathbf{v}` na direção de :math:`\mathbf{w}` é exatamente
:math:`1/\|\mathbf{w}\|`, como é mostrado em
:numref:`fig_vector-project`. O conjunto de todos os pontos onde isso
é verdade é uma linha perpendicularmente ao vetor :math:`\mathbf{w}`. Se
quiséssemos, poderíamos encontrar a equação para esta linha e veja que é
:math:`2x + y = 1` ou equivalentemente :math:`y = 1 - 2x`.
Se agora olharmos para o que acontece quando perguntamos sobre o
conjunto de pontos com :math:`\mathbf{w}\cdot\mathbf{v} > 1` ou
:math:`\mathbf{w}\cdot\mathbf{v} < 1`, podemos ver que estes são casos
em que as projeções são maiores ou menores que :math:`1/\|\mathbf{w}\|`,
respectivamente. Portanto, essas duas desigualdades definem os dois
lados da linha. Desta forma, descobrimos uma maneira de cortar nosso
espaço em duas metades, onde todos os pontos de um lado têm produto
escalar abaixo de um limite, e o outro lado acima como vemos em
:numref:`fig_space-division`.
.. _fig_space-division:
.. figure:: ../img/space-division.svg
Se considerarmos agora a versão da desigualdade da expressão, vemos
que nosso hiperplano (neste caso: apenas uma linha) separa o espaço
em duas metades.
A história em uma dimensão superior é praticamente a mesma. Se agora
tomarmos :math:`\mathbf{w} = [1,2,3]^\top` e perguntarmos sobre os
pontos em três dimensões com :math:`\mathbf{w}\cdot\mathbf{v} = 1`,
obtemos um plano perpendicular ao vetor dado :math:`\mathbf{w}`. As duas
desigualdades definem novamente os dois lados do plano como é mostrado
em :numref:`fig_higher-division`.
.. _fig_higher-division:
.. figure:: ../img/space-division-3d.svg
Hiperplanos em qualquer dimensão separam o espaço em duas metades.
Embora nossa capacidade de visualizar se esgote neste ponto, nada nos
impede de fazer isso em dezenas, centenas ou bilhões de dimensões. Isso
ocorre frequentemente quando se pensa em modelos aprendidos por máquina.
Por exemplo, podemos entender modelos de classificação linear como
aqueles de :numref:`sec_softmax`, como métodos para encontrar
hiperplanos que separam as diferentes classes de destino. Nesse
contexto, esses hiperplanos são freqüentemente chamados de *planos de
decisão*. A maioria dos modelos de classificação profundamente
aprendidos termina com uma camada linear alimentada em um *softmax*,
para que se possa interpretar o papel da rede neural profunda encontrar
uma incorporação não linear de modo que as classes de destino podem ser
separados de forma limpa por hiperplanos.
Para dar um exemplo feito à mão, observe que podemos produzir um modelo
razoável para classificar pequenas imagens de camisetas e calças do
conjunto de dados do Fashion MNIST (visto em
:numref:`sec_fashion_mnist`) apenas pegando o vetor entre seus meios
para definir o plano de decisão e olho um limiar bruto. Primeiro,
carregaremos os dados e calcularemos as médias.
.. raw:: html
.. raw:: html
.. code:: python
# Load in the dataset
train = gluon.data.vision.FashionMNIST(train=True)
test = gluon.data.vision.FashionMNIST(train=False)
X_train_0 = np.stack([x[0] for x in train if x[1] == 0]).astype(float)
X_train_1 = np.stack([x[0] for x in train if x[1] == 1]).astype(float)
X_test = np.stack(
[x[0] for x in test if x[1] == 0 or x[1] == 1]).astype(float)
y_test = np.stack(
[x[1] for x in test if x[1] == 0 or x[1] == 1]).astype(float)
# Compute averages
ave_0 = np.mean(X_train_0, axis=0)
ave_1 = np.mean(X_train_1, axis=0)
.. raw:: html
.. raw:: html
.. code:: python
# Load in the dataset
trans = []
trans.append(transforms.ToTensor())
trans = transforms.Compose(trans)
train = torchvision.datasets.FashionMNIST(root="../data", transform=trans,
train=True, download=True)
test = torchvision.datasets.FashionMNIST(root="../data", transform=trans,
train=False, download=True)
X_train_0 = torch.stack(
[x[0] * 256 for x in train if x[1] == 0]).type(torch.float32)
X_train_1 = torch.stack(
[x[0] * 256 for x in train if x[1] == 1]).type(torch.float32)
X_test = torch.stack(
[x[0] * 256 for x in test if x[1] == 0 or x[1] == 1]).type(torch.float32)
y_test = torch.stack([torch.tensor(x[1]) for x in test
if x[1] == 0 or x[1] == 1]).type(torch.float32)
# Compute averages
ave_0 = torch.mean(X_train_0, axis=0)
ave_1 = torch.mean(X_train_1, axis=0)
.. raw:: html
.. raw:: html
.. code:: python
# Load in the dataset
((train_images, train_labels), (
test_images, test_labels)) = tf.keras.datasets.fashion_mnist.load_data()
X_train_0 = tf.cast(tf.stack(train_images[[i for i, label in enumerate(
train_labels) if label == 0]] * 256), dtype=tf.float32)
X_train_1 = tf.cast(tf.stack(train_images[[i for i, label in enumerate(
train_labels) if label == 1]] * 256), dtype=tf.float32)
X_test = tf.cast(tf.stack(test_images[[i for i, label in enumerate(
test_labels) if label == 0]] * 256), dtype=tf.float32)
y_test = tf.cast(tf.stack(test_images[[i for i, label in enumerate(
test_labels) if label == 1]] * 256), dtype=tf.float32)
# Compute averages
ave_0 = tf.reduce_mean(X_train_0, axis=0)
ave_1 = tf.reduce_mean(X_train_1, axis=0)
.. raw:: html
.. raw:: html
Pode ser informativo examinar essas médias em detalhes, portanto, vamos
representar graficamente sua aparência. Nesse caso, vemos que a média
realmente se assemelha a uma imagem borrada de uma camiseta.
.. raw:: html
.. raw:: html
.. code:: python
# Plot average t-shirt
d2l.set_figsize()
d2l.plt.imshow(ave_0.reshape(28, 28).tolist(), cmap='Greys')
d2l.plt.show()
.. figure:: output_geometry-linear-algebraic-ops_80b1c3_29_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Plot average t-shirt
d2l.set_figsize()
d2l.plt.imshow(ave_0.reshape(28, 28).tolist(), cmap='Greys')
d2l.plt.show()
.. figure:: output_geometry-linear-algebraic-ops_80b1c3_32_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Plot average t-shirt
d2l.set_figsize()
d2l.plt.imshow(tf.reshape(ave_0, (28, 28)), cmap='Greys')
d2l.plt.show()
.. figure:: output_geometry-linear-algebraic-ops_80b1c3_35_0.svg
.. raw:: html
.. raw:: html
No segundo caso, vemos novamente que a média se assemelha a uma imagem
borrada de calças.
.. raw:: html
.. raw:: html
.. code:: python
# Plot average trousers
d2l.plt.imshow(ave_1.reshape(28, 28).tolist(), cmap='Greys')
d2l.plt.show()
.. figure:: output_geometry-linear-algebraic-ops_80b1c3_41_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Plot average trousers
d2l.plt.imshow(ave_1.reshape(28, 28).tolist(), cmap='Greys')
d2l.plt.show()
.. figure:: output_geometry-linear-algebraic-ops_80b1c3_44_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Plot average trousers
d2l.plt.imshow(tf.reshape(ave_1, (28, 28)), cmap='Greys')
d2l.plt.show()
.. figure:: output_geometry-linear-algebraic-ops_80b1c3_47_0.svg
.. raw:: html
.. raw:: html
Em uma solução totalmente aprendida pela máquina, aprenderíamos o limite
do conjunto de dados. Nesse caso, simplesmente analisamos um limite que
parecia bom nos dados de treinamento à mão.
.. raw:: html
.. raw:: html
.. code:: python
# Print test set accuracy with eyeballed threshold
w = (ave_1 - ave_0).T
predictions = X_test.reshape(2000, -1).dot(w.flatten()) > -1500000
# Accuracy
np.mean(predictions.astype(y_test.dtype) == y_test, dtype=np.float64)
.. parsed-literal::
:class: output
array(0.801, dtype=float64)
.. raw:: html
.. raw:: html
.. code:: python
# Print test set accuracy with eyeballed threshold
w = (ave_1 - ave_0).T
# '@' is Matrix Multiplication operator in pytorch.
predictions = X_test.reshape(2000, -1) @ (w.flatten()) > -1500000
# Accuracy
torch.mean(predictions.type(y_test.dtype) == y_test, dtype=torch.float64)
.. parsed-literal::
:class: output
tensor(0.7870, dtype=torch.float64)
.. raw:: html
.. raw:: html
.. code:: python
# Print test set accuracy with eyeballed threshold
w = tf.transpose(ave_1 - ave_0)
predictions = tf.reduce_sum(X_test * tf.nest.flatten(w), axis=0) > -1500000
# Accuracy
tf.reduce_mean(
tf.cast(tf.cast(predictions, y_test.dtype) == y_test, tf.float32))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Geometria de Transformações Lineares
------------------------------------
Por meio de :numref:`sec_linear-algebra` e das discussões acima, temos
um conhecimento sólido da geometria de vetores, comprimentos e ângulos.
No entanto, há um objeto importante que omitimos de discutir, e essa é
uma compreensão geométrica das transformações lineares representadas por
matrizes. Totalmente internalizando o que as matrizes podem fazer para
transformar dados entre dois espaços de dimensões elevadas
potencialmente diferentes requer prática significativa, e está além do
escopo deste apêndice. No entanto, podemos começar a construir a
intuição em duas dimensões.
Suponha que temos alguma matriz:
.. math::
\mathbf{A} = \begin{bmatrix}
a & b \\ c & d
\end{bmatrix}.
Se quisermos aplicar isso a um vetor arbitrário
:math:`\mathbf{v} = [x, y]^\top`, nós nos multiplicamos e vemos que
.. math::
\begin{aligned}
\mathbf{A}\mathbf{v} & = \begin{bmatrix}a & b \\ c & d\end{bmatrix}\begin{bmatrix}x \\ y\end{bmatrix} \\
& = \begin{bmatrix}ax+by\\ cx+dy\end{bmatrix} \\
& = x\begin{bmatrix}a \\ c\end{bmatrix} + y\begin{bmatrix}b \\d\end{bmatrix} \\
& = x\left\{\mathbf{A}\begin{bmatrix}1\\0\end{bmatrix}\right\} + y\left\{\mathbf{A}\begin{bmatrix}0\\1\end{bmatrix}\right\}.
\end{aligned}
Isso pode parecer um cálculo estranho, onde algo claro se tornou algo
impenetrável. No entanto, isso nos diz que podemos escrever da maneira
que uma matriz transforma *qualquer* vetor em termos de como ele
transforma *dois vetores específicos*: :math:`[1,0]^\top` and
:math:`[0,1]^\top`. Vale a pena considerar isso por um momento. Nós
essencialmente reduzimos um problema infinito (o que acontece com
qualquer par de números reais) para um finito (o que acontece com esses
vetores específicos). Esses vetores são um exemplo de *vetores
canônicos*, onde podemos escrever qualquer vetor em nosso espaço como
uma soma ponderada desses *vetores canônicos*.
Vamos desenhar o que acontece quando usamos a matriz específica
.. math::
\mathbf{A} = \begin{bmatrix}
1 & 2 \\
-1 & 3
\end{bmatrix}.
Se olharmos para o vetor específico :math:`\mathbf{v} = [2, -1]^\top`,
vemos que é :math:`2\cdot[1,0]^\top + -1\cdot[0,1]^\top`, e assim
sabemos que a matriz :math:`A` irá enviar isso para
:math:`2(\mathbf{A}[1,0]^\top) + -1(\mathbf{A}[0,1])^\top = 2[1, -1]^\top - [2,3]^\top = [0, -5]^\top`.
Se seguirmos essa lógica com cuidado, digamos, considerando a grade de
todos os pares inteiros de pontos, vemos que o que acontece é que a
multiplicação da matriz pode inclinar, girar e dimensionar a grade, mas
a estrutura da grade deve permanecer como você vê em
:numref:`fig_grid-transform`.
.. _fig_grid-transform:
.. figure:: ../img/grid-transform.svg
A matriz :math:`\mathbf{A}` agindo nos vetores de base dados. Observe
como toda a grade é transportada junto com ela.
Este é o ponto intuitivo mais importante para internalizar sobre
transformações lineares representadas por matrizes. As matrizes são
incapazes de distorcer algumas partes do espaço de maneira diferente de
outras. Tudo o que elas podem fazer é pegar as coordenadas originais em
nosso espaço e inclinar, girar e dimensioná-las.
Algumas distorções podem ser graves. Por exemplo, a matriz
.. math::
\mathbf{B} = \begin{bmatrix}
2 & -1 \\ 4 & -2
\end{bmatrix},
comprime todo o plano bidimensional em uma única linha. Identificar e
trabalhar com essas transformações é o tópico de uma seção posterior,
mas geometricamente podemos ver que isso é fundamentalmente diferente
dos tipos de transformações que vimos acima. Por exemplo, o resultado da
matriz :math:`\mathbf{A}` pode ser “dobrado” para a grade original. Os
resultados da matriz :math:`\mathbf{B}` não podem porque nunca saberemos
de onde o vetor :math:`[1,2]^\top` veio — estava it :math:`[1,1]^\top`
ou :math:`[0, -1]^\top`?
Embora esta imagem fosse para uma matriz :math:`2\times2`, nada nos
impede de levar as lições aprendidas para dimensões superiores. Se
tomarmos vetores de base semelhantes como :math:`[1,0, \ldots,0]` e ver
para onde nossa matriz os envia, podemos começar a ter uma ideia de como
a multiplicação da matriz distorce todo o espaço em qualquer dimensão de
espaço com a qual estamos lidando.
Dependência Linear
------------------
Considere novamente a matriz
.. math::
\mathbf{B} = \begin{bmatrix}
2 & -1 \\ 4 & -2
\end{bmatrix}.
Isso comprime todo o plano para viver na única linha :math:`y=2x`. A
questão agora surge: há alguma maneira de detectarmos isso apenas
olhando para a própria matriz? A resposta é que realmente podemos.
Tomemos :math:`\mathbf{b}_1 = [2,4]^\top` e
:math:`\mathbf{b}_2 = [-1, -2]^\top` sejam as duas colunas de
:math:`\mathbf{B}`. Lembre-se de que podemos escrever tudo transformado
pela matriz :math:`\mathbf{B}` como uma soma ponderada das colunas da
matriz: como :math:`a_1\mathbf{b}_1 + a_2\mathbf{b}_2`. Chamamos isso de
*combinação linear*. O fato de
:math:`\mathbf{b}_1 = -2\cdot\mathbf{b}_2` significa que podemos
escrever qualquer combinação linear dessas duas colunas inteiramente em
termos de, digamos, :math:`\mathbf{b}_2` desde
.. math::
a_1\mathbf{b}_1 + a_2\mathbf{b}_2 = -2a_1\mathbf{b}_2 + a_2\mathbf{b}_2 = (a_2-2a_1)\mathbf{b}_2.
Isso significa que uma das colunas é, de certo modo, redundante porque
não define uma direção única no espaço. Isso não deve nos surpreender
muito pois já vimos que esta matriz reduz o plano inteiro em uma única
linha. Além disso, vemos que a dependência linear
:math:`\mathbf{b}_1 = -2\cdot\mathbf{b}_2` captura isso. Para tornar
isso mais simétrico entre os dois vetores, vamos escrever isso como
.. math::
\mathbf{b}_1 + 2\cdot\mathbf{b}_2 = 0.
Em geral, diremos que uma coleção de vetores
:math:`\mathbf{v}_1, \ldots, \mathbf{v}_k` são *linearmente dependentes*
se existirem coeficientes :math:`a_1, \ldots, a_k` *nem todos iguais a
zero* de modo que
.. math::
\sum_{i=1}^k a_i\mathbf{v_i} = 0.
Neste caso, podemos resolver para um dos vetores em termos de alguma
combinação dos outros, e efetivamente torná-lo redundante. Assim, uma
dependência linear nas colunas de uma matriz é uma testemunha do fato de
que nossa matriz está comprimindo o espaço para alguma dimensão
inferior. Se não houver dependência linear, dizemos que os vetores são
*linearmente independentes*. Se as colunas de uma matriz são linearmente
independentes, nenhuma compressão ocorre e a operação pode ser desfeita.
Classificação
-------------
Se tivermos uma matriz geral :math:`n\times m`, é razoável perguntar em
qual espaço de dimensão a matriz mapeia. Um conceito conhecido como
classificação será a nossa resposta. Na seção anterior, notamos que uma
dependência linear testemunha a compressão do espaço em uma dimensão
inferior e assim seremos capazes de usar isso para definir a noção de
posto. Em particular, a classificação de uma matriz :math:`\mathbf{A}` é
o maior número de colunas linearmente independentes entre todos os
subconjuntos de colunas. Por exemplo, a matriz
.. math::
\mathbf{B} = \begin{bmatrix}
2 & 4 \\ -1 & -2
\end{bmatrix},
tem :math:`\mathrm{rank}(B)=1`, uma vez que as duas colunas são
linearmente dependentes, mas qualquer coluna por si só não é linearmente
dependente. Para um exemplo mais desafiador, podemos considerar
.. math::
\mathbf{C} = \begin{bmatrix}
1& 3 & 0 & -1 & 0 \\
-1 & 0 & 1 & 1 & -1 \\
0 & 3 & 1 & 0 & -1 \\
2 & 3 & -1 & -2 & 1
\end{bmatrix},
e mostrar que :math:`\mathbf{C}` tem classificação dois, uma vez que,
por exemplo, as duas primeiras colunas são linearmente independentes,
entretanto, qualquer uma das quatro coleções de três colunas é
dependente.
Este procedimento, conforme descrito, é muito ineficiente. Requer olhar
para cada subconjunto das colunas de nossa matriz, e, portanto, é
potencialmente exponencial no número de colunas. Mais tarde, veremos uma
forma mais eficiente do ponto de vista computacional para calcular a
classificação de uma matriz, mas por enquanto, isso é suficiente para
ver que o conceito está bem definido e compreende o significado.
Invertibilidade
---------------
Vimos acima que a multiplicação por uma matriz com colunas linearmente
dependentes não pode ser desfeita, ou seja, não há operação inversa que
sempre pode recuperar a entrada. No entanto, a multiplicação por uma
matriz de classificação completa (ou seja, algum :math:`\mathbf{A}` que
é :math:`n \times n` matriz com classificação :math:`n`), devemos sempre
poder desfazê-lo. Considere a matriz
.. math::
\mathbf{I} = \begin{bmatrix}
1 & 0 & \cdots & 0 \\
0 & 1 & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & 1
\end{bmatrix}.
que é a matriz com uns ao longo da diagonal e zeros em outros lugares.
Chamamos isso de matriz de \* identidade \*. É a matriz que deixa nossos
dados inalterados quando aplicados. Para encontrar uma matriz que
desfaça o que nossa matriz :math:`\mathbf{A}` fez, queremos encontrar
uma matriz :math:`\mathbf{A}^{-1}` tal que
.. math::
\mathbf{A}^{-1}\mathbf{A} = \mathbf{A}\mathbf{A}^{-1} = \mathbf{I}.
Se olharmos para isso como um sistema, temos :math:`n \times n`
incógnitas (as entradas de :math:`\mathbf{A}^{-1}`) e :math:`n \times n`
equações (a igualdade que precisa ser mantida entre cada entrada do
produto :math:`\mathbf{A}^{-1}\mathbf{A}` e cada entrada de
:math:`\mathbf{I}`) portanto, devemos genericamente esperar que exista
uma solução. Na verdade, na próxima seção, veremos uma quantidade
chamada de *determinante*, que tem a propriedade de que, desde que o
determinante não seja zero, podemos encontrar uma solução. Chamamos tal
matriz :math:`\mathbf{A}^{-1}` de matriz *inversa*. Por exemplo, se
:math:`\mathbf{A}` é a matriz :math:`2 \times 2` geral
.. math::
\mathbf{A} = \begin{bmatrix}
a & b \\
c & d
\end{bmatrix},
então podemos ver que a inversa é
.. math::
\frac{1}{ad-bc} \begin{bmatrix}
d & -b \\
-c & a
\end{bmatrix}.
Podemos testar para ver isso vendo que a multiplicação pela inversa dado
pela fórmula acima funciona na prática.
.. raw:: html
.. raw:: html
.. code:: python
M = np.array([[1, 2], [1, 4]])
M_inv = np.array([[2, -1], [-0.5, 0.5]])
M_inv.dot(M)
.. parsed-literal::
:class: output
array([[1., 0.],
[0., 1.]])
.. raw:: html
.. raw:: html
.. code:: python
M = torch.tensor([[1, 2], [1, 4]], dtype=torch.float32)
M_inv = torch.tensor([[2, -1], [-0.5, 0.5]])
M_inv @ M
.. parsed-literal::
:class: output
tensor([[1., 0.],
[0., 1.]])
.. raw:: html
.. raw:: html
.. code:: python
M = tf.constant([[1, 2], [1, 4]], dtype=tf.float32)
M_inv = tf.constant([[2, -1], [-0.5, 0.5]])
tf.matmul(M_inv, M)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Problemas Numéricos
~~~~~~~~~~~~~~~~~~~
Embora o inverso de uma matriz seja útil em teoria, devemos dizer que na
maioria das vezes não desejamos *usar* a matriz inversa para resolver um
problema na prática. Em geral, existem algoritmos muito mais estáveis
numericamente para resolver equações lineares como
.. math::
\mathbf{A}\mathbf{x} = \mathbf{b},
do que calcular a inversa e multiplicar para obter
.. math::
\mathbf{x} = \mathbf{A}^{-1}\mathbf{b}.
Assim como a divisão por um pequeno número pode levar à instabilidade
numérica, o mesmo pode acontecer com a inversão de uma matriz que está
perto de ter uma classificação baixa.
Além disso, é comum que a matriz :math:`\mathbf{A}` seja *esparsa*, o
que significa que ele contém apenas um pequeno número de valores
diferentes de zero. Se fossemos explorar exemplos, veríamos que isso não
significa que o inverso é esparso. Mesmo se :math:`\mathbf{A}` fosse uma
matriz de :math:`1` milhão por :math:`1` milhão com apenas :math:`5`
milhões de entradas diferentes de zero (e, portanto, precisamos apenas
armazenar aqueles :math:`5` milhões), a inversa normalmente terá quase
todas as entradas não negativas, exigindo que armazenemos todas as
:math:`1\text{M}^2` de entradas — isto é :math:`1` trilhão de entradas!
Embora não tenhamos tempo para mergulhar totalmente nas espinhosas
questões numéricas frequentemente encontrados ao trabalhar com álgebra
linear, queremos fornecer-lhe alguma intuição sobre quando proceder com
cautela, e geralmente evitar a inversão na prática é uma boa regra
prática.
Determinante
------------
A visão geométrica da álgebra linear oferece uma maneira intuitiva para
interpretar uma quantidade fundamental conhecida como *determinante*.
Considere a imagem da grade de antes, mas agora com uma região destacada
(:numref:`fig_grid-fill`).
.. _fig_grid-filled:
.. figure:: ../img/grid-transform-filled.svg
A matriz :math:`\mathbf{A}` novamente distorcendo a grade. Desta vez,
quero chamar a atenção em particular para o que acontece com o
quadrado destacado.
Olhe para o quadrado destacado. Este é um quadrado com bordas fornecidas
por :math:`(0, 1)` e :math:`(1, 0)` e, portanto, tem área um. Depois que
:math:`\mathbf{A}` transforma este quadrado, vemos que se torna um
paralelogramo. Não há razão para este paralelogramo ter a mesma área com
que começamos, e de fato no caso específico mostrado aqui de
.. math::
\mathbf{A} = \begin{bmatrix}
1 & 2 \\
-1 & 3
\end{bmatrix},
é um exercício de geometria coordenada para calcular a área deste
paralelogramo e obtenha que a área é :math:`5`.
Em geral, se tivermos uma matriz
.. math::
\mathbf{A} = \begin{bmatrix}
a & b \\
c & d
\end{bmatrix},
podemos ver com alguns cálculos que a área do paralelogramo resultante é
:math:`ad-bc`. Essa área é chamada de *determinante*.
Vamos verificar isso rapidamente com algum código de exemplo.
.. raw:: html
.. raw:: html
.. code:: python
import numpy as np
np.linalg.det(np.array([[1, -1], [2, 3]]))
.. parsed-literal::
:class: output
5.000000000000001
.. raw:: html
.. raw:: html
.. code:: python
torch.det(torch.tensor([[1, -1], [2, 3]], dtype=torch.float32))
.. parsed-literal::
:class: output
tensor(5.)
.. raw:: html
.. raw:: html
.. code:: python
tf.linalg.det(tf.constant([[1, -1], [2, 3]], dtype=tf.float32))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Os olhos de águia entre nós notarão que esta expressão pode ser zero ou
mesmo negativa. Para o termo negativo, isso é uma questão de convenção
geralmente considerado em matemática: se a matriz inverte a figura,
dizemos que a área está negada. Vejamos agora que quando o determinante
é zero, aprendemos mais.
Vamos considerar
.. math::
\mathbf{B} = \begin{bmatrix}
2 & 4 \\ -1 & -2
\end{bmatrix}.
Se calcularmos o determinante desta matriz, obtemos
:math:`2\cdot(-2 ) - 4\cdot(-1) = 0`. Dado o nosso entendimento acima,
isso faz sentido. :math:`\mathbf{B}` comprime o quadrado da imagem
original até um segmento de linha, que tem área zero. E, de fato, sendo
comprimido em um espaço dimensional inferior é a única maneira de ter
área zero após a transformação. Assim, vemos que o seguinte resultado é
verdadeiro: uma matriz :math:`A` é invertível se e somente se o
determinante não é igual a zero.
Como comentário final, imagine que temos alguma figura desenhada no
avião. Pensando como cientistas da computação, podemos decompor aquela
figura em uma coleção de pequenos quadrados de modo que a área da figura
é em essência apenas o número de quadrados na decomposição. Se agora
transformarmos essa figura em uma matriz, enviamos cada um desses
quadrados para paralelogramos, cada um deles tem área dada pelo
determinante. Vemos que para qualquer figura, o determinante dá o número
(com sinal) que uma matriz dimensiona a área de qualquer figura.
Determinantes de computação para matrizes maiores podem ser trabalhosos,
mas a intuição é a mesma. O determinante continua sendo o fator que
:math:`n\times n` matrizes escalam volumes :math:`n`-dimensionais.
Tensores e Operações de Álgebra Linear Comum
--------------------------------------------
Em :numref:`sec_linear-algebra` o conceito de tensores foi
introduzido. Nesta seção, vamos mergulhar mais profundamente nas
contrações tensoras (o tensor equivalente à multiplicação da matriz), e
ver como pode fornecer uma visão unificada em uma série de operações de
matriz e vetor.
Com matrizes e vetores, sabíamos como multiplicá-los para transformar os
dados. Precisamos ter uma definição semelhante para tensores se eles
forem úteis para nós. Pense na multiplicação de matrizes:
.. math::
\mathbf{C} = \mathbf{A}\mathbf{B},
ou equivalente
.. math:: c_{i, j} = \sum_{k} a_{i, k}b_{k, j}.
Esse padrão pode ser repetido para tensores. Para tensores, não há um
caso de qual para somar isso pode ser universalmente escolhido,
portanto, precisamos especificar exatamente quais índices queremos
somar. Por exemplo, podemos considerar
.. math::
y_{il} = \sum_{jk} x_{ijkl}a_{jk}.
Essa transformação é chamada de *contração tensorial*. Pode representar
uma família de transformações muito mais flexível que a multiplicação de
matriz sozinha.
Como uma simplificação de notação frequentemente usada, podemos notar
que a soma está exatamente acima desses índices que ocorrem mais de uma
vez na expressão, assim, as pessoas costumam trabalhar com *notação de
Einstein*, onde o somatório é implicitamente assumido sobre todos os
índices repetidos. Isso dá a expressão compacta:
.. math::
y_{il} = x_{ijkl}a_{jk}.
Exemplos Comuns de Álgebra Linear
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vamos ver quantas das definições algébricas lineares que vimos antes
pode ser expresso nesta notação de tensor compactado:
- :math:`\mathbf{v} \cdot \mathbf{w} = \sum_i v_iw_i`
- :math:`\|\mathbf{v}\|_2^{2} = \sum_i v_iv_i`
- :math:`(\mathbf{A}\mathbf{v})_i = \sum_j a_{ij}v_j`
- :math:`(\mathbf{A}\mathbf{B})_{ik} = \sum_j a_{ij}b_{jk}`
- :math:`\mathrm{tr}(\mathbf{A}) = \sum_i a_{ii}`
Dessa forma, podemos substituir uma miríade de notações especializadas
por expressões tensoriais curtas.
Expressando em Código
~~~~~~~~~~~~~~~~~~~~~
Os tensores também podem ser operados com flexibilidade no código.
Conforme visto em :numref:`sec_linear-algebra`, podemos criar tensores
como mostrado abaixo.
.. raw:: html
.. raw:: html
.. code:: python
# Define tensors
B = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
A = np.array([[1, 2], [3, 4]])
v = np.array([1, 2])
# Print out the shapes
A.shape, B.shape, v.shape
.. parsed-literal::
:class: output
((2, 2), (2, 2, 3), (2,))
.. raw:: html
.. raw:: html
.. code:: python
# Define tensors
B = torch.tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
A = torch.tensor([[1, 2], [3, 4]])
v = torch.tensor([1, 2])
# Print out the shapes
A.shape, B.shape, v.shape
.. parsed-literal::
:class: output
(torch.Size([2, 2]), torch.Size([2, 2, 3]), torch.Size([2]))
.. raw:: html
.. raw:: html
.. code:: python
# Define tensors
B = tf.constant([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
A = tf.constant([[1, 2], [3, 4]])
v = tf.constant([1, 2])
# Print out the shapes
A.shape, B.shape, v.shape
.. parsed-literal::
:class: output
(TensorShape([2, 2]), TensorShape([2, 2, 3]), TensorShape([2]))
.. raw:: html
.. raw:: html
O somatório de Einstein foi implementado diretamente. Os índices que
ocorrem na soma de Einstein podem ser passados como uma *string*,
seguido pelos tensores que estão sofrendo ação. Por exemplo, para
implementar a multiplicação de matrizes, podemos considerar o somatório
de Einstein visto acima (:math:`\mathbf{A}\mathbf{v} = a_{ij}v_j`) e
retirar os próprios índices para obter a implementação:
.. raw:: html
.. raw:: html
.. code:: python
# Reimplement matrix multiplication
np.einsum("ij, j -> i", A, v), A.dot(v)
.. parsed-literal::
:class: output
(array([ 5, 11]), array([ 5, 11]))
.. raw:: html
.. raw:: html
.. code:: python
# Reimplement matrix multiplication
torch.einsum("ij, j -> i", A, v), A@v
.. parsed-literal::
:class: output
(tensor([ 5, 11]), tensor([ 5, 11]))
.. raw:: html
.. raw:: html
.. code:: python
# Reimplement matrix multiplication
tf.einsum("ij, j -> i", A, v), tf.matmul(A, tf.reshape(v, (2, 1)))
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Esta é uma notação altamente flexível. Por exemplo, se quisermos
calcular o que seria tradicionalmente escrito como
.. math::
c_{kl} = \sum_{ij} \mathbf{b}_{ijk}\mathbf{a}_{il}v_j.
pode ser implementado via somatório de Einstein como:
.. raw:: html
.. raw:: html
.. code:: python
np.einsum("ijk, il, j -> kl", B, A, v)
.. parsed-literal::
:class: output
array([[ 90, 126],
[102, 144],
[114, 162]])
.. raw:: html
.. raw:: html
.. code:: python
torch.einsum("ijk, il, j -> kl", B, A, v)
.. parsed-literal::
:class: output
tensor([[ 90, 126],
[102, 144],
[114, 162]])
.. raw:: html
.. raw:: html
.. code:: python
tf.einsum("ijk, il, j -> kl", B, A, v)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Esta notação é legível e eficiente para humanos, por mais volumoso que
seja por algum motivo precisamos gerar uma contração de tensor
programaticamente. Por este motivo, ``einsum`` fornece uma notação
alternativa fornecendo índices inteiros para cada tensor. Por exemplo, a
mesma contração tensorial também pode ser escrita como:
.. raw:: html
.. raw:: html
.. code:: python
np.einsum(B, [0, 1, 2], A, [0, 3], v, [1], [2, 3])
.. parsed-literal::
:class: output
array([[ 90, 126],
[102, 144],
[114, 162]])
.. raw:: html
.. raw:: html
.. code:: python
# PyTorch doesn't support this type of notation.
.. raw:: html
.. raw:: html
.. code:: python
# TensorFlow doesn't support this type of notation.
.. raw:: html
.. raw:: html
Qualquer uma das notações permite uma representação concisa e eficiente
das contrações do tensor no código.
Resumo
------
- Os vetores podem ser interpretados geometricamente como pontos ou
direções no espaço.
- Os produtos escalares definem a noção de ângulo para espaços de
dimensões arbitrariamente altas.
- Hiperplanos são generalizações dimensionais de linhas e planos. Eles
podem ser usados para definir planos de decisão que geralmente são
usados como a última etapa em uma tarefa de classificação.
- A multiplicação de matrizes pode ser interpretada geometricamente
como distorções uniformes das coordenadas subjacentes. Eles
representam uma maneira muito restrita, mas matematicamente limpa, de
transformar vetores.
- Dependência linear é uma forma de saber quando uma coleção de vetores
está em um espaço dimensional inferior do que esperaríamos (digamos
que você tenha :math:`3` vetores vivendo em um espaço
:math:`2`-dimensional). A classificação de uma matriz é o tamanho do
maior subconjunto de suas colunas que são linearmente independentes.
- Quando a inversa de uma matriz é definida, a inversão da matriz nos
permite encontrar outra matriz que desfaça a ação da primeira. A
inversão da matriz é útil na teoria, mas requer cuidado na prática
devido à instabilidade numérica.
- Os determinantes nos permitem medir o quanto uma matriz se expande ou
contrai em um espaço. Um determinante diferente de zero implica uma
matriz invertível (não singular) e um determinante de valor zero
significa que a matriz é não invertível (singular).
- As contrações do tensor e a soma de Einstein fornecem uma notação
limpa e organizada para expressar muitos dos cálculos que são vistos
no aprendizado de máquina.
Exercícios
----------
1. Qual é o ângulo entre
.. math::
\vec v_1 = \begin{bmatrix}
1 \\ 0 \\ -1 \\ 2
\end{bmatrix}, \qquad \vec v_2 = \begin{bmatrix}
3 \\ 1 \\ 0 \\ 1
\end{bmatrix}?
2. Verdadeiro ou falso: :math:`\begin{bmatrix}1 & 2\\0&1\end{bmatrix}` e
:math:`\begin{bmatrix}1 & -2\\0&1\end{bmatrix}` são inversas uma da
outra?
3. Suponha que desenhemos uma forma no plano com área
:math:`100\mathrm{m}^2`. Qual é a área depois de transformar a figura
pela matriz
.. math::
\begin{bmatrix}
2 & 3\\
1 & 2
\end{bmatrix}.
4. Qual dos seguintes conjuntos de vetores são linearmente
independentes?
- :math:`\left\{\begin{pmatrix}1\\0\\-1\end{pmatrix}, \begin{pmatrix}2\\1\\-1\end{pmatrix}, \begin{pmatrix}3\\1\\1\end{pmatrix}\right\}`
- :math:`\left\{\begin{pmatrix}3\\1\\1\end{pmatrix}, \begin{pmatrix}1\\1\\1\end{pmatrix}, \begin{pmatrix}0\\0\\0\end{pmatrix}\right\}`
- :math:`\left\{\begin{pmatrix}1\\1\\0\end{pmatrix}, \begin{pmatrix}0\\1\\-1\end{pmatrix}, \begin{pmatrix}1\\0\\1\end{pmatrix}\right\}`
5. Suponha que você tenha uma matriz escrita como
:math:`A = \begin{bmatrix}c\\d\end{bmatrix}\cdot\begin{bmatrix}a & b\end{bmatrix}`
para alguma escolha de valores :math:`a, b, c`,e :math:`d`.
Verdadeiro ou falso: o determinante dessa matriz é sempre :math:`0`?
6. Os vetores :math:`e_1 = \begin{bmatrix}1\\0\end{bmatrix}` e
:math:`e_2 = \begin{bmatrix}0\\1\end{bmatrix}` são ortogonais. Qual é
a condição em uma matriz :math:`A` para que :math:`Ae_1` e
:math:`Ae_2` sejam ortogonais?
7. Como você pode escrever :math:`\mathrm{tr}(\mathbf{A}^4)` na notação
de Einstein para uma matriz arbitrária :math:`A`?
.. raw:: html
.. raw:: html
`Discussões `__
.. raw:: html
.. raw:: html
`Discussões `__
.. raw:: html
.. raw:: html
`Discussões `__
.. raw:: html
.. raw:: html
.. raw:: html