Vamos aqui implementar o processo de ortonormalização de Gram-Schmidt numa linguagem de programação. Vamos admitir fixada uma base ortonormal e que os vetores são dados em coordenadas nessa base.
a) Escreva uma função que recebe dois vetores e retorna o produto escalar entre eles.
b) Escreva uma função que recebe um vetor e retorna seu comprimento.
c) Usando as funções acima, escreva uma função que recebe dois vetores e determina a projeção ortogonal do primeiro vetor sobre o segundo.
d) Com tudo isso, escreva uma função que recebe três vetores, supostamente L.I., que devolve uma base para V^3 com vetores mutuamente ortogonais, com pelo menos um deles paralelo a algum dos vetores originais.
Discussão: O que você espera como resultado, caso os vetores dados sejam linearmente dependentes? Justifique.
e) Escreva agora uma função que retorna uma base ortonormal de V^3 a partir de três vetores dados, supostamente L.I.
Discussão: O que você espera como resultado, caso os vetores fornecidos sejam L.D.? Justifique.

Passo 1

O enunciado pede para implementar o processo de Gram–Schmidt em cinco funções, cada uma correspondendo a um ponto (a)–(e). O conteúdo é Álgebra Linear (produto escalar, norma, projeção e ortonormalização). Vamos precisar das seguintes ideias:
1. Produto escalar em R^n: lang<= u,vrang<==sumi=1^n ui vi.
2. Norma (comprimento): |v|=raizlang<= v,vrang<=.
3. Projeção ortogonal: projv(u)=dfraclang<= u,vrang<=lang<= v,vrang<=,v.
4. Gram–Schmidt para três vetores:
w1=v1,
w2=v2-projw1(v2),
w3=v3-projw1(v3)-projw2(v3).
5. Normalização: ui=wi/|wi|.
Nas próximas etapas vamos definir cada função em pseudocódigo Python-like e discutir o que acontece se os vetores forem linearmente dependentes (LD).

Passo 2

Definindo a função do produto escalar:
def dot(u, v):
    """
    Retorna o produto escalar \(\langle u, v \rangle\) \(=\) sum(\(u_i\) * \(v_i\)).
    """
    assert len(u) \(==\) len(v), "Dimensões incompatíveis"
    total \(=0.0\)
    for ui, vi in zip(u, v):
        total \(+=\) ui * vi
    return total
Aqui usamos a definição de produto escalar em coordenadas de uma base ortonormal.

Passo 3

Definindo a função para o comprimento (norma):
import math

def norm(v):
    """
    Retorna a norma \(\|v\|\) \(=\) sqrt(\(\langle v,v \rangle\)).
    """
    return math.sqrt(dot(v, v))
Isso aplica a fórmula .

Passo 4

Definindo a projeção ortogonal de sobre :
def proj(u, v):
    """
    Retorna \(\operatorname{proj}_v(u)\) \(=\) \(\frac{\langle u,v \rangle}{\langle v,v \rangle} \cdot v\).
    Se \(v\) for o vetor zero, lança erro de divisão por zero.
    """
    denom \(=\) dot(v, v)
    if denom \(==0\):
        raise ValueError("Não é possível projetar sobre vetor zero")
    coef \(=\) dot(u, v) / denom
    return [coef * vi for vi in v]
Usamos a fórmula padrão de projeção e detectamos o caso , que ocorre se os vetores forem LD e gerarem um nulo.

Passo 5

Função que, dados três vetores supostamente LI, retorna vetores ortogonais :
def \(gs_orth\)(v\(1\), v\(2\), v\(3\)):
    """
    Gram–Schmidt ortogonal (não normaliza):
    w\(1=\) v\(1\)
    w\(2=\) v\(2\) - \(proj_w1\)(v\(2\))
    w\(3=\) v\(3\) - \(proj_w1\)(v\(3\)) - \(proj_w2\)(v\(3\))
    Se algum \(w_i\) for zero, sinal de LD.
    """
    w\(1=\) v\(1\)
    w\(2=\) [v\(2\)i - pi for v\(2\)i, pi in zip(v\(2\), proj(v\(2\), w\(1\)))]
    if norm(w\(2\)) \(==0\):
        raise ValueError("v\(1\) e v\(2\) são LD; não há base ortogonal completa")
    w\(3=\) [v\(3\)i - p\(1\)i - p\(2\)i 
          for v\(3\)i, p\(1\)i, p\(2\)i in zip(v\(3\), proj(v\(3\), w\(1\)), proj(v\(3\), w\(2\)))]
    if norm(w\(3\)) \(==0\):
        raise ValueError("v\(1\), v\(2\) e v\(3\) são LD; não há base ortogonal completa")
    return w\(1\), w\(2\), w\(3\)
Discussão d): se os vetores fornecidos forem LD, então pelo menos um dos fica zero e a função detecta divisão por zero ou norma zero, indicando que não se pode formar uma base de . Em vez de uma base de dimensão , obtém-se apenas uma base para o subespaço gerado (dimensão menor).

Passo 6

Função que retorna base ortonormal a partir de três vetores LI:
def \(gs_orthonormal\)(v\(1\), v\(2\), v\(3\)):
    """
    Gram–Schmidt completo com normalização:
    Primeiro obtém w\(1\), w\(2\), w\(3\) ortogonais (via \(gs_orth\)),
    depois normaliza cada um: ui \(=\) wi / ||wi||.
    """
    w\(1\), w\(2\), w\(3= gs_orth\)(v\(1\), v\(2\), v\(3\))
    u\(1=\) [wi / norm(w\(1\)) for wi in w\(1\)]
    u\(2=\) [wi / norm(w\(2\)) for wi in w\(2\)]
    u\(3=\) [wi / norm(w\(3\)) for wi in w\(3\)]
    return u\(1\), u\(2\), u\(3\)
Discussão e): se os vetores forem LD, a chamada a \(gs_orth\) já falha, e portanto não há como produzir uma base ortonormal completa em . O algoritmo indica a dependência linear.

Resposta

def dot(u, v):
    assert len(u) \(==\) len(v), "Dimensões incompatíveis"
    total \(=0.0\)
    for ui, vi in zip(u, v):
        total \(+=\) ui * vi
    return total

import math

def norm(v):
    return math.sqrt(dot(v, v))

def proj(u, v):
    denom \(=\) dot(v, v)
    if denom \(==0\):
        raise ValueError("Não é possível projetar sobre vetor zero")
    coef \(=\) dot(u, v) / denom
    return [coef * vi for vi in v]

def \(gs_orth\)(v\(1\), v\(2\), v\(3\)):
    w\(1=\) v\(1\)
    w\(2=\) [v\(2\)i - pi for v\(2\)i, pi in zip(v\(2\), proj(v\(2\), w\(1\)))]
    if norm(w\(2\)) \(==0\):
        raise ValueError("v\(1\) e v\(2\) são LD; não há base ortogonal completa")
    w\(3=\) [v\(3\)i - p\(1\)i - p\(2\)i 
          for v\(3\)i, p\(1\)i, p\(2\)i in zip(v\(3\), proj(v\(3\), w\(1\)), proj(v\(3\), w\(2\)))]
    if norm(w\(3\)) \(==0\):
        raise ValueError("v\(1\), v\(2\) e v\(3\) são LD; não há base ortogonal completa")
    return w\(1\), w\(2\), w\(3\)

def \(gs_orthonormal\)(v\(1\), v\(2\), v\(3\)):
    w\(1\), w\(2\), w\(3= gs_orth\)(v\(1\), v\(2\), v\(3\))
    u\(1=\) [wi / norm(w\(1\)) for wi in w\(1\)]
    u\(2=\) [wi / norm(w\(2\)) for wi in w\(2\)]
    u\(3=\) [wi / norm(w\(3\)) for wi in w\(3\)]
    return u\(1\), u\(2\), u\(3\)

Exercícios relacionados