Álgebra linear: representar, projetar e ajustar
Você recebeu um ajuste pronto que retorna dois números, mas ninguém consegue explicar se a ordem das colunas está correta. Seu trabalho será construir uma calculadora pequena e auditável, testar entradas inválidas e mostrar as contas que justificam cada saída. Não há download de dados ou serviço externo: todos os registros são sintéticos e cabem numa folha.
Comece desenhando a matriz e estimando a inclinação sem executar nada. Depois implemente funções com contratos explícitos. O laboratório retoma vetores e projeção da leitura, mas muda a atividade: agora buscamos evidências de correção, testes que falhem quando um erro é introduzido e limites documentados para a implementação.
JavaScriptMatemáticaAo terminar esta aula
- Resultados manuais funcionam como oráculos independentes.
- Uma propriedade pode detectar erros que uma única saída não revela.
- Entradas degeneradas devem gerar diagnóstico explícito.
Antes de continuar: Leitura: Álgebra linear: representar, projetar e ajustar
Preparar contratos antes da primeira função
FundamentosCrie um arquivo algebra.mjs para executar com Node. Escreva no caderno que dot recebe dois vetores finitos de igual comprimento e devolve um escalar. Escreva também que matvec recebe uma matriz não vazia e um vetor com dimensão igual ao comprimento de cada linha. Essas condições evitam um problema silencioso de JavaScript: multiplicar undefined pode gerar NaN, e uma redução que percorre apenas a primeira lista pode ignorar valores da segunda. Um teste precisa provocar cada um desses casos para mostrar que o contrato foi defendido.
Antes de implementar, calcule dot([1,2],[3,4])=11 e matvec([[1,0],[1,2]],[3,0.5])=[3,4]. Esses resultados manuais serão oráculos: referências independentes da função testada. Não gere a expectativa chamando a mesma função com outros nomes. Para números de ponto flutuante, compare diferenças absolutas com tolerância pequena neste exemplo, porque frações como 7/6 não têm representação binária exata. Uma tolerância absoluta fixa é suficiente para nossas magnitudes pequenas, mas um componente genérico precisa considerar escala relativa e erro acumulado.
Implementar e inspecionar a projeção
FundamentosA função project primeiro calcula v·v. Se o resultado for zero, ela deve lançar um erro antes de dividir. Depois calcula u·v, encontra o coeficiente e multiplica todas as coordenadas de v. Confira o caso [2,1] e [1,1] no papel: numerador três, denominador dois, saída [1.5,1.5]. Agora experimente trocar o denominador por uma norma sem quadrado. O programa ainda poderá retornar números plausíveis, porém falhará no teste de perpendicularidade. Esse experimento ensina a testar uma propriedade matemática, em vez de apenas observar um valor com aparência razoável.
O teste com direção [2,2] deve dar a mesma projeção. Registre por que esse teste é importante: a direção mudou de representação, mas a linha continuou a mesma. Se houver dificuldade, desenhe ambos os vetores sobre a diagonal do plano. Em seguida tente a direção [0,0] e um vetor contendo NaN. A resposta esperada é uma exceção descritiva, pois devolver um vetor de zeros esconderia a ausência de direção. Na revisão, dê um ponto por cada propriedade demonstrada: dimensão compatível, escala da direção e rejeição da direção nula.
Montar o ajuste e descobrir informação insuficiente
FundamentosPara ajustar a reta, acumule n, soma de x, soma de y, soma de x² e soma de xy. Nos dados da atividade, esses totais são 3, 3, 5, 5 e 6. O determinante n vezes soma de x² menos o quadrado da soma de x vale seis. Os numeradores do intercepto e da inclinação valem sete e três, respectivamente. Dividir por seis produz 7/6 e 0.5. Essa implementação de duas variáveis é legível para a investigação; ela não é uma recomendação para resolver sistemas grandes por fórmulas de determinantes.
Faça o caso negativo x=[1,1,1]. O determinante passa a ser zero, porque as colunas [1,1,1] e x descrevem a mesma direção. O laboratório deve parar com a mensagem colunas dependentes. É tentador somar uma quantidade minúscula ao denominador apenas para continuar, mas isso altera o problema sem explicitar a hipótese. Uma regularização pode ser uma decisão legítima em outra modelagem; aqui queremos detectar a impossibilidade de separar os parâmetros. Inclua essa diferença no relatório: erro de entrada, falta de identificação e decisão de modelagem são diagnósticos distintos.
Verificar resíduos e transformação de unidade
FundamentosDepois de obter theta, use matvec para produzir as três previsões. Subtraia previsão de observação, preservando a convenção da leitura. Calcule os produtos internos do resíduo com a coluna constante e com x. Ambos devem ser próximos de zero. Se somente a soma simples for zero, o intercepto pode estar correto enquanto a inclinação continua errada. Inverta de propósito os parâmetros e observe quais verificações quebram. Não interprete a quebra como falha de assert: ela mostra que o teste distingue uma solução válida de uma troca de colunas.
Repita o ajuste usando [0,100,200]. A inclinação deve ser 0.005 e cada previsão deve coincidir com a anterior. O teste percorre todos os registros, porque comparar apenas o primeiro ponto, onde x vale zero, não exercita a inclinação. Registre os resultados e escreva uma recomendação operacional limitada: a calculadora explica estas observações e detecta alguns erros básicos, mas três casos não bastam para escolher uma família de modelos. A aprovação exige contas manuais, propriedades executadas e uma limitação concreta; imprimir apenas os parâmetros não completa o laboratório.
import assert from 'node:assert/strict';
const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-10, String(a)+' != '+b);
function vector(v){
if(!Array.isArray(v)||!v.length||!v.every(Number.isFinite)) throw Error('vetor inválido');
}
function dot(a,b){
vector(a);vector(b);
if(a.length!==b.length) throw Error('dimensões diferentes');
return a.reduce((s,x,i)=>s+x*b[i],0);
}
function matvec(A,v){
vector(v);
if(!Array.isArray(A)||!A.length) throw Error('matriz vazia');
return A.map(row=>dot(row,v)); // Cada linha gera uma coordenada.
}
function project(u,v){
const denominator=dot(v,v);
if(denominator===0) throw Error('direção nula');
const coefficient=dot(u,v)/denominator;
return v.map(x=>coefficient*x);
}
function fitLine(x,y){
vector(x);vector(y);
if(x.length!==y.length) throw Error('amostras diferentes');
const n=x.length, sx=x.reduce((a,b)=>a+b,0), sy=y.reduce((a,b)=>a+b,0);
const sxx=dot(x,x), sxy=dot(x,y), determinant=n*sxx-sx*sx;
if(Math.abs(determinant)<1e-12) throw Error('colunas dependentes');
return [(sxx*sy-sx*sxy)/determinant,(n*sxy-sx*sy)/determinant];
}
const x=[0,1,2], y=[1,2,2], A=x.map(v=>[1,v]);
const theta=fitLine(x,y), predictions=matvec(A,theta);
const residual=y.map((v,i)=>v-predictions[i]);
near(theta[0],7/6);near(theta[1],0.5);
near(dot(residual,[1,1,1]),0);near(dot(residual,x),0);
near(dot(residual,residual),1/6);
const projected=project([2,1],[1,1]);
assert.deepEqual(projected,[1.5,1.5]);
near(dot([0.5,-0.5],[1,1]),0);
const scaled=fitLine(x.map(v=>100*v),y);
near(scaled[1],0.005);
assert.ok(scaled.every(Number.isFinite));
matvec(x.map(v=>[1,100*v]),scaled).forEach((v,i)=>near(v,predictions[i]));
assert.throws(()=>dot([1],[1,2]),/dimensões/);
assert.throws(()=>project([1,2],[0,0]),/nula/);
assert.throws(()=>fitLine([1,1,1],y),/dependentes/);
assert.throws(()=>dot([NaN],[1]),/inválido/);
console.log({theta,predictions,residual,sse:dot(residual,residual)});Exercício aplicado
Entregue uma calculadora de álgebra com relatório auditável do ajuste de três pedidos.
- Implemente dot, matvec e project com rejeição de dimensão incorreta, NaN e direção nula.
- Ajuste os dados [0,1,2] e [1,2,2] usando os totais do sistema de duas equações.
- Calcule previsões, resíduos, perpendicularidade e soma dos quadrados.
- Refaça o ajuste com tamanho multiplicado por cem e rejeite tamanhos constantes.
Abrir resolução comentada
O programa completo inclui verificações executáveis para cada etapa. A função dot centraliza a validação dos vetores; matvec usa uma chamada por linha, o que também detecta linhas de tamanho incorreto. A projeção rejeita direção nula e retorna o vetor completo. O cálculo dos parâmetros usa os totais conferidos no caderno e não depende de pacote numérico externo.
As asserções de resíduos demonstram as duas condições do ajuste. A asserção de SSE confirma 1/6. No teste de unidade, percorremos todas as previsões após dividir a inclinação por cem. Os casos de dimensão, NaN e colunas dependentes precisam lançar exceções; retirar uma guarda deve fazer a respectiva asserção falhar. Esse procedimento transforma o código em uma demonstração pequena, com entradas, expectativas e falhas observáveis.
Avalie seu relatório com quatro critérios de igual peso: contas independentes, contratos defendidos, propriedades geométricas e limites explicados. Um resultado final correto sem justificar os resíduos recebe apenas parte da evidência. Para avançar, explique como a transformação matriz-vetor reaparecerá como soma ponderada em um neurônio; essa retomada conecta a calculadora à unidade de redes sem atribuir significado semântico automático às coordenadas.
import assert from 'node:assert/strict';
const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-10, String(a)+' != '+b);
function vector(v){
if(!Array.isArray(v)||!v.length||!v.every(Number.isFinite)) throw Error('vetor inválido');
}
function dot(a,b){
vector(a);vector(b);
if(a.length!==b.length) throw Error('dimensões diferentes');
return a.reduce((s,x,i)=>s+x*b[i],0);
}
function matvec(A,v){
vector(v);
if(!Array.isArray(A)||!A.length) throw Error('matriz vazia');
return A.map(row=>dot(row,v)); // Cada linha gera uma coordenada.
}
function project(u,v){
const denominator=dot(v,v);
if(denominator===0) throw Error('direção nula');
const coefficient=dot(u,v)/denominator;
return v.map(x=>coefficient*x);
}
function fitLine(x,y){
vector(x);vector(y);
if(x.length!==y.length) throw Error('amostras diferentes');
const n=x.length, sx=x.reduce((a,b)=>a+b,0), sy=y.reduce((a,b)=>a+b,0);
const sxx=dot(x,x), sxy=dot(x,y), determinant=n*sxx-sx*sx;
if(Math.abs(determinant)<1e-12) throw Error('colunas dependentes');
return [(sxx*sy-sx*sxy)/determinant,(n*sxy-sx*sy)/determinant];
}
const x=[0,1,2], y=[1,2,2], A=x.map(v=>[1,v]);
const theta=fitLine(x,y), predictions=matvec(A,theta);
const residual=y.map((v,i)=>v-predictions[i]);
near(theta[0],7/6);near(theta[1],0.5);
near(dot(residual,[1,1,1]),0);near(dot(residual,x),0);
near(dot(residual,residual),1/6);
const projected=project([2,1],[1,1]);
assert.deepEqual(projected,[1.5,1.5]);
near(dot([0.5,-0.5],[1,1]),0);
const scaled=fitLine(x.map(v=>100*v),y);
near(scaled[1],0.005);
assert.ok(scaled.every(Number.isFinite));
matvec(x.map(v=>[1,100*v]),scaled).forEach((v,i)=>near(v,predictions[i]));
assert.throws(()=>dot([1],[1,2]),/dimensões/);
assert.throws(()=>project([1,2],[0,0]),/nula/);
assert.throws(()=>fitLine([1,1,1],y),/dependentes/);
assert.throws(()=>dot([NaN],[1]),/inválido/);
console.log({theta,predictions,residual,sse:dot(residual,residual)});Como conferir seu resultado
- Todos os casos negativos lançam erro.
- Ajuste retorna [7/6,0.5] com SSE=1/6.
- Resíduo é perpendicular às duas colunas.
- Escala de x altera parâmetro e preserva as três previsões.
Teste sua compreensão
Responda com suas palavras antes de abrir o comentário. Saber explicar uma decisão é parte do domínio.
1. Por que conferir somente a previsão de x=0 não testa a inclinação?
Porque o termo m×x é zero nesse ponto.
O teste precisa exercitar valores não nulos para detectar troca ou escala errada.
2. Qual verificação detecta uma projeção que não é a mais próxima?
Produto interno do resíduo com a direção diferente de zero.
O restante da projeção correta é perpendicular à direção permitida.
3. Por que rejeitamos [1,1,1] como tamanhos para separar b e m?
Porque as colunas são dependentes.
As observações identificam uma combinação dos parâmetros, não cada um separadamente.
Seu progresso fica salvo neste navegador. Concluir a leitura não substitui demonstrar o domínio nos exercícios.
Referências e aprofundamento
Documentação oficial e trabalhos originais. As referências registram o escopo e as limitações para você conferir o que sustentam.
- 18.06 Linear Algebra — syllabus
MIT OpenCourseWare • consulta: 2026-10-06
MatemáticaVetores, sistemas lineares, projeções e mínimos quadrados como fundamentos da disciplina.
Limites: Programa da disciplina de 2010; exemplos numéricos e implementação desta preparação são originais e não cobrem o curso completo.