“Can machines think?”

Alan Turing

22 - Inteligência Artificial

Inteligência artificial voltou ao centro do debate tecnológico mundial com força renovada. Sistemas capazes de reconhecer imagens, recomendar conteúdo, traduzir textos, auxiliar diagnósticos, dirigir veículos em contextos controlados e interagir em linguagem natural passaram a fazer parte do cotidiano. A popularização recente de modelos generativos e assistentes conversacionais deu a impressão de que a IA surgiu de repente, mas essa revolução atual repousa sobre fundamentos construídos ao longo de décadas: busca em espaços de estados, representação de conhecimento, inferência lógica, raciocínio probabilístico, aprendizado a partir de dados e atuação de agentes em ambientes incertos.

Uma boa maneira de compreender a área é pensar que a IA tenta construir sistemas capazes de decidir em contextos nos quais não basta seguir uma sequência fixa de instruções. Em problemas simples, um algoritmo tradicional pode ser detalhado passo a passo. Em IA, porém, frequentemente há alternativas demais, informação incompleta, objetivos concorrentes, sinais ruidosos ou necessidade de adaptação. O sistema precisa representar o problema, explorar caminhos, revisar hipóteses, aprender padrões, atualizar crenças e agir de forma coerente mesmo sem certeza total.

Este capítulo organiza esses fundamentos em uma sequência progressiva. Começamos com abordagens simbólicas, programação em lógica e resolução de problemas como busca. Em seguida, estudamos estratégias heurísticas, esquemas de representação de conhecimento, sistemas de produção, raciocínio não monotônico e tratamento de incerteza por meios probabilísticos e fuzzy. Depois, passamos para aprendizado de máquina, aprendizado indutivo, árvores de decisão, redes neurais, algoritmos genéticos, sistemas especialistas, processamento de linguagem natural, agentes inteligentes e robótica. O objetivo é conectar os fundamentos clássicos da IA com a transformação atual provocada por sistemas orientados por dados em larga escala.

22.1 - Linguagens Simbólicas.

Linguagens simbólicas representam conhecimento por meio de símbolos, relações e regras explícitas. Em vez de aprender diretamente a partir de muitos exemplos, como fazem grande parte dos métodos estatísticos modernos, essa abordagem procura descrever o domínio em uma forma manipulável por operações lógicas. Um símbolo pode representar um objeto, como joao; um predicado pode representar uma relação, como matriculado(joao, algebra); e uma regra pode expressar conhecimento geral, como “todo aluno matriculado em uma disciplina precisa de um professor associado a ela”.

Uma analogia útil é pensar em uma linguagem simbólica como um arquivo jurídico ou um código de regulamentos. Cada ficha guarda fatos; cada artigo guarda uma regra; e o sistema atua como um intérprete que verifica se uma conclusão pode ser derivada a partir do material disponível. Isso contrasta com um modelo puramente estatístico, que se comporta mais como alguém que aprendeu por exposição a muitos exemplos e passou a reconhecer padrões sem necessariamente explicitar cada regra usada.

Contexto Histórico

O desenvolvimento das linguagens simbólicas está ligado aos primeiros anos da inteligência artificial. Na década de 1950, Allen Newell, Cliff Shaw e Herbert Simon criaram a família IPL (Information Processing Language) para apoiar programas como o Logic Theorist, um dos primeiros sistemas de IA voltados à prova de teoremas e resolução heurística de problemas. A importância histórica da IPL foi enorme porque ela introduziu mecanismos de manipulação de listas e estruturas simbólicas muito mais adequados para raciocínio do que as linguagens numéricas voltadas apenas a cálculo científico.

Logo depois, John McCarthy propôs Lisp, formalizada em 1960, como uma linguagem capaz de tratar expressões simbólicas de maneira elegante e recursiva. Se IPL foi um primeiro passo operacional, Lisp se tornou o grande veículo do paradigma simbólico por várias décadas. Ela facilitou a representação de listas, árvores, fórmulas e programas como dados, algo especialmente valioso em IA. Mais tarde, o desenvolvimento da programação em lógica levou à criação de Prolog no início dos anos 1970, ligando ainda mais fortemente linguagens de IA à dedução automática, à prova dirigida por objetivos e à representação declarativa do conhecimento.

Essa trajetória não foi apenas tecnológica, mas também conceitual. Em Programs with Common Sense, McCarthy defendeu a ideia de um advice taker, isto é, um programa que pudesse receber conhecimento expresso em linguagem formal e tirar dele consequências lógicas automaticamente. Essa proposta ajudou a consolidar a ambição central da IA simbólica: construir sistemas capazes de raciocinar sobre o mundo por manipulação estruturada de símbolos, e não apenas por cálculo numérico.

Relação com Inteligência Geral

O paradigma simbólico teve um papel central nas primeiras formulações de inteligência artificial geral. A hipótese era que comportamento inteligente poderia ser obtido se o sistema conseguisse representar fatos, objetivos e relações em uma linguagem formal suficientemente expressiva e operar sobre eles com mecanismos adequados de busca e inferência. Essa visão foi explicitada de forma famosa por Newell e Simon na hipótese do sistema físico de símbolos, segundo a qual um sistema simbólico teria os meios necessários e suficientes para ação inteligente geral.

Em termos intuitivos, a aposta era a seguinte: se um ser inteligente consegue planejar, provar, explicar, abstrair e reorganizar conhecimento, então talvez o núcleo desse comportamento esteja na manipulação estruturada de representações internas. Nessa visão, símbolos funcionariam como blocos de construção do pensamento, do mesmo modo que palavras, fórmulas e diagramas funcionam como blocos de raciocínio humano em muitos domínios formais.

Problemas de Complexidade e Limitações

Apesar de seu poder conceitual, a IA simbólica enfrenta dificuldades importantes quando o domínio estudado se torna muito grande, incerto ou dinâmico. A primeira delas é a explosão combinatória: o número de estados, combinações ou cadeias possíveis de inferência pode crescer muito rapidamente. Se um problema de busca tem fator de ramificação $b$ e profundidade $d$, o número de possibilidades cresce da ordem de $b^d$, o que inviabiliza exploração exaustiva em muitos casos práticos.

Outro problema clássico é a fragilidade diante de exceções e contexto. Um sistema que conhece a regra “aves voam” precisa de mecanismos adicionais para tratar exceções como pinguins, avestruzes ou aves feridas. Quanto mais complexo o domínio, mais difícil se torna escrever e manter uma base de regras completa, coerente e atualizada. É nesse ponto que aparecem gargalos como a aquisição de conhecimento, isto é, a dificuldade de extrair de especialistas humanos um conjunto robusto de regras formais, e o chamado problema do quadro, ligado à dificuldade de representar de modo eficiente o que muda e o que permanece igual após uma ação.

Uma analogia útil é a de tentar escrever, em forma de manual, tudo o que uma pessoa sabe sobre dirigir no trânsito de uma cidade grande. Não basta listar regras de código; seria preciso contemplar exceções, prioridades contextuais, situações raras, ambiguidades e mudanças em tempo real. Em muitos domínios, o conhecimento cresce mais rápido do que a capacidade de explicitá-lo manualmente.

Linguagens Mais Associadas ao Paradigma

Historicamente, três famílias de linguagens aparecem com frequência no desenvolvimento da IA simbólica:

  • IPL: pioneira no tratamento operacional de estruturas simbólicas e listas, ligada aos primeiros programas de prova e resolução de problemas.
  • Lisp e suas derivadas, como Scheme e Common Lisp: centrais para manipulação de listas, recursão, meta-programação e construção de sistemas especialistas, planejadores e ambientes de pesquisa em IA.
  • Prolog e a tradição da programação em lógica: fundamentais para representação declarativa, unificação, consulta a bases de conhecimento e prova orientada a objetivos.

Um exemplo muito simples em Lisp é representar conhecimento como lista e operar sobre ele recursivamente:

(defparameter *fatos* '((humano socrates)
                      (humano platao)))

(defun mortal-p (x)
  (member (list 'humano x) *fatos* :test #'equal))

(mortal-p 'socrates) ; retorna verdadeiro porque socrates esta em *fatos*

Nesse trecho, os fatos são armazenados como listas. A linguagem trata código e dados com estruturas semelhantes, o que historicamente favoreceu experimentação em IA. A ideia não é apenas guardar valores, mas representar relações simbólicas manipuláveis.

Já em Prolog, o mesmo tipo de conhecimento pode ser expresso assim:

humano(socrates).
humano(platao).
mortal(X) :- humano(X).

A consulta ?- mortal(socrates). pergunta se a conclusão pode ser provada. Nesse caso, a resposta é positiva porque a regra mortal(X) :- humano(X). se aplica ao fato humano(socrates). Uma analogia simples é pensar que Lisp tende a favorecer construção de estruturas e procedimentos sobre símbolos, enquanto Prolog favorece declaração de fatos e prova de relações.

Exemplo Lógico Básico

Se temos o fato humano(socrates) e a regra “todo humano é mortal”, podemos escrever em lógica de predicados:

$$ \forall x \, (humano(x) \rightarrow mortal(x)) $$

Nessa notação, $\forall x$ significa “para todo $x$”, e $\rightarrow$ significa “implica”. A fórmula pode ser lida assim: “para qualquer elemento $x$, se $x$ é humano, então $x$ é mortal”. A partir dela e do fato humano(socrates), concluímos mortal(socrates). O valor didático desse exemplo está em mostrar como o raciocínio fica explícito, auditável e reaplicável.

Textos Fundamentais

Alguns textos são especialmente importantes para entender a formação histórica do paradigma simbólico em IA:

A principal vantagem das linguagens simbólicas continua sendo a interpretabilidade e a capacidade de estruturar raciocínio explícito. Sua principal limitação aparece quando o domínio é grande demais, incerto demais ou mutável demais para ser descrito manualmente de forma completa. Por isso, a IA contemporânea frequentemente combina componentes simbólicos com aprendizado a partir de dados, buscando unir explicabilidade e capacidade adaptativa.

22.2 - Programação em Lógica.

Programação em lógica é um paradigma declarativo no qual o problema é descrito em termos de fatos, regras e consultas. Em vez de detalhar passo a passo como a solução deve ser executada, o programador declara o conhecimento do domínio e deixa para o sistema a tarefa de procurar provas, unificar termos e explorar alternativas. Essa mudança de perspectiva é profunda: em programação imperativa, costumamos dizer ao computador “faça isto, depois aquilo”; em programação em lógica, descrevemos “o que deve ser verdadeiro” e perguntamos se isso pode ser demonstrado.

Uma analogia útil é a de um investigador com acesso a um arquivo de fatos e a um conjunto de leis de inferência. O investigador não recebe um roteiro fixo de execução; ele recebe uma pergunta e tenta provar a resposta combinando registros disponíveis e regras gerais. É por isso que a programação em lógica é especialmente atraente em problemas de dedução, consulta inteligente, prova automática, interpretação de regras e construção de sistemas especialistas.

Contexto Histórico

A programação em lógica surgiu da aproximação entre duas tradições: a prova automática de teoremas e o desejo de construir linguagens mais adequadas para representação e raciocínio em IA. Nos anos 1960 e início dos anos 1970, Robert Kowalski trabalhou em procedimentos de resolução para prova automática, enquanto Alain Colmerauer e colaboradores, em Marselha, exploravam problemas de processamento de linguagem natural. Dessa convergência nasceu o Prolog, cujo primeiro sistema operacional apareceu em 1972. O nome vem de PROgrammation en LOGique.

Historicamente, o ponto decisivo foi perceber que um subconjunto bem escolhido da lógica de predicados podia servir não apenas para provar teoremas, mas também como base de programação. A ideia ficou famosa na fórmula associada a Kowalski: Algorithm = Logic + Control. Em termos intuitivos, isso significa que um programa pode ser visto como a combinação entre uma descrição lógica do problema e um mecanismo operacional que decide como explorar essa descrição.

Forma das Regras

Uma regra típica pode ser escrita na forma:

$$ H \leftarrow B_1, B_2, \ldots, B_n $$

A expressão se lê: “$H$ é verdadeiro se $B_1, B_2, \ldots, B_n$ forem verdadeiros”. A cabeça da regra é $H$; o corpo é a sequência das premissas. O símbolo $\leftarrow$ pode ser lido como “se”. Fatos são regras sem corpo. Consultas perguntam se certo objetivo pode ser provado.

Se quisermos escrever “todo avô é alguém que é pai de um pai”, usamos algo como:

$$ avo(X, Y) \leftarrow pai(X, Z), pai(Z, Y) $$

Nessa fórmula, $X$, $Y$ e $Z$ são variáveis. A vírgula significa conjunção, isto é, “e”. Portanto, a regra se lê: “$X$ é avô de $Y$ se existe algum $Z$ tal que $X$ é pai de $Z$ e $Z$ é pai de $Y$”. Essa notação costuma parecer estranha no começo, mas conceitualmente ela é apenas uma regra declarativa.

Exemplo Computacional em Prolog

Um pequeno exemplo computacional em Prolog ajuda:

pai(joao, maria).
pai(maria, ana).
avo(X, Y) :- pai(X, Z), pai(Z, Y).

A consulta ?- avo(joao, ana). pergunta se joao é avô de ana. O sistema tenta provar esse objetivo encontrando uma substituição válida para as variáveis. Primeiro, tenta casar a consulta com a cabeça da regra avo(X, Y), obtendo a substituição inicial X = joao e Y = ana. Depois, precisa provar o corpo: encontrar um Z tal que pai(joao, Z) e pai(Z, ana). Como os fatos indicam pai(joao, maria) e pai(maria, ana), a prova se fecha com Z = maria.

Fluxo simplificado de programação em lógica com fatos, regras, consulta, unificação e prova.
Figura 1. Em programação em lógica, uma consulta é resolvida tentando casar objetivos com fatos e regras por unificação e busca.
Unificação e Busca

O mecanismo central por trás desse processo é a unificação. Unificar significa encontrar uma substituição de variáveis que torne duas expressões compatíveis. Por exemplo, pai(X, ana) unifica com pai(maria, ana) usando a substituição X = maria. Já pai(X, ana) não unifica com pai(maria, joao), porque o segundo argumento é diferente.

Uma analogia simples é pensar em moldes com espaços em branco. A expressão pai(X, ana) funciona como um molde em que o primeiro espaço ainda não foi preenchido. Quando o sistema encontra pai(maria, ana), ele encaixa maria no lugar de X. A programação em lógica combina essa operação de encaixe com busca sistemática por alternativas.

Essa busca geralmente é feita com retrocesso, ou backtracking. Se um caminho de prova falha, o sistema volta ao último ponto de escolha e tenta outra possibilidade. Em termos computacionais, é como explorar um corredor de possibilidades e, ao encontrar um beco sem saída, retornar ao cruzamento anterior.

Exemplo Matemático de Consulta

Considere agora o predicado recursivo de ancestralidade:

ancestral(X, Y) :- pai(X, Y).
ancestral(X, Y) :- pai(X, Z), ancestral(Z, Y).

Se temos os fatos pai(joao, maria), pai(maria, ana) e pai(ana, clara), então a consulta ?- ancestral(joao, clara). pode ser entendida matematicamente como a tentativa de provar a existência de uma cadeia:

$$ pai(joao, z_1) \land pai(z_1, z_2) \land pai(z_2, clara) $$

A prova se fecha com $z_1 = maria$ e $z_2 = ana$. Esse tipo de exemplo mostra como relações recursivas em lógica podem representar fechos transitivos, hierarquias, genealogias, dependências e caminhos em grafos.

Aplicações e Dificuldades

A programação em lógica foi especialmente importante em consulta a bases de conhecimento, linguagem natural, prova automática, planejamento e sistemas especialistas. Ela também influenciou fortemente bancos de dados dedutivos e linguagens de regras. Seu grande valor didático está em mostrar que computar pode significar provar.

Sua limitação aparece quando o espaço de busca cresce demais, quando o controle do retrocesso se torna caro ou quando o domínio depende fortemente de incerteza, ruído e dados não estruturados. Nesses casos, o paradigma pode precisar ser combinado com heurísticas, restrições adicionais ou métodos estatísticos. Ainda assim, ele permanece central na história da IA porque explicita de maneira particularmente clara a ligação entre lógica, inferência e computação.

22.3 - Resolução de Problemas como Busca.

Muitos problemas clássicos de inteligência artificial podem ser formulados como problemas de busca em um espaço de estados. Essa formulação é uma das ideias mais influentes de toda a área, porque transforma tarefas aparentemente muito diferentes em uma estrutura comum: há uma configuração inicial, um conjunto de transformações possíveis e uma meta a alcançar. Resolver o problema passa a significar encontrar uma sequência de ações que leva do estado inicial a um estado objetivo.

Historicamente, essa visão ganhou força nos primeiros trabalhos de Newell e Simon, especialmente no Logic Theorist e, depois, no General Problem Solver. A aposta conceitual era poderosa: talvez muitos comportamentos inteligentes possam ser entendidos como exploração organizada de alternativas em espaços de possibilidades. Em vez de tratar cada tarefa como algo totalmente distinto, a IA passou a perguntar se o problema poderia ser descrito por estados, operadores e critérios de sucesso.

Uma analogia direta é a de um labirinto. Cada posição do explorador é um estado; cada movimento permitido é um operador; a saída é a meta. Em IA, porém, o “labirinto” raramente é físico. Ele pode ser uma configuração de peças em um quebra-cabeça, um cronograma em construção, um tabuleiro de jogo, a rota de um robô, uma sequência de transformações algébricas ou o estado interno de um sistema que tenta provar um teorema. A grande força da formulação por busca é justamente essa abstração.

Elementos da Formulação

Ao modelar um problema como busca, normalmente definimos quatro componentes centrais:

  1. estado inicial, isto é, a configuração de partida;
  2. ações ou operadores, que descrevem transições possíveis;
  3. teste de objetivo, que decide se a meta foi alcançada;
  4. custo de caminho, quando queremos comparar soluções melhores e piores.

Essa estrutura pode ser representada matematicamente por um grafo $G = (V, E)$, em que $V$ é o conjunto de estados e $E$ o conjunto de transições permitidas. Nem sempre o problema é implementado literalmente como grafo explícito, mas essa visão é muito útil. Em muitos casos, o grafo é gerado implicitamente à medida que os operadores são aplicados.

Espaço de estados com estado inicial, operadores, estados intermediários e estado meta.
Figura 2. Resolver um problema como busca significa explorar um espaço de estados até encontrar um caminho entre a configuração inicial e a meta.
Exemplo Matemático Elementar

Considere um problema simples: sair do número 2 e chegar ao número 9 usando apenas duas operações, “somar 2” e “multiplicar por 2”. O estado inicial é 2. A partir dele, podemos gerar novos estados: de 2 vamos para 4; de 4 podemos ir para 6 ou 8; de 6 podemos ir para 8 ou 12; e assim por diante. Se a meta for alcançar exatamente 10, um caminho possível é $2 \rightarrow 4 \rightarrow 8 \rightarrow 10$. Se a meta for 9, o problema não tem solução com esses operadores. Esse exemplo mostra que, antes mesmo de escolher um algoritmo, é preciso formular corretamente o espaço de estados e verificar se a meta é alcançável.

Um segundo exemplo matemático aparece no problema dos jarros. Suponha um jarro de 4 litros e outro de 3 litros. O objetivo é obter exatamente 2 litros em algum deles. Cada estado pode ser representado por um par ordenado $(x, y)$, em que $x$ é a quantidade no jarro de 4 litros e $y$ a quantidade no jarro de 3 litros. O estado inicial é $(0,0)$. Operadores incluem encher um jarro, esvaziá-lo e transferir água de um para o outro. Nesse caso, modelar o problema como busca significa definir formalmente quais pares são estados válidos e quais transições entre pares são permitidas.

Esse tipo de representação por pares, tuplas ou vetores é muito comum. Em geral, quanto melhor a representação matemática do estado, mais clara fica a busca e mais fácil se torna medir custo, distância e viabilidade de operadores.

Exemplo Computacional

Em termos computacionais, formular um problema como busca muitas vezes significa escrever uma função que, dado um estado, gere seus sucessores. Em pseudocódigo, isso pode aparecer assim:

estado_inicial = 2
meta = 10

def sucessores(x):
    return [x + 2, x * 2]

O algoritmo de busca não precisa conhecer antecipadamente todos os estados possíveis; ele pode gerá-los conforme a exploração avança. Essa é uma ideia importante em problemas grandes: o espaço de estados pode ser conceitualmente enorme, mas apenas uma fração dele será visitada na prática.

Em um exemplo mais moderno, considere navegação em mapas digitais. Cada interseção pode ser modelada como estado, cada rua como transição e o custo como tempo estimado de percurso. Em robótica móvel, o estado pode incluir posição, orientação e até nível de bateria. Em jogos digitais, o estado pode incluir a posição de todas as peças, pontuação, recursos disponíveis e turno do jogador. Em IA contemporânea, a mesma formulação também aparece em planejamento automático, compiladores otimizadores, sistemas de recomendação com restrições e resolução de problemas combinatórios em larga escala.

Propriedades Fundamentais

Ao avaliar algoritmos de busca, quatro propriedades aparecem com frequência: completude, optimalidade, complexidade de tempo e complexidade de espaço. Completude pergunta se o método encontra uma solução sempre que ela existe. Optimalidade pergunta se a solução encontrada é a melhor segundo algum critério de custo. Complexidade de tempo mede o esforço computacional; complexidade de espaço mede o consumo de memória.

Essas propriedades são inseparáveis da matemática do problema. Se um espaço de estados tem fator de ramificação $b$ e a solução está na profundidade $d$, então muitos algoritmos podem ter custo de exploração proporcional a ordens como $b^d$. Aqui, $b$ representa o número médio de sucessores gerados por estado, e $d$ representa a profundidade da solução. Essa notação aparece frequentemente em IA porque resume, de forma compacta, por que certos problemas se tornam tão difíceis: mesmo valores modestos de $b$ e $d$ podem produzir explosão combinatória.

Por exemplo, se $b = 3$ e $d = 10$, então $b^d = 3^{10} = 59049$. Se $b = 10$ e $d = 8$, então $b^d = 10^8 = 100000000$. Essa diferença numérica ilustra por que escolher uma boa formulação do estado e bons operadores pode ser tão importante quanto escolher o algoritmo em si.

Relações com Matemática

Problemas de busca se conectam diretamente com grafos, árvores, combinatória, recorrência, otimização e teoria da complexidade. Quando representamos estados como vértices e operadores como arestas, já estamos usando linguagem de teoria dos grafos. Quando avaliamos quantos caminhos ou configurações existem, entramos em contagem combinatória. Quando comparamos custo e profundidade, trabalhamos com noções algorítmicas de crescimento assintótico. Essa é uma das razões pelas quais IA clássica dialoga tão fortemente com matemática discreta e análise de algoritmos.

Problemas Modernos

A formulação de problemas como busca continua extremamente atual. Mesmo em sistemas modernos guiados por aprendizado, vários subproblemas permanecem estruturados como busca. Modelos generativos podem explorar espaços de alternativas; agentes autônomos planejam sequências de ações; sistemas de logística resolvem roteamento e escalonamento; ferramentas de projeto automatizado buscam configurações ótimas em espaços combinatórios. Em muitos desses casos, o aprendizado fornece boas heurísticas, mas a espinha dorsal decisória ainda pode ser entendida como exploração de um espaço de estados.

Em resumo, formular problemas como busca é uma das maneiras mais poderosas de tornar tratável o raciocínio computacional em IA. A formulação não resolve tudo sozinha, mas fornece um quadro geral no qual diferentes algoritmos, heurísticas e critérios de custo podem ser comparados com clareza.

22.4 - Estratégias de Busca, Busca Cega e Busca Heurística.

Depois de formular um problema como busca, a pergunta seguinte é: em que ordem explorar os estados possíveis? É exatamente isso que uma estratégia de busca define. Duas abordagens gerais aparecem com frequência: busca cega, também chamada de não informada, e busca heurística, também chamada de informada. A diferença entre elas não está no problema em si, mas no tipo de orientação adicional que o algoritmo utiliza para decidir qual nó expandir primeiro.

Na busca cega, o algoritmo conhece apenas a estrutura formal do problema: estado inicial, operadores, teste de objetivo e, em alguns casos, custos. Ele não dispõe de uma estimativa sobre quais caminhos parecem mais promissores. Já na busca heurística, introduzimos uma função de avaliação capaz de orientar a exploração. Em termos intuitivos, a diferença é parecida com procurar um endereço em uma cidade desconhecida com ou sem mapa. No primeiro caso, testamos caminhos segundo uma regra geral de exploração; no segundo, temos uma noção de direção ou proximidade que ajuda a reduzir tentativas desnecessárias.

Contexto Histórico

Historicamente, a distinção entre busca cega e busca heurística foi central para o desenvolvimento da IA clássica. Os primeiros sistemas, como o Logic Theorist e o General Problem Solver, deixaram claro que não bastava representar o problema: era preciso também decidir como navegar no espaço de estados. Muito cedo ficou evidente que uma exploração puramente exaustiva se tornava inviável em problemas de grande porte. A noção de heurística ganhou força exatamente como tentativa de capturar “pistas úteis” sobre o domínio para tornar a busca mais eficiente sem precisar examinar tudo.

Busca Cega

Entre os métodos cegos mais clássicos estão busca em largura, busca de custo uniforme, busca em profundidade, profundidade limitada e aprofundamento iterativo. Eles diferem, sobretudo, na política de expansão da fronteira. A busca em largura expande primeiro os nós mais rasos; a busca em profundidade aprofunda um ramo o máximo possível antes de retroceder; a busca de custo uniforme sempre escolhe o nó com menor custo acumulado até então.

A analogia do prédio ajuda bastante. Imagine que você procura uma sala específica em um edifício. Na busca em largura, você visita todos os cômodos do primeiro andar antes de subir; na busca em profundidade, entra em um corredor e vai até o fim antes de reconsiderar outras opções; na busca de custo uniforme, você escolheria o próximo movimento considerando um custo como tempo, distância ou esforço. Nenhuma dessas estratégias usa conhecimento direto sobre “qual sala parece mais próxima da sala correta”; elas se orientam apenas por uma regra geral de exploração.

Matematicamente, se uma árvore de busca tem fator de ramificação $b$ e profundidade de solução $d$, então a busca em largura pode visitar uma quantidade de nós da ordem de:

$$ 1 + b + b^2 + \cdots + b^d $$

Se $b = 4$ e $d = 6$, por exemplo, essa soma vale:

$$ 1 + 4 + 16 + 64 + 256 + 1024 + 4096 = 5461 $$

Esse número já é considerável para um problema pequeno. Quando $b$ e $d$ crescem, o custo explode rapidamente. Essa observação matemática explica por que métodos cegos, apesar de conceitualmente limpos, tornam-se caros em muitos problemas reais.

Comparação visual entre exploração ampla de busca cega e exploração guiada por heurística.
Figura 3. A busca cega segue uma política fixa de exploração; a busca heurística tenta priorizar estados mais promissores.
Busca Heurística

Na busca heurística, o algoritmo usa informação adicional sobre o domínio para estimar a qualidade de um estado ou sua distância até a meta. Essa estimativa costuma ser expressa por uma função $h(n)$, em que $n$ representa um nó. A função não precisa ser perfeita; ela precisa apenas ser útil. Em navegação, por exemplo, a distância em linha reta até o destino pode servir como heurística. Em um quebra-cabeça, o número de peças fora do lugar pode ser uma estimativa simples de quão longe estamos da solução.

Uma analogia muito direta é a de um estudante resolvendo um quebra-cabeça. Um aluno sem heurística tenta movimentos quase às cegas; outro usa uma pista como “aproxime primeiro as peças de borda” ou “priorize peças com cores parecidas com a região alvo”. A heurística não garante acerto imediato, mas reduz a exploração desordenada.

Em termos matemáticos, a heurística pode ser vista como uma função:

$$ h : V \to \mathbb{R} $$

Isso significa que cada estado do conjunto $V$ recebe um valor real que expressa sua prioridade, distância estimada ou atratividade. A notação $\mathbb{R}$ representa o conjunto dos números reais. Em busca heurística, esses valores são usados para ordenar a fronteira de expansão.

Comparação por Exemplo

Considere um problema de caminho em grade em que um robô deve sair da posição $(0,0)$ e chegar à posição $(5,4)$. A busca cega em largura trata muitos estados na mesma profundidade como igualmente promissores, ainda que estejam em direções claramente menos úteis. Já uma heurística como a distância Manhattan, dada por

$$ h(x, y) = |x - 5| + |y - 4| $$

fornece uma estimativa simples de quão longe o robô está da meta quando os movimentos são horizontais e verticais. Aqui, as barras verticais representam valor absoluto. Se o robô está em $(1,2)$, então:

$$ h(1,2) = |1-5| + |2-4| = 4 + 2 = 6 $$

Essa conta não resolve o problema sozinha, mas já fornece uma pista concreta sobre quais estados parecem mais próximos do objetivo.

Exemplo Computacional

Em um programa, a diferença entre busca cega e heurística aparece muitas vezes apenas no critério de ordenação da fronteira. Em pseudocódigo, poderíamos ter algo assim:

# busca cega em largura
fronteira = fila()

# busca heuristica
fronteira = fila_de_prioridade(chave = h(n))

O espaço de estados continua o mesmo; o que muda é a política de priorização. Essa observação é importante didaticamente, porque mostra que heurística não substitui a formulação do problema: ela orienta a exploração dentro de uma formulação já existente.

Problemas Modernos

Em aplicações modernas, a diferença entre busca cega e heurística continua extremamente relevante. Sistemas de navegação, jogos digitais, roteamento logístico, escalonamento de tarefas em datacenters, planejamento robótico e sistemas de decisão em ambientes parcialmente observáveis frequentemente dependem de heurísticas para reduzir custo computacional. Mesmo em contextos contemporâneos de aprendizado profundo, muitas vezes os modelos aprendem estimativas que funcionam como heurísticas para buscas mais amplas.

Em resumo, a busca cega oferece um ponto de partida conceitualmente puro e útil para análise formal. A busca heurística acrescenta conhecimento prático sobre o domínio para tornar a exploração mais eficiente. A tensão entre generalidade e orientação é uma das marcas mais importantes da IA clássica e continua aparecendo em muitos problemas atuais.

22.5 - Hill climbing, best first, simulated annealing e Algoritmo A*.

Depois de distinguir entre busca cega e busca heurística, o passo seguinte é estudar algoritmos concretos que usam essas ideias de maneiras diferentes. Nesta seção aparecem quatro famílias muito importantes: hill climbing, busca best-first, simulated annealing e o algoritmo $A^*$. Embora todos estejam ligados à noção de busca orientada, eles não resolvem o problema da mesma forma. Alguns trabalham localmente sobre uma solução corrente; outros mantêm fronteiras explícitas de exploração; alguns priorizam rapidez prática; outros mantêm garantias mais fortes de qualidade da solução.

Panorama Histórico

O desenvolvimento desses métodos acompanha a própria evolução da IA e da otimização combinatória. Estratégias locais como hill climbing surgiram cedo porque muitos problemas eram grandes demais para exploração exaustiva. A família best-first consolidou a ideia de expandir primeiro o nó mais promissor segundo uma avaliação heurística. Em 1968, Hart, Nilsson e Raphael publicaram o artigo clássico que formalizou o algoritmo $A^*$, estabelecendo uma base teórica para busca heurística com garantias de optimalidade sob certas condições. Já o simulated annealing se tornou especialmente influente a partir do artigo de Kirkpatrick, Gelatt e Vecchi, em 1983, ao conectar otimização combinatória com a metáfora física do recozimento térmico.

Esses métodos refletem duas grandes tradições. A primeira é a tradição da busca em grafos e árvores, em que mantemos explicitamente uma fronteira de estados candidatos. A segunda é a tradição da busca local e da otimização estocástica, em que trabalhamos principalmente sobre uma solução corrente e tentamos melhorá-la ao longo do tempo.

Comparação entre busca local em paisagem de otimização e busca A estrela em grafo com caminho até a meta.
Figura 4. Alguns métodos de busca percorrem um grafo de estados explicitamente; outros se comportam como busca local em uma paisagem de valores.
Hill Climbing

Hill climbing é uma técnica de busca local que parte de uma solução inicial e tenta melhorá-la por pequenas modificações sucessivas. A analogia clássica é a de alguém subindo uma montanha em meio à neblina: a pessoa não vê a paisagem inteira, apenas os arredores imediatos, e escolhe sempre a direção de subida mais promissora. Isso costuma levar rapidamente a melhorias, mas não garante que o pico encontrado seja o melhor de toda a região.

Os principais obstáculos conceituais são:

  • ótimos locais, isto é, pontos melhores do que todos os vizinhos próximos, mas inferiores ao ótimo global;
  • planaltos, em que muitos estados têm avaliação semelhante;
  • cristas, em que a direção de melhora não é bem capturada por movimentos locais simples.

Um exemplo matemático simples é maximizar uma função como

$$ f(x) = -x^4 + 8x^2 $$

Se discretizamos o domínio e sempre escolhemos o vizinho com maior valor, podemos subir rapidamente até um pico local da paisagem induzida por $f$. O método não falha por falta de inteligência; ele falha por enxergar apenas a vizinhança imediata. Em termos computacionais, hill climbing é muito usado em ajuste de hiperparâmetros, problemas de escalonamento e montagem incremental de soluções.

Best-First Search

A busca best-first mantém uma fronteira de estados candidatos e expande primeiro aquele considerado mais promissor segundo uma função de avaliação. Se chamarmos essa função de $f(n)$, então o algoritmo ordena a fila de prioridade pela melhor estimativa disponível. Em um caso guloso, podemos usar apenas a heurística $h(n)$ e escolher sempre o nó aparentemente mais próximo da meta. Em um caso mais sofisticado, podemos combinar custo já acumulado com estimativa restante, preparando o terreno para algoritmos como $A^*$.

A analogia aqui é a de um explorador que mantém vários caminhos possíveis abertos, mas sempre escolhe continuar aquele que parece mais vantajoso no momento. Diferentemente de hill climbing, que tipicamente mantém uma solução corrente e sua vizinhança, best-first trabalha com uma coleção explícita de alternativas concorrentes.

Em termos computacionais, isso costuma ser implementado com uma fila de prioridade. Um esboço simples seria:

fronteira = fila_de_prioridade(chave = f(n))
enquanto fronteira nao vazia:
    n = remover_melhor(fronteira)
    expandir(n)

Esse estilo de busca é muito importante em planejamento, navegação, jogos e problemas combinatórios em que dispomos de boas heurísticas, mas ainda precisamos manter alternativas abertas para evitar decisões precipitadas demais.

Simulated Annealing

O simulated annealing também é uma técnica de busca local, mas introduz aleatoriedade controlada para escapar de aprisionamento prematuro em ótimos locais. A ideia vem da física dos materiais: ao aquecer e resfriar lentamente um sólido, é possível levá-lo a configurações estruturais mais estáveis do que aquelas obtidas por resfriamento abrupto. Em otimização, isso se traduz em aceitar, ocasionalmente, movimentos que pioram temporariamente a solução.

Se uma modificação muda o valor da função objetivo em $\Delta E$, uma forma clássica de modelar a aceitação é:

$$ P(\text{aceitar}) = e^{-\Delta E / T} $$

Nessa fórmula, $T$ representa a temperatura. Quando $T$ é alta, o algoritmo aceita com mais facilidade movimentos desfavoráveis, explorando mais o espaço. À medida que $T$ diminui, o comportamento fica mais conservador. A notação $e^{x}$ representa a função exponencial. O ponto intuitivo é que o algoritmo começa mais “explorador” e termina mais “seletivo”.

Um exemplo moderno bastante natural é otimização de rotas, alocação de tarefas em servidores e desenho de circuitos. Nessas situações, pequenas pioras temporárias podem ser úteis para escapar de más regiões da paisagem de soluções e encontrar configurações melhores no longo prazo.

Algoritmo A*

O algoritmo $A^*$ é um dos marcos da busca heurística porque combina orientação prática com garantias formais fortes. Ele avalia cada nó pela soma entre o custo já acumulado e uma estimativa do custo restante:

$$ f(n) = g(n) + h(n) $$

Aqui, $g(n)$ é o custo real do caminho do início até $n$, e $h(n)$ é a estimativa do custo de $n$ até a meta. O valor $f(n)$ tenta estimar o custo total de uma solução passando por $n$. Se $h$ for admissível, isto é, se nunca superestimar o custo real restante, então $A^*$ preserva optimalidade em muitas condições clássicas.

Um exemplo matemático simples aparece em grades ortogonais. Se o agente pode mover-se apenas na horizontal e na vertical, uma heurística comum é a distância Manhattan:

$$ h(x, y) = |x - x_g| + |y - y_g| $$

Se o estado atual é $(2,1)$ e a meta é $(5,4)$, então:

$$ h(2,1) = |2-5| + |1-4| = 3 + 3 = 6 $$

Se o custo acumulado até esse ponto for $g(n)=4$, então

$$ f(n) = 4 + 6 = 10 $$

Em termos computacionais, $A^*$ é amplamente usado em jogos, navegação robótica, roteamento em mapas, planejamento em malhas e sistemas de IA embarcados. Em versões modernas, princípios da família de busca heurística incremental, como D* e D* Lite, estendem essa ideia para ambientes que mudam ao longo do tempo.

Ao estudar esses algoritmos, surgem variações naturais. Em busca best-first, por exemplo, podemos ter versões mais gulosas, nas quais a avaliação depende principalmente de $h(n)$. Em busca local, uma estratégia comum é o random-restart hill climbing, que reinicia a exploração várias vezes para reduzir o impacto de ótimos locais. No simulated annealing, o cronograma de resfriamento influencia diretamente a qualidade da solução e o custo do processo. Já em $A^*$, a diferença entre heurísticas admissíveis e consistentes afeta tanto garantias teóricas quanto eficiência prática. Isso mostra que os algoritmos da seção não são casos isolados, mas membros de famílias mais amplas de estratégias orientadas.

Também vale notar como esses métodos dialogam com matemática de formas diferentes. Em hill climbing, pensamos em paisagens de função, gradientes implícitos e máximos locais. Em simulated annealing, aparece a função exponencial e uma leitura probabilística do processo de aceitação. Em $A^*$, raciocinamos sobre ordenação em grafos ponderados, estimativas inferiores e decomposição de custo em parte acumulada e parte estimada. A matemática não entra aqui como ornamentação formal, mas como instrumento para entender por que cada método funciona, quando tende a falhar e que tipo de garantia pode oferecer.

Essas técnicas continuam muito atuais. Busca local aparece em otimização combinatória, ajuste de hiperparâmetros, desenho de arquiteturas e escalonamento de cargas em datacenters. Métodos da família best-first aparecem em planejamento, inferência estruturada e decodificação aproximada. Já $A^*$ e seus descendentes seguem fundamentais em robótica, jogos digitais, veículos autônomos e sistemas de navegação. Mesmo quando modelos modernos de aprendizado profundo dominam percepção ou previsão, a etapa de decisão ainda frequentemente depende de alguma forma de busca estruturada.

Em síntese, orientar uma busca não significa apenas “usar uma heurística”. Significa decidir que tipo de memória o método mantém, quanta exploração aceita, que garantias oferece e qual relação estabelece entre estrutura do problema, custo computacional e qualidade da solução.

22.6 - Busca como Maximização de Função.

Em muitos problemas de IA, a pergunta central não é apenas “existe uma solução?”, mas “qual é a melhor solução entre muitas alternativas possíveis?”. Nesses casos, a busca pode ser reformulada como um problema de otimização: cada solução candidata recebe uma pontuação, um custo, uma utilidade ou uma medida de erro, e o objetivo passa a ser maximizar ou minimizar essa função. Em vez de tratar a meta como um conjunto rígido de estados aceitáveis, atribuímos uma qualidade graduada às possibilidades e procuramos a melhor delas.

Historicamente, essa forma de pensar aproximou a IA de áreas como pesquisa operacional, otimização combinatória, estatística e controle. Muitos algoritmos apresentados em IA clássica, especialmente os de busca local, podem ser reinterpretados como navegadores de uma paisagem de função. Em vez de expandir explicitamente um grande grafo de estados até uma meta binária, o algoritmo se move tentando melhorar o valor de uma função de avaliação. Essa mudança conceitual é importante porque conecta problemas de busca a problemas de ajuste de parâmetros, seleção de modelos, planejamento com preferências e aprendizagem.

Formulação da Função Objetivo

Formalmente, podemos escrever um problema de maximização como:

$$ x^* = \arg\max_x f(x) $$

O símbolo $\arg\max$ significa “o valor de $x$ que maximiza $f(x)$”. Se quisermos minimizar, usamos $\arg\min$. A diferença entre maximização e minimização é muitas vezes apenas de convenção. Uma função de utilidade alta pode ser equivalente a um custo baixo, bastando inverter sinais ou reformular o critério.

Em vários problemas, a solução candidata $x$ não é um número simples, mas uma estrutura: uma rota, um cronograma, uma configuração de hiperparâmetros, uma política de decisão, uma sequência de ações ou uma rede de conexões. A função objetivo é então um mapeamento do espaço de soluções para os números reais, algo como $f : S \to \mathbb{R}$, em que $S$ é o conjunto de soluções possíveis e $\mathbb{R}$ representa o conjunto dos números reais. Essa notação apenas formaliza a ideia de que cada solução recebe um valor mensurável.

Paisagem de função objetivo com regiões de alta e baixa qualidade e trajetórias de busca.
Figura 5. Em muitos problemas de IA, buscar uma solução significa navegar por uma paisagem de valores tentando maximizar utilidade ou minimizar custo.
Exemplos Matemáticos

Considere primeiro um exemplo contínuo simples. Suponha que desejamos maximizar a função

$$ f(x) = -x^2 + 6x - 5 $$

Como essa é uma parábola voltada para baixo, o ponto de máximo ocorre no vértice. Pela fórmula do vértice, para $ax^2 + bx + c$ temos $x_v = -\frac{b}{2a}$. Aqui, $a=-1$ e $b=6$, então:

$$ x_v = -\frac{6}{2(-1)} = 3 $$

Substituindo em $f(x)$:

$$ f(3) = -(3)^2 + 6\cdot3 - 5 = -9 + 18 - 5 = 4 $$

Logo, a melhor solução é $x^* = 3$, com valor máximo igual a 4. Esse exemplo é simples, mas ilustra a lógica geral: cada candidato tem um valor, e o objetivo é localizar a melhor região da paisagem.

Agora considere um exemplo discreto. Suponha três rotas possíveis para entrega com custos 18, 11 e 15. Nesse caso, a função objetivo pode ser o custo total, e o problema é minimizar:

$$ x^* = \arg\min_{x \in \{r_1,r_2,r_3\}} custo(x) $$

Como $custo(r_2)=11$ é o menor valor, a melhor rota é $r_2$. Esse tipo de formulação aparece em logística, roteamento, sequenciamento e alocação de recursos.

Restrições, Vizinhança e Factibilidade

Na prática, uma função objetivo raramente aparece sozinha. Muitos problemas incluem restrições. Não basta encontrar uma solução de bom valor; ela precisa ser válida. Em escalonamento, por exemplo, uma agenda pode ser excelente em custo, mas inválida se alocar a mesma sala para duas turmas no mesmo horário. Em planejamento de rotas, um caminho pode ser curto demais para ser permitido se atravessar uma região bloqueada.

Por isso, vários algoritmos trabalham com a noção de solução factível, isto é, uma solução que satisfaz todas as restrições do problema. Em alguns casos, as restrições são tratadas explicitamente; em outros, são incorporadas à própria função objetivo por penalização. Se uma solução viola uma restrição, somamos uma penalidade grande ao custo total. Essa técnica é muito comum em problemas combinatórios.

A ideia de vizinhança também se torna essencial. Em busca local, não comparamos uma solução com todas as outras possíveis, mas com soluções “próximas” segundo alguma operação simples. Em um problema de caixeiro viajante, por exemplo, uma vizinhança pode ser definida pela troca da ordem de duas cidades. Em ajuste de parâmetros, pode significar alterar ligeiramente um valor numérico. Em outras palavras, a noção de proximidade não é geométrica por si só; ela depende da estrutura do problema.

Exemplos Computacionais

Em aprendizado de máquina, a formulação por otimização aparece o tempo todo. Treinar um modelo linear pode significar minimizar uma função de perda como o erro quadrático médio:

$$ L(\theta) = \frac{1}{n}\sum_{i=1}^{n}(f_{\theta}(x_i) - y_i)^2 $$

Aqui, $\theta$ representa os parâmetros do modelo, $x_i$ são entradas, $y_i$ são saídas desejadas e $f_{\theta}(x_i)$ é a previsão produzida pelo modelo. O símbolo $\sum$ indica uma soma sobre os exemplos de treino. Minimizar $L(\theta)$ significa encontrar parâmetros que tornem as previsões o mais próximas possível dos valores observados.

Um exemplo computacional simples de formulação seria algo como:

def objetivo(parametros):
    return acuracia_validacao(modelo(parametros))

melhor = argmax(espaco_de_busca, chave=objetivo)

Nesse pseudocódigo, o espaço de busca contém configurações possíveis de um modelo, e a função objetivo mede seu desempenho em validação. Em sistemas reais, isso aparece em ajuste de hiperparâmetros, busca de arquitetura de redes neurais, seleção de features e desenho de políticas de decisão.

Paisagens, Ótimos Locais e Subtópicos Naturais

Quando escrevemos uma função objetivo, implicitamente criamos uma paisagem de otimização. Alguns problemas têm superfície suave e relativamente simples; outros apresentam muitos picos, vales, platôs e regiões quase equivalentes. É nesse contexto que surgem naturalmente conceitos como ótimo local, ótimo global, função de aptidão, custo, energia e critério de penalização. Em algoritmos genéticos, por exemplo, fala-se frequentemente em fitness; em otimização estocástica, pode-se falar em energia; em aprendizado de máquina, fala-se em perda ou loss. Em termos matemáticos, são papéis diferentes para a mesma ideia geral: uma função que ordena soluções.

Esse ponto ajuda a conectar a seção atual às anteriores. Hill climbing, simulated annealing e vários métodos de busca local podem ser vistos como navegadores dessa paisagem. Já algoritmos como $A^*$ tratam o valor de uma solução parcial de forma mais estruturada, separando custo acumulado e estimativa restante. A diferença está menos no objetivo final e mais na maneira como a função orienta a exploração.

Aplicações Contemporâneas

Em problemas modernos, essa formulação continua decisiva. Ajustar pesos de modelos, escolher hiperparâmetros, planejar rotas de veículos, escalar cargas em nuvem, alocar tarefas em processadores, otimizar portfólios de decisão e organizar cadeias logísticas são todos exemplos em que a IA trata soluções como candidatos avaliados por uma função. Mesmo em grandes sistemas generativos, etapas internas podem ser entendidas como processos de otimização, seja na fase de treinamento, seja em mecanismos de busca ou reranqueamento durante a inferência.

Em síntese, pensar busca como maximização de função é transformar o problema de “encontrar alguma solução” em “avaliar sistematicamente a qualidade das soluções”. Essa mudança aproxima a IA de ferramentas matemáticas poderosas e explica por que otimização se tornou linguagem comum tanto na IA clássica quanto na contemporânea.

22.7 - Grafos And/Or.

Grafos AND/OR são usados para representar problemas em que resolver o objetivo não significa apenas escolher um caminho entre estados, mas também decompor o problema em subproblemas. Em um nó OR, basta escolher uma entre várias alternativas possíveis. Em um nó AND, por outro lado, todos os subproblemas associados precisam ser resolvidos para que o problema original seja considerado resolvido. Essa distinção é importante porque muitos problemas reais combinam decisão e composição ao mesmo tempo.

Uma analogia muito clara é organizar uma viagem. O objetivo “realizar a viagem” depende de reservar transporte e reservar hospedagem. Isso é um nó AND, porque ambas as tarefas são necessárias. Já a subtarefa “escolher transporte” pode ser um nó OR: ônibus, carro ou avião. Em termos intuitivos, um nó OR representa escolha; um nó AND representa obrigação conjunta.

Contexto Histórico

O interesse por grafos AND/OR cresceu na IA clássica quando pesquisadores perceberam que muitos problemas não eram bem representados apenas por árvores de decisão lineares. Em planejamento, prova automática de teoremas, diagnóstico e resolução hierárquica de tarefas, frequentemente não basta escolher entre alternativas; é preciso também decompor um objetivo em vários componentes que precisam ser satisfeitos juntos. Trabalhos sobre decomposição de problemas e busca heurística em grafos AND/OR, como os estudos de Martelli e Montanari nos anos 1970, ajudaram a formalizar esse tipo de estrutura.

Historicamente, essa ideia dialoga com uma ambição antiga da IA: tratar problemas complexos por redução a subproblemas menores. Em vez de resolver tudo de uma vez, o sistema tenta quebrar o objetivo em partes. Grafos AND/OR são justamente uma forma explícita de representar quando essa decomposição exige resolver todas as partes e quando ela exige escolher apenas uma entre várias rotas possíveis.

Grafo AND OR com objetivo principal, nós de escolha e nós de decomposição em subtarefas.
Figura 6. Em um grafo AND/OR, alguns nós exigem escolher uma alternativa; outros exigem resolver simultaneamente vários subproblemas.
Leitura Estrutural

Do ponto de vista matemático, podemos pensar em um grafo AND/OR como um grafo dirigido em que cada nó carrega um tipo semântico. Em nós OR, o custo ou a viabilidade da solução depende de ao menos um dos filhos. Em nós AND, depende da solução conjunta de todos os filhos. Se uma formulação de busca comum trabalha com a ideia “encontre um caminho”, aqui muitas vezes passamos à ideia “encontre uma subestrutura de solução”.

Se quisermos escrever essa diferença de forma simplificada, podemos pensar assim. Se um nó OR tem filhos com custos $c_1, c_2, \ldots, c_k$, então o custo da melhor solução local pode ser modelado como:

$$ C_{OR} = \min(c_1, c_2, \ldots, c_k) $$

Já se um nó AND depende de todos os seus filhos, uma forma simples de agregação pode ser:

$$ C_{AND} = \sum_{i=1}^{k} c_i $$

Essas fórmulas não esgotam todas as variantes possíveis, mas ajudam a entender a diferença estrutural. Em um caso, escolhemos a melhor alternativa; no outro, acumulamos o custo de vários componentes necessários.

Exemplo Matemático

Suponha que o objetivo $G$ possa ser resolvido de duas maneiras: por uma alternativa direta com custo 9, ou por uma decomposição em duas subtarefas obrigatórias com custos 4 e 3. Se a primeira possibilidade for um ramo OR e a segunda envolver um nó AND, então temos:

$$ C_{direto} = 9 $$

e

$$ C_{decomposto} = 4 + 3 = 7 $$

Nesse caso, a estrutura AND/OR mostra que, embora resolver duas subtarefas pareça mais complexo, o custo total ainda pode ser menor do que seguir a alternativa direta. Esse tipo de raciocínio aparece naturalmente em planejamento hierárquico, montagem de provas, composição de pipelines e organização de processos.

Exemplos Computacionais

Em um sistema de diagnóstico, uma falha de equipamento pode ser modelada como “problema elétrico” OR “problema mecânico”. Já “problema elétrico” pode exigir simultaneamente “baixa tensão” AND “sensor de alimentação inconsistente”. Nesse caso, um nó OR representa hipóteses concorrentes, e um nó AND representa um conjunto de evidências que precisa ser satisfeito junto.

Outro exemplo computacional surge em planejamento de tarefas. Suponha um agente que precisa “publicar um artigo”. Esse objetivo pode ser decomposto em “escrever texto” AND “revisar” AND “submeter”. Já “coletar dados para o artigo” pode ter alternativas diferentes, como “usar base pública” OR “executar experimento próprio”. Essa forma de representação é especialmente útil quando o problema tem estrutura hierárquica e o sistema precisa raciocinar sobre dependências entre subtarefas.

Em pseudocódigo, uma avaliação recursiva simplificada pode aparecer assim:

def custo(no):
    if no.tipo == "OR":
        return min(custo(filho) for filho in no.filhos)
    if no.tipo == "AND":
        return sum(custo(filho) for filho in no.filhos)

Esse pseudocódigo deixa claro o ponto central: nós OR escolhem entre alternativas; nós AND agregam componentes obrigatórios.

Ao estudar grafos AND/OR, surgem naturalmente temas como decomposição de problemas, custo aditivo, consistência entre subsoluções, compartilhamento de subestruturas e busca heurística orientada por contexto. Em certos problemas, dois ramos diferentes podem depender de um mesmo subproblema, o que leva a representar não apenas árvores, mas grafos com reuso de subsoluções. Isso evita recomputações desnecessárias e aproxima a representação de técnicas modernas de fatoração e inferência em modelos gráficos.

Essa ideia continua atual em planejamento hierárquico, síntese de programas, raciocínio sobre workflows, inferência probabilística estruturada, montagem automática, diagnóstico e resolução de problemas em redes bayesianas e modelos fatorados. Mesmo quando sistemas contemporâneos são fortemente orientados por aprendizado, a decomposição explícita de problemas em subpartes continua sendo uma ferramenta poderosa para organizar decisão e inferência.

Do ponto de vista matemático, a seção conversa com teoria dos grafos, recorrência, otimização em estruturas compostas e análise de custo em decomposições recursivas. Em vez de pensar apenas em um caminho ótimo, passamos a pensar em composição ótima de soluções parciais. Isso torna os grafos AND/OR especialmente úteis quando a estrutura do problema é mais importante do que uma simples sequência linear de estados.

22.8 - Esquemas para Representação do Conhecimento: Lógicos, em Rede, Estruturados, Procedurais.

Representar conhecimento significa escolher uma estrutura formal para armazenar fatos, regras, conceitos e relações de modo que um sistema possa raciocinar, responder perguntas, explicar conclusões e adaptar decisões. Ao longo da história da IA, ficou claro que dados isolados raramente bastam. O problema central não é apenas guardar informação, mas organizá-la de um modo que preserve significado e permita inferência. Essa preocupação se tornou especialmente importante na IA simbólica, quando pesquisadores tentavam fazer a máquina lidar com linguagem, senso comum, diagnóstico, planejamento e compreensão de cenas.

Historicamente, a área evoluiu porque domínios reais se mostraram mais complexos do que simples listas de fatos. Em um domínio pequeno, talvez baste registrar afirmações soltas. Em um domínio mais rico, surgem hierarquias, exceções, papéis, dependências temporais, rotinas de ação e conhecimento implícito sobre contextos. Foi nesse ambiente que se consolidaram diferentes esquemas de representação, entre eles os formais lógicos, as redes semânticas, os frames e as representações procedurais. Cada um surgiu como resposta a uma pergunta prática: como estruturar conhecimento para que ele possa ser usado, e não apenas armazenado?

Uma analogia útil é pensar em quatro maneiras de organizar a mesma biblioteca. A representação lógica se parece com um conjunto de regras jurídicas muito precisas. A representação em rede lembra um mapa de metrô, em que estações são conceitos e ligações são relações. A representação estruturada se parece com fichas detalhadas ou formulários inteligentes, com campos padrão e valores esperados. A representação procedural, por fim, se parece com um manual operacional: não descreve apenas o que algo é, mas também como agir diante de certas situações. Em sistemas reais, essas formas costumam coexistir.

Comparação entre representação lógica, em rede, estruturada e procedural do conhecimento.
Figura 7. Quatro maneiras clássicas de representar conhecimento em IA: fórmulas, grafos conceituais, estruturas com atributos e rotinas de ação.
Representações Lógicas

Nas representações lógicas, o conhecimento é descrito por fórmulas, fatos e regras com sintaxe bem definida. A grande vantagem desse esquema é a precisão: se sabemos exatamente o que cada símbolo significa e quais regras de inferência são válidas, podemos provar conclusões de maneira controlada. Esse estilo foi fortemente influenciado pela lógica matemática e pelo programa de McCarthy de tratar raciocínio como manipulação formal de sentenças.

Um exemplo elementar seria escrever:

$$ \forall x \, (Professor(x) \rightarrow Pessoa(x)) $$

e também:

$$ Professor(Ana) $$

A partir dessas duas afirmações, concluímos:

$$ Pessoa(Ana) $$

Nessa notação, o símbolo $\forall$ significa "para todo", e a seta $\rightarrow$ pode ser lida como "implica". Em termos intuitivos, a regra diz: "todo professor é uma pessoa". Como Ana é professora, segue-se que Ana é uma pessoa. A força da representação lógica está em permitir esse tipo de inferência com clareza semântica.

Um exemplo computacional simples em Prolog seria:

professor(ana).
pessoa(X) :- professor(X).

Nesse caso, o sistema responde a uma consulta como pessoa(ana) usando uma regra declarativa. Esse modelo é poderoso em verificação de restrições, sistemas jurídicos, consulta semântica, planejamento e certas formas de raciocínio explicável. Ao mesmo tempo, domínios ricos em exceções e conhecimento implícito costumam exigir extensões, pois escrever tudo em forma puramente lógica pode se tornar caro e pouco flexível.

Representações em Rede

As representações em rede ganharam destaque nos anos 1960, especialmente com os trabalhos de Quillian sobre memória semântica. A ideia central é modelar conhecimento como um grafo: conceitos aparecem como nós, e relações aparecem como arestas rotuladas. Em vez de pensar apenas em fórmulas isoladas, passamos a visualizar o conhecimento como uma malha de conexões.

Matematicamente, isso pode ser visto como um grafo dirigido $G = (V, E)$, em que $V$ é o conjunto de nós e $E$ é o conjunto de arestas. Se temos os nós canario, ave e animal, e arestas do tipo eh_um, podemos escrever algo conceitualmente equivalente a:

$$ canario \xrightarrow{eh\_um} ave \xrightarrow{eh\_um} animal $$

Se o nó ave estiver ligado ao atributo "tem asas", o sistema pode herdar essa propriedade para canario. A analogia aqui é a de uma árvore genealógica de conceitos: em vez de repetir em cada nó tudo o que ele sabe, usamos a estrutura para propagar informação. Isso torna a representação econômica e intuitiva.

Em termos computacionais, um fragmento de rede pode ser armazenado como triplas:

("canario", "eh_um", "ave")
("ave", "eh_um", "animal")
("ave", "tem", "asas")

Esse formato antecipa o modo como muitos grafos de conhecimento modernos são armazenados. Sistemas de busca semântica, assistentes virtuais, recomendação baseada em entidades e a Web Semântica usam ideias próximas, agora em escala muito maior. O limite das redes mais simples é que nem toda inferência fica clara apenas pela estrutura do grafo; por isso, muitas aplicações modernas combinam redes com semântica formal mais rigorosa.

Representações Estruturadas

Quando os domínios exigem descrições mais ricas de objetos, situações e papéis, surgem representações estruturadas como frames, scripts e, em desenvolvimentos posteriores, ontologias. Minsky popularizou os frames nos anos 1970 como uma forma de representar situações típicas por meio de estruturas com campos, valores esperados e informações padrão. A ideia é parecida com preencher uma ficha inteligente: alguns campos já possuem valores default, outros esperam tipos específicos de preenchimento, e certos campos podem apontar para outras estruturas.

Suponha um frame chamado SalaDeAula com slots como professor, disciplina, horario e alunos. Em notação simplificada, poderíamos escrever:

SalaDeAula:
  professor = "Ana"
  disciplina = "IA"
  horario = "08:00"
  capacidade = 40

Essa forma de organizar conhecimento facilita herança, valores padrão, especialização e tratamento de papéis contextuais. Um frame LaboratorioDeIA pode herdar propriedades gerais de SalaDeAula e acrescentar slots como equipamentos ou restricoes_de_acesso. Em problemas de compreensão de linguagem e visão, esse tipo de estrutura ajuda a capturar o que normalmente se espera de uma situação, mesmo quando nem tudo foi explicitamente dito.

Essa família de representações também conversa com tópicos matemáticos e lógicos mais formais, como classes, relações, restrições e subsunção. Em ontologias modernas, por exemplo, é comum representar classes e propriedades com linguagens como OWL, que combinam uma visão em rede com fundamentos lógicos mais fortes. Isso é relevante hoje em integração de dados, biomedicina, catálogos digitais, interoperabilidade e agentes que precisam navegar entre várias fontes de conhecimento heterogêneas.

Representações Procedurais

Nem todo conhecimento aparece naturalmente como uma afirmação sobre o mundo. Em muitos casos, o que interessa é saber como agir. Esse é o território do conhecimento procedural. Em vez de descrever apenas fatos, a representação incorpora métodos, rotinas e sequências operacionais. A diferença intuitiva é a mesma que existe entre "saber que" e "saber como".

Considere um procedimento para diagnosticar falha de login:

def diagnosticar_login(usuario):
    if senha_incorreta(usuario):
        return "redefinir senha"
    if conta_bloqueada(usuario):
        return "desbloquear conta"
    return "verificar servidor de autenticacao"

Esse fragmento não descreve apenas relações estáticas entre conceitos; ele codifica uma estratégia de ação. Em sistemas especialistas, manutenção industrial, assistentes de suporte, jogos e robótica, esse tipo de conhecimento é essencial. A desvantagem é que procedimentos podem ser eficientes para executar, mas menos transparentes para explicar ou reorganizar semanticamente do que representações declarativas.

Por isso, uma lição importante da história da IA é que nenhum esquema resolve tudo sozinho. Problemas simples podem caber em regras lógicas; domínios relacionais pedem redes; contextos ricos e típicos favorecem frames e ontologias; tarefas operacionais dependem de procedimentos. Em sistemas contemporâneos, inclusive nos que interagem com modelos de linguagem, é comum combinar bases declarativas, grafos de conhecimento, estruturas ontológicas e rotinas procedurais. Quanto mais complexo o domínio, maior tende a ser a necessidade de combinar esquemas em vez de escolher apenas um.

22.9 - Sistemas de Produção com Encadeamento para a Frente e Encadeamento para trás (forward and backward chaining).

Sistemas de produção são uma das arquiteturas mais influentes da IA simbólica. Neles, o conhecimento costuma ser expresso por regras do tipo “se condição, então ação” ou “se condição, então conclusão”, enquanto um motor de inferência decide quais regras podem ser usadas a partir da situação atual. Em vez de escrever um grande programa monolítico com todas as decisões embutidas, o projetista organiza o comportamento em pequenas produções relativamente independentes. Isso torna o sistema mais modular, mais legível e, em muitos domínios, mais fácil de manter.

Historicamente, esse modelo ganhou força nos anos 1970 e 1980 com linguagens e ambientes como OPS5, além de sistemas especialistas de grande repercussão. Um caso clássico foi o XCON, usado para auxiliar na configuração de computadores da DEC por meio de milhares de regras. Mais tarde, ferramentas como CLIPS, desenvolvida na NASA, ajudaram a popularizar o paradigma em contextos industriais, educacionais e de prototipação. Ao mesmo tempo, o crescimento do número de regras trouxe um problema prático importante: como comparar rapidamente muitos fatos contra muitas condições? Foi nesse contexto que o algoritmo Rete, de Charles Forgy, se tornou central para tornar o encadeamento para a frente viável em bases maiores.

Do ponto de vista estrutural, um sistema de produção costuma ter pelo menos três partes: uma base de regras, uma memória de trabalho e um mecanismo de controle. A base de regras armazena as produções. A memória de trabalho contém os fatos conhecidos naquele instante. O mecanismo de controle executa um ciclo que pode ser resumido como match-select-act: encontra as regras aplicáveis, escolhe uma entre elas e executa sua ação. Uma analogia útil é a de um painel operacional em um centro de controle. Os fatos na memória de trabalho são os sinais acesos no painel; as regras são instruções do manual; e o motor de inferência é o operador que verifica quais instruções se aplicam à situação corrente.

Ciclo de um sistema de producao com memoria de trabalho, base de regras, agenda e disparo de regras.
Figura 8. Em sistemas de produção, os fatos ativam regras candidatas; o motor escolhe uma delas, dispara sua ação e atualiza a memória de trabalho.
Encadeamento para a Frente

No encadeamento para a frente, o raciocínio é dirigido por dados. O sistema parte dos fatos atuais e pergunta: “o que mais posso concluir a partir daqui?”. Sempre que as condições de uma regra são satisfeitas, ela se torna candidata a disparo. Se a ação da regra acrescenta um novo fato, esse fato pode, por sua vez, ativar outras regras. O processo continua até que não haja mais regras aplicáveis ou até que uma meta operacional seja atingida.

Um exemplo simples ajuda a visualizar:

SE febre(p1) E tosse(p1) ENTAO suspeita_infeccao_respiratoria(p1)
SE suspeita_infeccao_respiratoria(p1) E saturacao_baixa(p1) ENTAO prioridade_alta(p1)

Se a memória de trabalho começar com os fatos febre(p1), tosse(p1) e saturacao_baixa(p1), a primeira regra pode disparar e inserir suspeita_infeccao_respiratoria(p1). Em seguida, a segunda regra se torna aplicável e produz prioridade_alta(p1). Esse encadeamento é parecido com uma sequência de dominós: um fato derruba a próxima regra, que produz um novo fato, que ativa a seguinte.

Se quisermos escrever isso em linguagem de conjuntos, podemos imaginar a memória de trabalho como um conjunto $W$ de fatos. Cada regra funciona como uma transformação parcial sobre $W$. Aplicar o sistema repetidamente equivale a calcular novos conjuntos $W_1, W_2, W_3, \ldots$ até atingir um ponto em que nenhuma regra acrescenta informação nova. Em termos matemáticos, é uma forma de fechamento por inferência. Essa visão ajuda a entender por que encadeamento para a frente se relaciona com teoria de conjuntos, lógica proposicional, monotonicidade e pontos fixos.

Esse estilo é especialmente útil quando o sistema precisa reagir a fluxos de eventos, monitorar condições, classificar ocorrências ou explorar todas as consequências relevantes de uma base de fatos. Por isso, ideias próximas continuam vivas em motores de regras de negócio, detecção de fraude, automação industrial, processamento de eventos complexos e políticas de decisão em sistemas corporativos.

Encadeamento para trás

No encadeamento para trás, o raciocínio é dirigido por objetivos. O sistema parte de uma hipótese e pergunta: “o que preciso provar para aceitar essa conclusão?”. Se a meta for pneumonia(p1), o motor busca regras cujo consequente seja exatamente esse objetivo. Cada regra encontrada gera subobjetivos correspondentes às suas premissas. A analogia clássica é a de um detetive que parte da tese final e vai atrás das evidências necessárias para sustentá-la.

Considere as regras:

SE febre(X) E tosse(X) E infiltrado_raio_x(X) ENTAO pneumonia(X)
SE pneumonia(X) E idade_avancada(X) ENTAO internacao_recomendada(X)

Se a pergunta for internacao_recomendada(p1), o sistema pode trabalhar para trás: primeiro tenta provar pneumonia(p1) e idade_avancada(p1); depois, para provar pneumonia(p1), procura evidências como febre(p1), tosse(p1) e infiltrado_raio_x(p1). O raciocínio não sai produzindo todas as consequências possíveis; ele busca apenas o que for necessário para a meta atual. Esse comportamento o torna eficiente em cenários de consulta, diagnóstico orientado por hipótese e prova de objetivos, como ocorre em muitas consultas lógicas e em linguagens como Prolog.

Matematicamente, esse processo se aproxima de uma busca em árvore de provas. A raiz é a meta principal; os filhos são submetas geradas por regras compatíveis; e uma prova é bem-sucedida quando todas as folhas necessárias podem ser satisfeitas por fatos conhecidos ou novas derivações. Em termos de complexidade, isso deixa claro um ponto importante: a eficiência não depende apenas do número de regras, mas também da ordem de busca, da seletividade das premissas e da quantidade de metas intermediárias geradas.

Agenda, Conflitos e Eficiência

Em sistemas de produção reais, várias regras podem ficar aptas a disparar ao mesmo tempo. O conjunto dessas regras forma a agenda, e o problema passa a ser escolher qual delas executar primeiro. Esse processo é chamado de resolução de conflitos. Estratégias comuns incluem prioridade por especificidade, recência dos fatos, ordem declarada ou saliência atribuída pelo projetista. A escolha importa porque pode afetar desempenho, explicabilidade e, em alguns casos, até o comportamento observável do sistema.

Suponha, por exemplo, as regras:

SE febre(X) ENTAO solicitar_temperatura(X)
SE febre(X) E tosse(X) ENTAO isolar_paciente(X)

Se os fatos febre(p1) e tosse(p1) estiverem presentes, ambas as regras entram na agenda. Uma estratégia que privilegie a regra mais específica pode escolher primeiro isolar_paciente(p1), porque ela usa mais condições e tende a ser mais informativa para aquela situação. Esse exemplo mostra que o motor de inferência não é apenas um executor mecânico de regras; ele também incorpora uma política de controle.

Foi justamente para lidar com o custo de casar muitas regras com muitos fatos que o algoritmo Rete ganhou importância histórica. Em vez de recomputar tudo do zero a cada atualização da memória de trabalho, ele compartilha testes entre regras e reaproveita resultados parciais. Em termos intuitivos, é como se o sistema guardasse partes do raciocínio já verificadas, evitando repetir o mesmo trabalho a cada novo fato inserido. Essa ideia foi decisiva para tornar motores de produção mais eficientes em bases volumosas.

Exemplo Computacional

Um pseudocódigo simples de encadeamento para a frente pode ser escrito assim:

while existe_regra_aplicavel(memoria, regras):
    agenda = regras_ativadas(memoria, regras)
    regra = escolher_regra(agenda)
    memoria = disparar(regra, memoria)

Já uma visão simplificada de encadeamento para trás poderia ser:

def provar(meta, fatos, regras):
    if meta in fatos:
        return True
    for regra in regras_com_consequente(meta):
        if all(provar(premissa, fatos, regras) for premissa in regra.premissas):
            return True
    return False

Esses esquemas deixam clara a diferença central entre os dois paradigmas: no primeiro, os fatos empurram o raciocínio para frente; no segundo, a meta puxa o raciocínio para trás. Em aplicações modernas, os dois estilos ainda aparecem, isoladamente ou de forma híbrida, em compliance, automação de atendimento, triagem clínica, motores de recomendação baseados em políticas, auditoria e integração de conhecimento simbólico com sistemas orientados por dados.

22.10 - Raciocínio Não-Monotônico.

Na lógica monotônica clássica, acrescentar novas premissas não invalida conclusões já obtidas corretamente. Se uma conclusão era derivável a partir de um conjunto de premissas, ela continua derivável mesmo quando adicionamos mais informação. Esse comportamento é elegante do ponto de vista formal, mas entra em choque com vários padrões de raciocínio do cotidiano. Em problemas reais, trabalhamos frequentemente com informação incompleta, regras gerais sujeitas a exceções e hipóteses provisórias. O raciocínio não monotônico surge justamente para modelar esse cenário, em que uma conclusão razoável hoje pode precisar ser revista amanhã diante de novas evidências.

Uma analogia simples é a de um médico em uma triagem inicial. Ao ouvir certos sintomas, ele formula uma hipótese plausível e toma decisões preliminares. Quando novos exames chegam, essa hipótese pode ser fortalecida, refinada ou abandonada. O ponto central não é que o médico “errou”, mas que ele raciocinou da melhor forma possível com a informação disponível naquele momento. O raciocínio não monotônico tenta formalizar esse comportamento de revisão controlada.

Por que a monotonicidade falha no senso comum

O exemplo clássico é: “aves normalmente voam”. Se sabemos apenas que piu é uma ave, parece razoável concluir por default que piu voa. Mas, se depois descobrimos que piu é um pinguim, a conclusão deve ser retirada. Esse tipo de inferência é chamado de derrotável ou defeasible: vale na ausência de informação contrária, mas pode ser vencida por uma exceção mais específica.

Em termos lógicos, podemos imaginar uma regra geral informal como:

$$ Ave(x) \wedge \text{normal}(x) \rightarrow Voa(x) $$

Se temos apenas Ave(piu), poderíamos assumir por default que normal(piu) vale e então concluir Voa(piu). Mas, ao acrescentar Pinguim(piu) e a informação de que pinguins são aves que normalmente não voam, a hipótese anterior precisa ser revisada. O conjunto de conclusões diminui ou muda. Isso é exatamente o contrário da monotonicidade clássica.

Matematicamente, o contraste pode ser expresso assim. Em uma lógica monotônica, se $\Gamma \vdash \varphi$, então para qualquer conjunto adicional $\Delta$, também temos $\Gamma \cup \Delta \vdash \varphi$. No raciocínio não monotônico, essa propriedade deixa de valer em geral. O símbolo $\vdash$ pode ser lido como “deriva” ou “prova”. A ideia é simples: aprender mais pode obrigar o agente a saber menos do que ele julgava saber antes.

Exemplo de raciocinio nao monotonico com ave, conclusao default de voo e revisao apos a descoberta de que o animal e um pinguim.
Figura 9. Uma conclusão default pode ser razoável em um estágio do conhecimento e tornar-se inadequada quando uma exceção é descoberta.
Contexto histórico

O tema ganhou força na IA a partir dos anos 1970 e 1980, quando pesquisadores perceberam que a lógica clássica, embora poderosa, não bastava para formalizar conhecimento de senso comum. John McCarthy defendeu a necessidade de mecanismos capazes de representar o que é normalmente verdadeiro, sem exigir a enumeração exaustiva de todas as exceções. Nessa linha surgiram propostas como a circunscrição, associada a McCarthy, e a lógica default de Raymond Reiter. Posteriormente, a revisão de crenças ganhou formulações próprias, como a tradição AGM, preocupada em descrever como um agente racional deve modificar seu conjunto de crenças ao receber nova informação.

Esses desenvolvimentos mostram que o problema não era apenas técnico, mas conceitual. A IA precisava de formalismos capazes de distinguir entre conhecimento estrito, que vale sem exceção, e conhecimento presumido, que vale “normalmente”. Também precisava modelar mudança epistêmica: como alterar um sistema de crenças preservando o máximo possível do que já se sabia, mas sem ignorar a nova evidência.

Defaults, exceções e especificidade

Uma ideia recorrente em raciocínio não monotônico é a do default: uma regra aplicada na ausência de informação em contrário. Em linguagem natural, defaults aparecem em frases como “estudantes costumam ter matrícula”, “carros normalmente precisam de combustível” ou “e-mails com muitos links suspeitos tendem a ser spam”. Nenhuma dessas regras é absoluta, mas todas são úteis como guias iniciais.

Um exemplo computacional simples seria:

SE ave(X) E nao_ha_evidencia_de_excecao(X) ENTAO voa(X)
SE pinguim(X) ENTAO ave(X)
SE pinguim(X) ENTAO excecao_voo(X)

Se o sistema conhece apenas ave(piu), pode inferir voa(piu). Ao adicionar pinguim(piu), entra em cena a exceção. Em muitas abordagens, regras mais específicas derrotam regras mais gerais. Esse princípio de especificidade é crucial para evitar conclusões absurdas e aparece também em classificação, ontologias com exceções, triagem automática e políticas de negócio.

O tema conversa naturalmente com estruturas de ordem parcial e preferência. Quando duas conclusões entram em conflito, o sistema pode precisar decidir qual delas tem prioridade. Em alguns formalismos, isso é feito por minimização, em outros por hierarquia de regras, por preferências explícitas ou por modelos de revisão. Essa proximidade com relações de ordem ajuda a conectar o tema à matemática da escolha racional e da otimização sob restrições conceituais.

Revisão de crenças

Outra vertente importante é a revisão de crenças. Imagine que um agente mantém um conjunto de crenças $K$. Quando recebe uma nova informação $\alpha$, ele não pode simplesmente somá-la a $K$ se isso produzir inconsistência. Precisa haver um processo de revisão, frequentemente escrito como:

$$ K * \alpha $$

Nessa notação, $*$ representa um operador de revisão: o novo estado de crenças obtido ao incorporar $\alpha$ em $K$. A grande questão é como fazer isso preservando o máximo possível do conhecimento anterior. Se o agente acreditava que “o servidor principal está ativo” e recebe uma evidência forte de falha, talvez precise abandonar algumas inferências derivadas dessa crença, mas não jogar fora tudo o que sabia sobre a rede.

Um exemplo pequeno mostra a ideia. Suponha:

$$ K = \{A, A \rightarrow B\} $$

Desse conjunto, derivamos $B$. Se chega a nova informação $\neg A$, não podemos manter simultaneamente $A$ e $\neg A$ num sistema consistente. Revisar $K$ por $\neg A$ significa reconstruir o conjunto de crenças, talvez preservando regras úteis, mas abandonando a crença antiga em $A$. Esse tipo de problema aparece em agentes autônomos, monitoramento de sistemas, segurança, diagnóstico, assistência médica e integração de múltiplas fontes de informação.

Aplicações contemporâneas

Embora o auge histórico do tema tenha ocorrido na IA simbólica clássica, o raciocínio não monotônico continua atual. Sistemas modernos precisam lidar com políticas que admitem exceções, conhecimento jurídico com precedência contextual, bases médicas sujeitas a atualização, filtros de moderação com regras derrotáveis e agentes que operam sob informação parcial. Em arquiteturas híbridas, combinando aprendizado estatístico com módulos simbólicos, a necessidade de revisar hipóteses continua central. Um modelo pode apontar uma classe provável; um módulo simbólico pode vetar a conclusão ao detectar uma condição excepcional.

Em síntese, o raciocínio não monotônico é a tentativa de formalizar uma ideia profundamente humana: raciocinar bem não significa jamais voltar atrás, mas saber quando uma conclusão deve ser mantida, refinada ou abandonada. Essa capacidade de revisão aproxima os sistemas inteligentes de domínios reais, em que quase nunca dispomos de todas as informações desde o início.

22.11 - Formalismos para a Representação de Conhecimento Incerto.

Nem todo conhecimento disponível para um sistema inteligente é exato, completo ou confiável. Em muitos domínios, a IA precisa raciocinar com sintomas que apenas sugerem doenças, sensores sujeitos a ruído, linguagem imprecisa, testemunhos incompletos, previsões instáveis e categorias vagas. Nesses contextos, a lógica clássica pura muitas vezes é insuficiente, porque exige afirmações totalmente verdadeiras ou totalmente falsas. Surgem então formalismos destinados a representar diferentes tipos de incerteza, imprecisão e evidência parcial.

Uma analogia útil é pensar em três médicos avaliando o mesmo paciente. O primeiro diz: “há 80% de chance de pneumonia”; o segundo diz: “a regra me deixa moderadamente confiante nessa hipótese”; o terceiro diz: “a febre está alta em grau 0,8”. As três falas envolvem números, mas não significam a mesma coisa. A primeira fala em probabilidade de ocorrência. A segunda expressa um grau de confiança operacional em uma conclusão. A terceira descreve um conceito vago, “febre alta”, com pertencimento gradual. Distinguir essas situações é essencial para escolher o formalismo correto.

Naturezas diferentes da incerteza

Antes de escolher um formalismo, é preciso perguntar: qual é o problema? Às vezes, a incerteza decorre de desconhecimento sobre se um evento ocorreu. Em outros casos, o problema é a imprecisão da linguagem, como “temperatura elevada”, “risco moderado” ou “paciente jovem”. Em outros ainda, lidamos com fontes parciais de evidência que apoiam conclusões em intensidades diferentes, sem necessariamente formar uma probabilidade bem calibrada. A matemática adequada depende da natureza do fenômeno.

Essa distinção ajuda a evitar uma confusão frequente. Um valor como 0,7 pode representar muitas coisas diferentes. Pode significar probabilidade, grau de crença, fator de certeza, pertinência fuzzy, possibilidade ou peso heurístico. O número isolado não basta; é o formalismo que dá semântica ao valor.

Comparacao entre probabilidade, fatores de certeza, logica fuzzy e teoria da evidencia para representar incerteza.
Figura 10. Formalismos diferentes tratam problemas diferentes: ocorrência incerta, apoio evidencial, vagueza conceitual ou combinação de evidências parciais.
Probabilidade

A probabilidade é o formalismo mais consolidado quando o objetivo é quantificar incerteza sobre eventos. Ela é especialmente adequada quando queremos responder perguntas como “qual a chance de chover?”, “qual a probabilidade de falha do servidor?” ou “qual a probabilidade de um e-mail ser spam?”. Matematicamente, uma probabilidade é uma função $P$ que associa valores entre 0 e 1 a eventos, respeitando propriedades como:

$$ 0 \leq P(A) \leq 1, \quad P(\Omega)=1 $$

e, para eventos mutuamente exclusivos,

$$ P(A \cup B) = P(A) + P(B) $$

Se um sensor acerta 90% das vezes ao detectar fumaça, podemos modelar esse comportamento probabilisticamente. Esse tipo de formalização é central em classificação estatística, filtragem bayesiana, redes probabilísticas, visão computacional, robótica e previsão. A próxima seção aprofunda justamente a atualização dessas probabilidades com a Regra de Bayes, por isso aqui o importante é fixar a natureza do formalismo: ele trata incerteza sobre ocorrência, não vagueza linguística.

Fatores de certeza

Antes da consolidação ampla dos modelos probabilísticos em IA aplicada, sistemas especialistas recorreram a mecanismos mais pragmáticos para lidar com incerteza. Um dos mais conhecidos foi o uso de fatores de certeza no sistema MYCIN, desenvolvido para apoio a diagnóstico médico. Em vez de exigir probabilidades rigorosas para cada regra, o sistema trabalhava com valores que indicavam quanto uma evidência favorecia ou enfraquecia uma hipótese.

Se uma regra disser que “culturas positivas apoiam fortemente a hipótese de infecção bacteriana”, o sistema pode associar a isso um fator de certeza como 0,8. Esse valor não precisa ser interpretado exatamente como probabilidade. Ele funciona mais como uma medida operacional de apoio. Um exemplo simplificado seria:

SE febre_alta(X) E cultura_positiva(X) ENTAO infeccao_bacteriana(X) [FC = 0.8]

Se outra evidência enfraquece a conclusão, o sistema precisa combinar fatores positivos e negativos. Essa abordagem foi historicamente importante porque permitia construir sistemas úteis mesmo sem uma teoria probabilística completa para cada domínio. Ao mesmo tempo, ela revelou limites conceituais: nem sempre os fatores obedecem propriedades probabilísticas claras, e sua combinação pode depender fortemente de hipóteses implícitas sobre independência, reforço e conflito entre evidências.

Lógica fuzzy e vagueza

A lógica fuzzy e a teoria de conjuntos fuzzy, associadas a Lotfi Zadeh a partir de 1965, foram desenvolvidas para outro tipo de problema: a vagueza. Aqui a questão não é “ocorreu ou não ocorreu?”, mas “em que grau este objeto pertence a um conceito gradual?”. Em vez de perguntar se uma temperatura é estritamente “quente” ou “não quente”, perguntamos em que grau ela pertence ao conjunto dos valores considerados quentes.

Se definimos uma função de pertinência $\mu_{Quente}(x)$, podemos ter:

$$ \mu_{Quente}(28)=0{,}6, \qquad \mu_{Quente}(35)=0{,}9 $$

A notação $\mu_A(x)$ deve ser lida como “grau de pertencimento de $x$ ao conjunto fuzzy $A$”. Isso não significa que a temperatura 28 graus “tem 60% de chance de ser quente”. Significa que o conceito “quente” se aplica a ela com intensidade 0,6 segundo uma convenção de modelagem. Esse formalismo é especialmente útil em controle, decisão gradual, linguística computacional, classificação flexível e sistemas embarcados. A seção `22.13` aprofunda esse tema.

Teoria da evidência e incerteza parcial

Há ainda formalismos que procuram representar não apenas crenças pontuais, mas também ignorância parcial. Uma família importante é a teoria da evidência, associada a Dempster e Shafer. A ideia geral é permitir que uma fonte apoie não apenas um evento específico, mas também um conjunto de hipóteses, refletindo informação incompleta. Em vez de dizer diretamente “a hipótese A tem probabilidade 0,7”, uma evidência pode atribuir massa a um conjunto de hipóteses compatíveis.

Um exemplo intuitivo seria um sensor que detecta “algum movimento anômalo”, mas não distingue se a causa é uma pessoa ou um animal. Em vez de distribuir imediatamente probabilidades finas, o sistema pode registrar apoio ao conjunto {pessoa, animal}. Esse tipo de formalismo é relevante quando as fontes são incompletas, heterogêneas ou difíceis de calibrar probabilisticamente. Ele aparece em fusão de sensores, defesa, diagnóstico e monitoramento em ambientes incertos.

Comparação conceitual

Vale resumir a diferença central. Probabilidade modela incerteza sobre ocorrência. Fatores de certeza modelam apoio operacional a conclusões em sistemas baseados em regras. Lógica fuzzy modela vagueza e pertencimento gradual. Teorias de evidência modelam apoio parcial e ignorância estruturada. Esses formalismos podem coexistir em um mesmo sistema, desde que cada um seja usado para o tipo correto de problema.

Em aplicações contemporâneas, essa distinção continua importante. Um carro autônomo pode usar modelos probabilísticos para estimar a posição de objetos, lógica fuzzy para controle suave de velocidade e distância, e regras com pesos ou políticas híbridas para lidar com decisões excepcionais. Em saúde, um sistema pode combinar probabilidade para risco clínico, fatores de apoio para triagem e termos vagos em descrições textuais de sintomas. Em IA moderna, o valor prático não está em eleger um único formalismo universal, mas em entender qual estrutura expressa melhor cada forma de incerteza.

22.12 - A Regra de Bayes.

A Regra de Bayes é um dos resultados mais importantes da teoria da probabilidade e da IA probabilística. Ela permite inverter condicionais: em vez de perguntar apenas “qual a probabilidade de observar certa evidência se uma hipótese for verdadeira?”, podemos perguntar “qual a probabilidade da hipótese ser verdadeira depois de observar a evidência?”. Essa passagem da observação para a revisão da crença é o coração da inferência bayesiana.

Em termos intuitivos, Bayes funciona como um mecanismo de atualização racional. Começamos com uma crença inicial sobre uma hipótese, observamos dados e então recalculamos essa crença. Uma analogia útil é a de um investigador. Antes de examinar novas pistas, ele já tem uma suspeita inicial sobre os possíveis culpados. Cada pista nova não cria a investigação do zero, mas altera o peso relativo das hipóteses já existentes. Bayes formaliza esse movimento de “antes” para “depois”.

Forma matemática da regra

Sua forma mais conhecida é:

$$ P(A \mid B) = \frac{P(B \mid A)\,P(A)}{P(B)} $$

Nessa expressão, $P(A)$ é a probabilidade a priori de $A$, isto é, a crença inicial antes de observar a evidência. O termo $P(B \mid A)$ é a verossimilhança, ou likelihood: a probabilidade de observar $B$ caso $A$ seja verdadeiro. Já $P(A \mid B)$ é a probabilidade a posteriori, isto é, a crença atualizada em $A$ depois de observar $B$. A barra vertical $\mid$ é lida como “dado que”. O denominador $P(B)$ funciona como fator de normalização: garante que as probabilidades finais continuem coerentes.

Do ponto de vista algébrico, a fórmula é consequência direta da definição de probabilidade condicional:

$$ P(A \mid B)=\frac{P(A \cap B)}{P(B)} \qquad \text{e} \qquad P(B \mid A)=\frac{P(A \cap B)}{P(A)} $$

Igualando as duas expressões para $P(A \cap B)$, obtemos a Regra de Bayes. Esse detalhe é didaticamente importante porque mostra que Bayes não é um truque isolado, mas uma consequência natural da teoria básica de probabilidade.

Fluxo visual da Regra de Bayes mostrando prior, likelihood, evidencia e posterior.
Figura 11. A inferência bayesiana combina crença inicial, força da evidência e normalização para produzir uma crença atualizada.
Contexto histórico

Historicamente, a regra leva o nome de Thomas Bayes, cujas ideias foram publicadas postumamente no século XVIII e depois desenvolvidas e difundidas por Richard Price e por Laplace. No século XX, a abordagem bayesiana ganhou um papel central em estatística, filosofia da ciência e IA. Em inteligência artificial, sua importância cresceu especialmente quando sistemas probabilísticos passaram a competir com abordagens puramente baseadas em regras para lidar com diagnóstico, percepção, aprendizado e tomada de decisão sob incerteza.

A partir dos anos 1980, trabalhos de Judea Pearl consolidaram o papel das redes bayesianas como estruturas gráficas capazes de organizar inferências probabilísticas complexas de modo mais escalável. Assim, a regra de Bayes deixou de ser apenas uma fórmula de sala de aula e passou a atuar como peça operacional em sistemas de classificação, filtragem, fusão de sensores, robótica, PLN e aprendizado de máquina.

Exemplo matemático clássico

Suponha que 1% da população tenha certa doença:

$$ P(D)=0{,}01 $$

Um teste é positivo em 95% dos casos realmente doentes:

$$ P(+ \mid D)=0{,}95 $$

Mas também apresenta falso positivo em 10% dos não doentes:

$$ P(+ \mid \neg D)=0{,}10 $$

Queremos calcular a probabilidade de um paciente estar doente dado que o teste foi positivo:

$$ P(D \mid +) = \frac{P(+ \mid D)\,P(D)}{P(+)} $$

Primeiro calculamos a probabilidade total de teste positivo pela lei da probabilidade total:

$$ P(+) = P(+ \mid D)P(D) + P(+ \mid \neg D)P(\neg D) $$

Como $P(\neg D)=0{,}99$, temos:

$$ P(+) = 0{,}95 \cdot 0{,}01 + 0{,}10 \cdot 0{,}99 = 0{,}1085 $$

Logo,

$$ P(D \mid +) = \frac{0{,}95 \cdot 0{,}01}{0{,}1085} \approx 0{,}0876 $$

Ou seja, mesmo com teste positivo, a probabilidade de doença é de aproximadamente 8,76%. Esse resultado costuma surpreender porque nossa intuição tende a ignorar a taxa base. O exemplo mostra por que Bayes é tão importante: ele força o raciocínio a combinar a qualidade do teste com a frequência inicial da condição estudada.

Exemplo computacional

Em código, uma atualização bayesiana simples pode aparecer assim:

p_doenca = 0.01
p_pos_dado_doenca = 0.95
p_pos_dado_sem_doenca = 0.10

p_pos = p_pos_dado_doenca * p_doenca + p_pos_dado_sem_doenca * (1 - p_doenca)
p_doenca_dado_pos = (p_pos_dado_doenca * p_doenca) / p_pos

Esse padrão de cálculo aparece em diagnóstico médico, detecção de fraude, classificação de texto, filtragem de spam e triagem automatizada. Em classificadores Naive Bayes, por exemplo, a ideia é calcular a probabilidade posterior de uma classe dada a observação de certos atributos, assumindo independência condicional simplificada entre eles.

Extensões naturais

A regra também conversa com subtópicos importantes da matemática e da IA. Um deles é a lei da probabilidade total, já usada acima. Outro é a independência condicional, central para redes bayesianas e modelos probabilísticos fatorados. Se variáveis são condicionalmente independentes dado um contexto, conseguimos decompor distribuições complexas em partes menores, reduzindo o custo computacional da inferência.

Em redes bayesianas, por exemplo, a distribuição conjunta pode ser fatorada como:

$$ P(x_1,\dots,x_n)=\prod_{i=1}^{n} P(x_i \mid pa_i) $$

Nessa fórmula, $pa_i$ representa os pais de $x_i$ no grafo. A ideia é que a estrutura do grafo codifica dependências relevantes e independências condicionais. Isso torna a aplicação de Bayes escalável em problemas reais, como monitoramento de máquinas, inferência causal aproximada, sistemas tutores, bioinformática e diagnóstico em redes complexas.

Aplicações contemporâneas

Hoje, a regra de Bayes continua presente em áreas muito diversas. Em visão computacional, ajuda a combinar pistas visuais com conhecimento prévio. Em robótica, aparece em localização probabilística e fusão de sensores. Em PLN, está por trás de modelos clássicos de classificação e de mecanismos de reranqueamento. Em segurança digital, ajuda a estimar a probabilidade de comportamento malicioso a partir de sinais parciais. Em saúde, aparece em triagem, rastreamento populacional e apoio a diagnóstico.

Em síntese, Bayes é uma regra de atualização de crenças sob evidência. Seu valor para a IA não está apenas na fórmula, mas na mudança de perspectiva que ela impõe: inferir não é apenas reconhecer padrões observados, mas revisar hipóteses de maneira quantitativamente coerente quando novos dados chegam.

22.13 - Conjuntos e Lógica Fuzzy.

Na lógica clássica, uma afirmação é verdadeira ou falsa, e um elemento pertence ou não pertence a um conjunto. Em muitos problemas práticos, porém, essa divisão rígida não representa bem conceitos vagos ou graduais. Palavras como “alto”, “quente”, “próximo”, “arriscado” ou “jovem” raramente têm fronteiras exatas no mundo real. A teoria de conjuntos fuzzy e a lógica fuzzy surgem justamente para modelar esse tipo de transição suave entre pertencer e não pertencer.

Uma analogia simples é pensar no amanhecer. Não existe um instante universal em que a noite termina abruptamente e o dia começa com fronteira perfeita para toda percepção humana. Há uma passagem gradual. A lógica fuzzy tenta capturar matematicamente esse tipo de gradação, muito comum em linguagem natural, controle, classificação e tomada de decisão.

Contexto histórico

A teoria dos conjuntos fuzzy foi proposta por Lotfi Zadeh em 1965. A ideia central era estender a noção clássica de pertencimento para permitir graus intermediários entre 0 e 1. Em vez de exigir que um objeto pertença ou não pertença a um conjunto, passamos a admitir pertencimento parcial. Essa proposta teve forte impacto em áreas aplicadas, especialmente controle e sistemas embarcados, porque oferecia uma ponte entre descrições linguísticas humanas e mecanismos computacionais formais.

Mais tarde, a lógica fuzzy evoluiu também como objeto matemático próprio, com semântica, conectivos, sistemas dedutivos e diferentes interpretações para conjunção, disjunção e implicação. Assim, o tema passou a ter duas faces complementares: uma mais aplicada, ligada a conjuntos, regras e controle; e outra mais formal, ligada à lógica matemática de verdade parcial.

Função de pertinência

Se um conjunto clássico pode ser representado por uma função indicadora que vale apenas 0 ou 1, um conjunto fuzzy é representado por uma função de pertinência:

$$ \mu_A : X \rightarrow [0,1] $$

Nessa notação, $X$ é o universo de discurso e $\mu_A(x)$ indica o grau com que o elemento $x$ pertence ao conjunto fuzzy $A$. Se o conjunto é “temperaturas quentes”, então $\mu_{Quente}(x)$ mede o quanto a temperatura $x$ é considerada quente segundo o modelo adotado.

Por exemplo:

$$ \mu_{Quente}(20)=0{,}1,\qquad \mu_{Quente}(28)=0{,}6,\qquad \mu_{Quente}(35)=0{,}9 $$

Esses valores não são probabilidades. Eles não significam “20 graus tem 10% de chance de ser quente”. Significam, isso sim, que o conceito “quente” se aplica a esses valores com intensidades diferentes. Essa distinção já foi preparada na seção `22.11` e aqui ela se torna operacional.

Curva de pertinencia fuzzy e exemplo de operacoes de conjunto com graus graduais.
Figura 12. Em conjuntos fuzzy, o pertencimento varia gradualmente; operações como interseção e união passam a combinar graus, não apenas rótulos binários.
Exemplo matemático de função triangular

Uma escolha comum em aplicações é a função de pertinência triangular. Se quisermos modelar “temperatura morna”, poderíamos definir uma função centrada em 25 graus, crescendo linearmente até esse ponto e depois decrescendo. Um exemplo simples seria:

$$ \mu_{Morna}(x)= \begin{cases} 0, & x \leq 18 \\ \frac{x-18}{7}, & 18 < x \leq 25 \\ \frac{32-x}{7}, & 25 < x < 32 \\ 0, & x \geq 32 \end{cases} $$

Se $x=21$, então:

$$ \mu_{Morna}(21)=\frac{21-18}{7}=\frac{3}{7}\approx 0{,}43 $$

Se $x=25$, temos pertinência máxima igual a 1. Esse tipo de função é útil porque é simples, interpretável e fácil de implementar. Outras formas comuns incluem funções trapezoidais, gaussianas e sigmoides, dependendo do comportamento desejado.

Operações fuzzy

Assim como em conjuntos clássicos temos união, interseção e complemento, em conjuntos fuzzy também definimos operações correspondentes. Uma escolha muito comum é:

$$ \mu_{A \cap B}(x)=\min(\mu_A(x),\mu_B(x)) $$

$$ \mu_{A \cup B}(x)=\max(\mu_A(x),\mu_B(x)) $$

$$ \mu_{\neg A}(x)=1-\mu_A(x) $$

Suponha que um carro tenha grau 0,7 no conjunto “rápido” e 0,5 no conjunto “econômico”. Então, usando interseção pelo mínimo:

$$ \mu_{Rapido \cap Economico}(carro)=\min(0{,}7,0{,}5)=0{,}5 $$

Essas definições não são as únicas possíveis. Em lógica fuzzy matemática aparecem conectivos mais gerais, como t-normas e t-conormas, que generalizam interseção e união. Isso aproxima o tema de álgebra, teoria da ordem e lógica multivalorada.

Regras fuzzy e inferência aproximada

O grande valor prático da lógica fuzzy aparece quando combinamos conjuntos fuzzy com regras linguísticas. Um sistema pode usar regras do tipo:

SE temperatura e alta ENTAO ventilacao e forte
SE temperatura e morna ENTAO ventilacao e media
SE temperatura e baixa ENTAO ventilacao e fraca

Aqui, palavras como “alta”, “morna” e “forte” não são tratadas como categorias rígidas, mas como conjuntos fuzzy. Se a temperatura observada ativa parcialmente mais de uma regra, o sistema combina essas ativações para produzir uma resposta gradual. Em seguida, um processo de desfuzzificação converte o resultado fuzzy em uma ação numérica, como a velocidade do ventilador.

Um pseudocódigo simples seria:

grau_alta = mu_alta(temperatura)
grau_morna = mu_morna(temperatura)
grau_baixa = mu_baixa(temperatura)

saida_fuzzy = combinar_regras(grau_alta, grau_morna, grau_baixa)
velocidade = desfuzzificar(saida_fuzzy)

Esse tipo de mecanismo foi amplamente usado em eletrodomésticos, automação industrial, câmeras, transmissão automotiva, controle de freios, robótica e sistemas embarcados. Mesmo em aplicações modernas de IA, ideias fuzzy continuam úteis quando se quer preservar interpretabilidade e suavidade de decisão.

Tópicos matemáticos relacionados

O tema conversa naturalmente com funções reais, intervalos, máximos e mínimos, continuidade, convexidade e teoria da ordem. Em certos desenvolvimentos mais formais, entram também t-normas, residuação, lógicas de Łukasiewicz e semânticas multivaloradas. Para o leitor de computação, o mais importante é perceber que a lógica fuzzy não substitui a probabilidade: ela resolve outro problema. Sua força está em representar conceitos graduais e construir inferência aproximada onde fronteiras rígidas seriam artificiais.

Aplicações contemporâneas

Hoje, lógica fuzzy aparece menos como “moda” isolada e mais como componente de sistemas híbridos. Pode ser combinada com otimização, aprendizado de máquina e controle adaptativo. Em veículos, robôs e dispositivos inteligentes, continua útil quando o comportamento desejado precisa ser estável, interpretável e sensível a transições graduais. Em sistemas de recomendação e avaliação, também pode ser usada para representar critérios vagos como “perfil muito compatível”, “risco moderado” ou “nível de confiança aceitável”.

22.14 - Aprendizado de Máquina.

Aprendizado de máquina é a área da IA que estuda métodos capazes de ajustar modelos automaticamente a partir de dados. Em vez de programar explicitamente todas as regras do comportamento desejado, fornecemos exemplos, observações ou sinais de recompensa para que o sistema aprenda padrões úteis. Essa mudança de paradigma está no centro da revolução atual da IA, porque permitiu escalar sistemas para visão computacional, PLN, recomendação, bioinformática, previsão de demanda, diagnóstico e controle.

Historicamente, o campo ganhou identidade própria quando Arthur Samuel, no fim dos anos 1950, formulou programas capazes de melhorar seu desempenho no jogo de damas a partir da experiência. Pouco depois, Frank Rosenblatt apresentou o perceptron, um dos primeiros modelos de aprendizado supervisionado inspirados em neurônios artificiais. Ao longo das décadas seguintes, o campo incorporou estatística, otimização, teoria da computação e, mais recentemente, o aprendizado profundo em grande escala.

Uma analogia útil é a de três formas de aprender. No aprendizado supervisionado, o aluno recebe exercícios com gabarito. No não supervisionado, ele recebe apenas um monte de material e precisa descobrir sozinho como organizá-lo. No aprendizado por reforço, ele aprende pelas consequências de suas ações, como em um jogo em que algumas escolhas rendem pontos e outras custam oportunidades. Essas três famílias cobrem boa parte das formulações modernas.

Comparação entre aprendizado supervisionado, não supervisionado e por reforço.
Figura 13. Os principais paradigmas de aprendizado diferem pelo tipo de informação fornecida ao sistema: rótulos, estrutura implícita ou sinal de recompensa.
Formulação geral

Em termos matemáticos, o aprendizado supervisionado costuma procurar uma função $f_{\theta}$ parametrizada por $\theta$ que mapeia entradas $x$ em saídas previstas. Dado um conjunto de exemplos $(x_i,y_i)$, escolhemos os parâmetros de modo a minimizar alguma função de perda:

$$ L(\theta)=\sum_{i=1}^{n}\ell(f_{\theta}(x_i),y_i) $$

Aqui, $\ell$ mede o erro entre previsão e resposta correta. Se a perda escolhida for o erro quadrático, obtemos:

$$ L(\theta)=\sum_{i=1}^{n}(f_{\theta}(x_i)-y_i)^2 $$

Essa expressão já apareceu antes no capítulo, mas aqui ela ganha papel conceitual mais amplo: aprender passa a ser otimizar parâmetros para reduzir erro em um conjunto de exemplos. Em classificação, poderíamos usar outras perdas, como entropia cruzada. Em regressão, erros quadráticos ou absolutos são mais comuns.

Treino, validação e teste

Um ponto essencial é que aprender não significa apenas se ajustar bem aos dados já vistos. O objetivo é generalizar para casos novos. Por isso, o conjunto de dados costuma ser dividido em treino, validação e teste. O conjunto de treino ajusta os parâmetros. O de validação ajuda a escolher hiperparâmetros e comparar modelos. O de teste mede desempenho em exemplos mantidos fora do processo de escolha.

Essa separação evita o autoengano estatístico. Um modelo pode memorizar perfeitamente os dados de treino e, ainda assim, falhar em produção. Em termos intuitivos, decorar respostas antigas não é o mesmo que aprender uma regra útil. Em aplicações modernas, essa distinção é crucial em medicina, crédito, detecção de fraude, sistemas judiciais e qualquer tarefa em que o modelo precisará agir sobre casos inéditos.

Aprendizado supervisionado, não supervisionado e por reforço

No aprendizado supervisionado, cada exemplo vem acompanhado da resposta correta. Podemos prever nota final de um estudante, diagnosticar presença de doença a partir de exames ou classificar um e-mail como spam e não spam. No aprendizado não supervisionado, o sistema recebe apenas dados e tenta descobrir estrutura por conta própria. Isso aparece em clusterização, redução de dimensionalidade, detecção de anomalias e descoberta de tópicos.

No aprendizado por reforço, um agente interage com um ambiente e recebe recompensas ao longo do tempo. Em vez de pares entrada-saída fixos, temos sequências de estado, ação e retorno. A formulação matemática natural envolve estados $s$, ações $a$, recompensa $r$ e uma política $\pi$ que decide o que fazer em cada situação. Essa vertente conecta aprendizado de máquina com teoria da decisão, programação dinâmica e controle estocástico.

Exemplo computacional

Um esqueleto simples de treinamento supervisionado pode ser escrito assim:

for epoca in range(num_epocas):
    previsoes = modelo(x_treino, parametros)
    perda = funcao_de_perda(previsoes, y_treino)
    grad = gradiente(perda, parametros)
    parametros = parametros - taxa_aprendizado * grad

Esse pseudocódigo resume uma das ideias mais importantes do campo: ajustar iterativamente parâmetros com base no gradiente da perda. Mesmo quando o modelo é simples, como regressão linear, ou muito complexo, como uma rede profunda, a lógica geral de otimização permanece próxima.

Aplicações e limites atuais

Hoje, aprendizado de máquina está presente em busca, recomendação, tradução, diagnóstico assistido, reconhecimento de voz, direção autônoma, previsão climática, descoberta de fármacos, otimização industrial e assistência educacional. Ao mesmo tempo, seu sucesso trouxe desafios novos: viés amostral, dados desequilibrados, fuga de dados, custo energético, falta de interpretabilidade e sensibilidade a mudanças de distribuição entre treino e uso real.

Por isso, entender aprendizado de máquina não é apenas saber treinar um modelo. É saber formular o problema, escolher dados, definir métricas, avaliar generalização e reconhecer limitações. As próximas seções aprofundam essa base ao tratar de aprendizado indutivo e de famílias específicas de modelos.

22.15 - Aprendizado Indutivo.

Aprendizado indutivo é o processo de generalizar a partir de exemplos particulares. O sistema observa casos concretos e tenta construir uma hipótese que explique esses casos e funcione bem para novos exemplos ainda não vistos. Em termos simples, a indução pergunta: “que regularidade geral parece plausível a partir dos dados que observei?”.

Essa questão está no centro da aprendizagem automática e tem importância filosófica e matemática antiga. Desde muito antes dos computadores, o problema da indução já aparecia na ciência: como justificar leis gerais a partir de observações finitas? Em IA, a pergunta reaparece em forma operacional: dado um conjunto de exemplos, como escolher uma hipótese entre muitas possíveis?

Seja $\mathcal{H}$ um espaço de hipóteses possíveis. Aprender indutivamente significa escolher uma hipótese $h \in \mathcal{H}$ que explique bem os dados de treino e tenha boa capacidade de generalização. O problema é que, em geral, existem muitas hipóteses compatíveis com um conjunto finito de exemplos. Por isso, nenhum aprendizado é totalmente neutro: sempre há algum viés indutivo, isto é, alguma preferência por certos tipos de hipótese.

Viés indutivo e generalização

Uma analogia útil é a de um professor corrigindo redações. Se dois alunos deram respostas corretas nas questões já vistas, mas um sempre escreveu regras simples e o outro inventou exceções ad hoc para cada caso, o professor tende a confiar mais no primeiro para questões futuras. Em aprendizado de máquina, fazemos algo parecido: preferimos hipóteses mais simples, mais estáveis ou mais coerentes com o conhecimento do domínio.

Essa preferência pode ser expressa de várias formas. Pode surgir na escolha do modelo, da regularização, da profundidade máxima de uma árvore, do grau de um polinômio ou da própria arquitetura da rede neural. Em linguagem matemática, aprender envolve equilibrar erro empírico e complexidade do modelo. Esse tema conversa com probabilidade, estatística, teoria da informação e teoria da computação.

Exemplo matemático

Suponha que observamos três pontos:

$$ (1,2),\quad (2,4),\quad (3,6) $$

Uma hipótese simples seria a função linear $h(x)=2x$. Mas também poderíamos construir um polinômio de grau 2, 3 ou maior que passe exatamente por esses pontos. O fato de várias hipóteses se ajustarem aos dados mostra por que a indução não é trivial. Escolher $h(x)=2x$ significa apostar que a regularidade observada continuará fora do conjunto amostrado.

Se tivermos ainda um quarto ponto real em $x=4$ com valor 8, a hipótese linear generaliza bem. Se um polinômio de grau elevado produzisse 23 nesse ponto, perceberíamos que ele decorou o treino sem capturar a regularidade relevante. Esse é o problema clássico do overfitting.

Overfitting, underfitting e regularizacao

Quando o modelo é simples demais para representar o padrão real, temos underfitting. Quando é complexo demais e começa a memorizar ruídos ou peculiaridades do treino, temos overfitting. O objetivo do aprendizado indutivo é encontrar uma faixa intermediária em que o modelo seja expressivo o bastante para captar regularidades, mas não tão flexível a ponto de perder generalização.

Uma forma matemática comum de tratar isso é penalizar complexidade no objetivo de treino:

$$ L(\theta)=\sum_{i=1}^{n}\ell(f_{\theta}(x_i),y_i)+\lambda \,\Omega(\theta) $$

Aqui, $\Omega(\theta)$ representa um termo de regularização, e $\lambda$ controla seu peso. A ideia é simples: não basta ajustar os dados; também queremos evitar soluções excessivamente complexas.

Validação cruzada e exemplo computacional

Na prática, a escolha entre hipóteses concorrentes costuma ser feita com validação cruzada ou com conjuntos separados de validação. Um pseudocódigo simples seria:

melhor_modelo = None
melhor_erro = infinito

for modelo in candidatos:
    ajustar(modelo, treino)
    erro = avaliar(modelo, validacao)
    if erro < melhor_erro:
        melhor_modelo = modelo
        melhor_erro = erro

Esse procedimento materializa a ideia de indução controlada: não escolhemos a hipótese apenas porque ela se ajustou ao passado, mas porque mostrou comportamento promissor em dados não usados diretamente no ajuste.

Aplicações atuais

O aprendizado indutivo continua central em classificação de imagens, diagnóstico, previsão financeira, modelos de linguagem, detecção de falhas, segurança digital e sistemas educacionais adaptativos. Em todos esses casos, a pergunta subjacente permanece a mesma: como passar de observações finitas para regras que funcionem bem em situações novas? A resposta nunca é puramente mecânica; depende de escolha de representação, avaliação estatística e conhecimento sobre o domínio.

22.16 - Árvores de Decisão, Redes Neurais e Algoritmos Genéticos.

Estas três famílias ocupam posições muito diferentes no ecossistema da IA. Árvores de decisão privilegiam interpretabilidade e particionamento explícito do espaço de atributos. Redes neurais privilegiam representação distribuída e capacidade de ajustar padrões complexos em larga escala. Algoritmos genéticos privilegiam busca populacional em espaços onde a estrutura analítica do problema pode ser difícil de explorar diretamente.

Historicamente, cada uma nasceu em um contexto distinto. As árvores de decisão ganharam força com trabalhos de indução simbólica, especialmente com Quinlan e algoritmos como ID3 e C4.5. As redes neurais modernas remontam ao perceptron de Rosenblatt e ganharam novo impulso com a popularização da retropropagação nos anos 1980. Já os algoritmos genéticos foram sistematizados por John Holland como modelos de adaptação inspirados em evolução biológica.

Comparação visual entre árvore de decisão, rede neural e algoritmo genético.
Figura 14. Três estilos de modelagem em IA: regras hierárquicas, representação distribuída e busca evolutiva em populações de soluções.
Árvores de decisão

Árvores de decisão classificam exemplos por meio de testes sucessivos sobre atributos. Cada nó interno faz uma pergunta, cada ramo representa uma resposta possível e cada folha produz uma conclusão. Sua grande vantagem é a interpretabilidade: o raciocínio pode ser lido como uma sequência de perguntas condicionais.

Em um sistema acadêmico, por exemplo, uma árvore pode perguntar: “frequência < 75%?”; “média parcial < 5?”; “houve recuperação?”. A cada resposta, seguimos por um ramo diferente até chegar a uma previsão. Isso aproxima a árvore de um procedimento humano de triagem.

Matematicamente, a construção de árvores costuma envolver medidas de impureza. Uma das mais conhecidas é a entropia:

$$ H(S)=-\sum_{c} p_c \log_2 p_c $$

Se um conjunto $S$ contém 8 aprovados e 8 reprovados, então $p_{aprovado}=p_{reprovado}=0{,}5$, e a entropia vale 1 bit. Se um teste separa bem as classes, a entropia dos subconjuntos diminui. O ganho de informação mede justamente essa redução e ajuda a escolher o melhor atributo para dividir os dados.

Redes neurais artificiais

Redes neurais artificiais são modelos compostos por unidades interconectadas com pesos ajustáveis. Uma unidade simples pode ser escrita como:

$$ y = \sigma(w_1x_1 + w_2x_2 + \cdots + w_nx_n + b) $$

Nessa fórmula, $x_i$ são entradas, $w_i$ são pesos, $b$ é um viés e $\sigma$ é uma função de ativação. A ideia intuitiva é combinar sinais de entrada com importâncias diferentes e produzir uma saída transformada. Empilhando muitas dessas unidades em camadas, obtemos modelos capazes de aprender representações intermediárias complexas.

O passo decisivo para o sucesso prático das redes profundas foi a retropropagação do erro. Se a perda do modelo é $L$, o algoritmo calcula gradientes $\frac{\partial L}{\partial w_i}$ e ajusta os pesos por gradiente descendente. Em linguagem simples, a rede erra, mede quanto cada peso contribuiu para o erro e então corrige esses pesos na direção adequada.

Hoje, redes neurais dominam visão computacional, tradução, reconhecimento de voz, modelagem de proteínas, recomendação e modelos generativos. Sua principal força está na expressividade; sua principal fraqueza costuma ser o custo computacional e a dificuldade de interpretação detalhada.

Algoritmos genéticos

Algoritmos genéticos são métodos de busca e otimização inspirados em processos evolutivos. Em vez de melhorar uma única solução passo a passo, mantemos uma população de soluções candidatas. Cada solução tem uma aptidão, ou fitness, que mede sua qualidade. As melhores tendem a ser selecionadas para reprodução, gerando novas combinações por cruzamento e mutação.

Se uma agenda de produção pode ser codificada como uma sequência de tarefas, um algoritmo genético pode começar com várias agendas aleatórias, medir custo total de atraso e então combinar as melhores agendas para produzir descendentes. Uma mutação pequena, como trocar a ordem de duas tarefas, pode abrir espaço para soluções que a população anterior ainda não havia explorado.

Matematicamente, se $f(s)$ mede a aptidão de uma solução $s$, o algoritmo tenta maximizar $f$ ao longo das gerações. Não há garantia de ótima global em tempo finito, mas a estratégia costuma ser útil em problemas com grande espaço de busca e estrutura irregular, como escalonamento, projeto de circuitos, seleção de parâmetros e otimização combinatória.

Comparação prática

Árvores de decisão são atraentes quando interpretabilidade e rapidez são prioritárias. Redes neurais são preferidas quando a relação entre entrada e saída é altamente complexa e há muitos dados. Algoritmos genéticos são úteis quando a busca é difícil de parametrizar por gradientes ou quando a solução precisa ser codificada de maneira combinatória.

Em aplicações modernas, esses modelos muitas vezes não competem diretamente; eles se complementam. Uma árvore pode explicar decisões locais. Uma rede neural pode aprender representações. Um algoritmo genético pode otimizar hiperparâmetros, arquiteturas ou políticas. O ponto central é reconhecer que “aprender” não significa sempre usar a mesma família de modelo.

22.17 - Sistemas Especialistas.

Sistemas especialistas são programas projetados para reproduzir, em um domínio restrito, parte da capacidade de decisão de especialistas humanos. Em vez de aprender tudo a partir de dados, eles armazenam conhecimento explícito sobre um campo específico e usam mecanismos de inferência para aplicar esse conhecimento a casos concretos. O resultado é um tipo de IA fortemente orientado por regras, explicações e especialização de domínio.

Uma analogia útil é a de um consultor experiente. Ele não sabe tudo sobre o mundo, mas sabe muito sobre um campo particular e consegue justificar suas recomendações com base em princípios, regras, exceções e experiência acumulada. Sistemas especialistas tentam formalizar exatamente esse tipo de competência localizada.

Contexto histórico

O movimento ganhou força a partir de projetos como DENDRAL, dedicado à inferência de estruturas químicas, e MYCIN, focado em aconselhamento sobre infecções bacterianas. Mais tarde, sistemas como XCON mostraram valor econômico real em configuração industrial. Esses projetos convenceram a comunidade de que conhecimento explícito e inferência formal podiam gerar comportamento útil, explicável e de impacto prático.

Ao mesmo tempo, eles revelaram uma lição importante da história da IA: em muitos problemas, ter o conhecimento certo é tão importante quanto ter um método geral de busca. Essa percepção ajudou a deslocar o foco da “inteligência geral por heurísticas universais” para a “engenharia do conhecimento” em domínios específicos.

Arquitetura típica

Um sistema especialista clássico costuma ter pelo menos quatro componentes: base de conhecimento, memória de trabalho, motor de inferência e módulo de explicação. A base de conhecimento armazena fatos e regras. A memória de trabalho armazena o caso atual. O motor de inferência combina ambos para produzir conclusões. O módulo de explicação responde perguntas como “por que você chegou a essa recomendação?” ou “que regra foi usada?”.

Em um sistema de suporte técnico, por exemplo, poderíamos ter regras como:

SE temperatura_cpu_alta E ventoinha_parada ENTAO suspeita_falha_refrigeracao
SE suspeita_falha_refrigeracao E desligamento_subito ENTAO prioridade_alta

Esse tipo de estrutura se conecta naturalmente com a seção `22.9`, mas aqui o foco é mais amplo: não apenas como as regras disparam, e sim como um sistema inteiro é montado em torno de conhecimento especializado.

Exemplo explicável

Uma das forças mais importantes dos sistemas especialistas é a explicabilidade nativa. Se o sistema conclui prioridade_alta, ele pode justificar: “usei a regra R2 porque já havia sido inferido suspeita_falha_refrigeracao com base em temperatura alta e ventoinha parada”. Essa característica é valiosa em medicina, direito, auditoria, compliance e suporte técnico, onde não basta decidir; é preciso justificar.

Em termos computacionais, a explicação pode ser obtida registrando a trilha de inferência:

trilha = [
    "temperatura_cpu_alta",
    "ventoinha_parada",
    "R1 => suspeita_falha_refrigeracao",
    "R2 => prioridade_alta"
]
Limites e legado

A principal limitação histórica foi o chamado gargalo de aquisição de conhecimento. Extrair regras corretas, completas e atualizadas de especialistas humanos é caro e difícil. Além disso, sistemas especialistas tendem a ser frágeis fora do domínio previsto e podem ter dificuldade para lidar com ruído, ambiguidade e mudança rápida do ambiente.

Mesmo assim, seu legado permanece. Motores de regras, sistemas de decisão normativa, diagnósticos estruturados, bases jurídicas e sistemas híbridos com módulos simbólicos continuam reutilizando muitas de suas ideias. Em várias arquiteturas modernas, modelos aprendidos por dados convivem com camadas explícitas de regras e restrições, especialmente quando segurança, conformidade ou explicabilidade são prioritárias.

22.18 - Processamento de Linguagem Natural.

Processamento de Linguagem Natural, ou PLN, é a área da IA dedicada à análise, compreensão e geração de linguagem humana. Entre suas tarefas estão tokenização, análise morfológica, marcação gramatical, análise sintática, interpretação semântica, sumarização, tradução, resposta a perguntas, extração de informação e diálogo. O desafio central é que linguagem humana é ambígua, contextual, econômica e dependente de conhecimento de mundo.

Considere a frase “O banco fechou cedo”. A palavra “banco” pode significar uma instituição financeira ou um assento. O contexto é o que resolve a ambiguidade. A analogia é a de um leitor humano que não apenas reconhece palavras, mas interpreta intenção, cenário, conhecimento prévio e expectativas discursivas.

Contexto histórico

Historicamente, o PLN passou por várias fases. Nas décadas iniciais, predominavam gramáticas formais, dicionários e regras simbólicas. Depois vieram métodos estatísticos, com modelos n-grama, HMMs e aprendizado supervisionado para tarefas como etiquetagem morfossintática e classificação. Mais recentemente, redes neurais profundas, embeddings e transformadores remodelaram a área e abriram caminho para grandes modelos de linguagem.

Essa trajetória é importante porque mostra uma tensão recorrente entre estrutura explícita e aprendizado a partir de grandes volumes de texto. A IA atual em linguagem natural combina, em graus variados, estatística, representação vetorial, atenção, pré-treinamento e adaptação a tarefas específicas.

Fluxo de processamento de linguagem natural desde tokenização e embeddings até modelos e tarefas finais.
Figura 15. Em PLN moderno, o texto passa por etapas de representação e modelagem antes de alimentar tarefas como classificação, tradução e resposta a perguntas.
Níveis de análise

O PLN pode ser visto como uma cadeia de níveis. Na morfologia, estudamos a estrutura das palavras. Na sintaxe, estudamos como as palavras se combinam em frases. Na semântica, estudamos significado. Na pragmática, entramos no uso contextual da linguagem. Em aplicações reais, esses níveis se misturam. Uma resposta aparentemente simples muitas vezes depende de todos eles ao mesmo tempo.

Um modo matemático clássico de modelar linguagem é a probabilidade de uma sequência de palavras:

$$ P(w_1,\dots,w_n)=\prod_{t=1}^{n} P(w_t \mid w_1,\dots,w_{t-1}) $$

Essa fatoração diz que a probabilidade de uma frase inteira pode ser decomposta como produto das probabilidades de cada palavra dado o contexto anterior. Modelos de linguagem, dos n-gramas aos transformadores, trabalham justamente com aproximações cada vez mais potentes dessa ideia.

Tokenização, embeddings e transformadores

Em sistemas atuais, o texto costuma ser primeiro dividido em unidades menores chamadas tokens. Esses tokens são então mapeados para vetores numéricos chamados embeddings. A partir daí, modelos neurais processam sequências inteiras, explorando dependências locais e globais. Nos transformadores, o mecanismo de atenção permite que cada token “olhe” para outros tokens relevantes da sequência ao construir sua representação contextual.

Isso foi decisivo para tarefas em que o significado depende de relações distantes na frase, no parágrafo ou no documento. É uma das razões pelas quais modelos baseados em transformadores passaram a dominar tradução, sumarização, resposta a perguntas e geração de texto.

Exemplo computacional

Um pipeline simplificado de classificação de sentimento pode aparecer assim:

tokens = tokenizar(frase)
vetores = embedar(tokens)
representacao = modelo(vetores)
classe = classificador(representacao)

Se a frase for “o atendimento foi lento, mas o produto é excelente”, o sistema precisa lidar com polaridade mista, negação implícita e possivelmente dependências discursivas. Isso mostra por que PLN vai muito além de contar palavras positivas e negativas.

Problemas contemporâneos

Hoje, PLN está no centro de buscadores, tradutores, moderadores de conteúdo, extração de entidades, contratos, sistemas jurídicos, assistentes conversacionais e grandes modelos de linguagem. Ao mesmo tempo, enfrenta desafios importantes: alucinação factual, viés linguístico e cultural, contexto longo, avaliação semântica, robustez a ruído e integração com conhecimento externo verificável.

Em síntese, PLN é a área em que a IA tenta transformar linguagem em estrutura computável sem perder demais a riqueza do significado humano. É justamente essa tensão entre formalização e flexibilidade que torna o campo tão central na era dos modelos generativos.

22.19 - Agentes Inteligentes.

Um agente inteligente é uma entidade que percebe o ambiente por sensores e age sobre ele por atuadores. Seu comportamento é dito racional quando escolhe ações que tendem a maximizar alguma medida de desempenho com base nas informações disponíveis. O conceito de agente é central porque permite reunir, em um único modelo, percepção, representação, decisão, aprendizado e ação.

Uma analogia clara é a de um motorista. Os olhos e espelhos funcionam como sensores; volante, freio e acelerador funcionam como atuadores. O motorista observa, interpreta, prevê consequências e age. Em IA, um agente pode ser muito simples, reagindo a estímulos imediatos, ou muito sofisticado, mantendo memória, objetivos, utilidade e capacidade de adaptação.

Ciclo de um agente inteligente com ambiente, sensores, estado interno, decisão e atuadores.
Figura 16. Um agente observa o ambiente, atualiza seu estado interno, escolhe uma ação e altera novamente o ambiente.
Ambientes e racionalidade

Nem todos os ambientes impõem o mesmo desafio. Alguns são totalmente observáveis; outros são parcialmente observáveis. Alguns são determinísticos; outros são estocásticos. Alguns são episódicos; outros exigem planejamento de longo prazo. Essa classificação é importante porque o desenho do agente depende fortemente do tipo de ambiente em que ele opera.

Uma ferramenta didática clássica é a descrição PEAS: Performance measure, Environment, Actuators, Sensors. Em um robô aspirador, por exemplo, a medida de desempenho pode ser limpar bem com pouco consumo; o ambiente é a casa; os atuadores são rodas e escovas; os sensores incluem colisão, proximidade e carga da bateria.

Tipos de agente

Agentes reflexos simples respondem diretamente à percepção atual. Agentes com modelo mantêm um estado interno sobre aspectos não observados diretamente. Agentes baseados em objetivos escolhem ações levando em conta estados desejados. Agentes baseados em utilidade comparam alternativas pela qualidade esperada de seus resultados. Agentes aprendizes ajustam comportamento com experiência.

Essas categorias não são mutuamente excludentes. Um sistema real pode combinar reflexos rápidos, modelo interno, utilidade e aprendizado. Em aplicações modernas, essa combinação aparece em recomendação, negociação automática, assistentes com ferramentas, robótica autônoma e agentes que interagem com múltiplas APIs e bases de conhecimento.

Formulação matemática

Uma formalização comum em IA é o Processo de Decisão de Markov (MDP), definido por estados $S$, ações $A$, transições $P$, recompensas $R$ e fator de desconto $\gamma$. A ideia é escolher uma política $\pi$ que maximize o retorno esperado. Em termos simbólicos, o valor de uma política pode ser escrito como:

$$ V^{\pi}(s)=\mathbb{E}\left[\sum_{t=0}^{\infty}\gamma^t r_t \mid s_0=s,\pi\right] $$

Essa expressão diz, em essência, que o agente busca maximizar a soma descontada das recompensas futuras. Se o ambiente é parcialmente observável, entram modelos mais ricos, como POMDPs, em que o agente precisa agir sem enxergar completamente o estado do mundo.

Exemplo computacional

Um esqueleto simples de decisão reativa pode ser:

percepcao = observar(ambiente)
estado = atualizar_modelo(estado, percepcao)
acao = escolher_acao(estado, objetivo)
executar(acao)

Mesmo esse pseudocódigo mínimo já mostra a força do paradigma de agentes: ele integra percepção, memória, decisão e ação em um único ciclo. É por isso que o conceito é tão útil para organizar sistemas inteligentes muito diferentes entre si.

Aplicações atuais

Hoje, agentes aparecem em robótica móvel, jogos, sistemas multiagentes, comércio eletrônico, finanças, redes de sensores, operações industriais e assistentes digitais. Com a popularização de modelos de linguagem, também surgiram agentes baseados em LLMs que planejam subtarefas, usam ferramentas externas, consultam documentos e executam fluxos de trabalho. Isso amplia enormemente o alcance do conceito, mas também traz problemas novos de segurança, alinhamento, confiabilidade e supervisão.

22.20 - Robótica.

Robótica estuda o projeto e a operação de sistemas que percebem o ambiente físico e atuam sobre ele. Em IA, a robótica interessa especialmente quando o robô precisa lidar com incerteza, planejar ações, navegar, manipular objetos e adaptar-se a mudanças do ambiente. Isso torna a robótica um ponto de encontro entre algoritmos abstratos e restrições concretas do mundo real.

Uma analogia poderosa é a de um corpo guiado por um cérebro artificial. Sensores fazem o papel dos sentidos, algoritmos fazem o papel do raciocínio, e atuadores executam a ação física. A diferença para muitos outros temas da IA é que, em robótica, erros conceituais frequentemente viram colisões, atrasos, desperdício de energia ou risco físico real.

Pilha conceitual de um sistema robótico com percepção, localização, mapeamento, planejamento e controle.
Figura 17. Robôs inteligentes combinam percepção, estimação de estado, planejamento e controle em ciclos contínuos de interação com o ambiente.
Percepção, localização e mapeamento

Um sistema robótico combina percepção, modelagem, planejamento, controle e atuação. Sensores como câmeras, LiDAR, sonar, encoders e IMUs alimentam estimativas sobre o ambiente e sobre o próprio estado do robô. A partir dessas leituras, o sistema precisa responder perguntas básicas: “onde estou?”, “o que há ao meu redor?” e “como chego aonde preciso ir?”.

Esse problema leva a tópicos clássicos como localização e SLAM (Simultaneous Localization and Mapping). Em SLAM, o robô precisa construir um mapa do ambiente ao mesmo tempo em que estima sua própria posição. A dificuldade é circular: para mapear bem, ele precisa saber onde está; para saber onde está, precisa de um mapa razoável. Por isso, modelos probabilísticos ganharam tanta importância em robótica moderna.

Cinemática, planejamento e controle

Além de perceber, o robô precisa mover-se. Em um manipulador, uma relação típica é a cinemática direta:

$$ x=f(q) $$

Aqui, $q$ representa variáveis articulares, como ângulos de juntas, e $x$ representa a posição do efetuador final no espaço. Em robôs móveis, em vez de braço e garra, pensamos em pose, velocidade e trajetória. O planejamento então precisa encontrar uma sequência de estados ou controles que leve o robô ao objetivo evitando colisões e respeitando restrições físicas.

Matematicamente, isso conecta robótica com geometria, álgebra linear, otimização, controle e probabilidade. Em um caso simples de planejamento em grade, A* pode ser suficiente. Em ambientes contínuos e dinâmicos, entram planejadores de movimento mais sofisticados, filtros probabilísticos, MPC, controle ótimo e aprendizado por reforço.

Exemplo integrado

Imagine um robô móvel em um corredor. Ele pode usar sensores para mapear obstáculos, um algoritmo de localização para estimar sua posição, um planejador para calcular um caminho e um controlador para seguir a trajetória. Em pseudocódigo:

leituras = sensores()
estado = localizar(leituras, mapa)
mapa = atualizar_mapa(estado, leituras)
trajetoria = planejar(estado, meta, mapa)
controle = seguir(trajetoria, estado)
atuar(controle)

Nesse único ciclo reaparecem vários temas do capítulo: busca, heurísticas, incerteza, agentes, otimização e ação física.

Manipulação e autonomia

Robótica não se limita à navegação. Em manipulação, o desafio é agarrar, mover e montar objetos em ambientes estruturados ou desestruturados. Isso exige visão, estimação de pose, planejamento de preensão, controle de força e adaptação a pequenas variações no mundo real. Uma peça alguns milímetros fora do lugar já pode comprometer a operação.

Aplicações modernas incluem logística, agricultura, inspeção industrial, cirurgia assistida, exploração submarina, veículos autônomos, robôs domésticos e plataformas humanoides. Com a ascensão da IA contemporânea, cresce também o interesse em robôs com capacidades multimodais, aprendizado por demonstração e integração entre modelos de linguagem e ação incorporada.

Desafios atuais

Os maiores desafios continuam sendo robustez, segurança, custo energético, interação com humanos, adaptação a ambientes não estruturados e transferência do aprendizado da simulação para o mundo físico. Em visão mais ampla, a robótica é a área em que a IA precisa provar que consegue não apenas inferir e prever, mas agir no mundo material de forma confiável.


Glossário

Agente
Entidade que percebe o ambiente por sensores e age sobre ele por atuadores.
Agenda
Conjunto de regras candidatas a disparo em um sistema de produção, após o casamento entre fatos e condições.
Algoritmo A*
Método de busca que combina custo acumulado e estimativa heurística do custo restante.
Aprendizado de máquina
Área da IA que estuda métodos capazes de ajustar modelos automaticamente a partir de dados.
Aprendizado indutivo
Processo de generalizar hipóteses ou regras a partir de exemplos particulares observados.
Árvore de decisão
Modelo que organiza a classificação ou previsão como uma sequência hierárquica de testes sobre atributos.
A priori
Probabilidade ou crença inicial atribuída a uma hipótese antes da observação de uma nova evidência.
A posteriori
Probabilidade ou crença atualizada de uma hipótese depois da observação da evidência.
Backpropagação
Algoritmo usado para propagar erros em redes neurais e calcular gradientes dos pesos durante o treinamento.
Busca heurística
Estratégia de busca que utiliza conhecimento adicional para orientar a exploração do espaço de estados.
Busca não informada
Busca que utiliza apenas a definição formal do problema, sem estimativas adicionais sobre os estados.
Clusterização
Técnica de aprendizado não supervisionado que agrupa elementos semelhantes em conjuntos.
Encadeamento para a frente
Método de inferência dirigido por dados, no qual novas conclusões são produzidas a partir dos fatos disponíveis.
Encadeamento para trás
Método de inferência dirigido por objetivos, no qual o sistema tenta provar uma hipótese.
Espaço de estados
Conjunto das configurações possíveis de um problema formulado como busca.
Função heurística
Função que estima quão promissor é um estado ou quão distante ele está da meta.
Função objetivo
Função que mede a qualidade de uma solução candidata em um problema de otimização.
Função de perda
Função usada para medir o erro de um modelo em aprendizado de máquina, normalmente minimizada durante o treinamento.
Função de aptidão
Medida de qualidade usada para avaliar soluções candidatas, especialmente em algoritmos evolutivos.
Grafo AND/OR
Estrutura que representa problemas compostos por alternativas exclusivas e subtarefas obrigatórias.
Decomposição de problema
Estratégia de resolver um problema dividindo-o em subproblemas menores e mais manejáveis.
Default
Regra ou suposição aplicada na ausência de evidência contrária, típica do raciocínio não monotônico.
Derrotabilidade
Propriedade de uma conclusão que pode ser retirada quando surge informação mais específica ou conflitante.
Desfuzzificação
Processo de converter uma saída fuzzy, expressa por graus de pertinência, em um valor numérico utilizável por um sistema de controle ou decisão.
Evidência parcial
Informação que apoia uma ou mais hipóteses sem determinar completamente qual delas é verdadeira.
Embedding
Representação vetorial densa de palavras, tokens, imagens ou outros objetos, usada por modelos de aprendizado.
Frame
Estrutura de representação que organiza conhecimento em slots, valores e expectativas típicas sobre uma situação ou objeto.
Generalização
Capacidade de um modelo funcionar bem em exemplos novos, não vistos durante o treinamento.
Grafo de conhecimento
Estrutura em forma de rede que organiza entidades e relações de modo consultável, frequentemente combinando semântica formal e dados heterogêneos.
Gradiente descendente
Método iterativo de otimização que ajusta parâmetros na direção oposta ao gradiente da função de perda.
Herança
Mecanismo pelo qual um conceito ou estrutura especializada reutiliza propriedades definidas em um conceito mais geral.
Heurística admissível
Heurística que nunca superestima o custo real restante até o objetivo.
Heurística consistente
Heurística que respeita uma desigualdade triangular entre estados sucessivos, ajudando a evitar reexpansões desnecessárias em A*.
Hill climbing
Técnica de busca local que melhora sucessivamente uma solução movendo-se para vizinhos melhores.
Hipótese nula
Hipótese estatística que normalmente representa ausência de efeito ou ausência de relação relevante.
Independência condicional
Relação em que duas variáveis se tornam independentes quando o valor de uma terceira variável é conhecido.
Linguagem simbólica
Linguagem que representa conhecimento por símbolos, fatos, relações e regras explícitas.
Lógica fuzzy
Formalismo que permite graus graduais de pertencimento ou verdade entre 0 e 1.
Função de pertinência
Função que atribui a cada elemento de um universo um grau de pertencimento entre 0 e 1 em um conjunto fuzzy.
Memória de trabalho
Conjunto de fatos atualmente disponíveis para o motor de inferência em um sistema de produção.
MDP
Processo de Decisão de Markov, formalismo para tomada de decisão sequencial com estados, ações, recompensas e transições probabilísticas.
Motor de inferência
Componente de um sistema baseado em conhecimento que aplica regras e produz conclusões.
Massa de crença
Valor atribuído, em teorias de evidência, a um conjunto de hipóteses para representar apoio parcial ou ignorância estruturada.
Naive Bayes
Classificador probabilístico que aplica a Regra de Bayes assumindo independência condicional simplificada entre atributos.
Notação $P(A \mid B)$
Probabilidade de $A$ dado que $B$ ocorreu; a barra vertical é lida como “dado que”.
Ontologia
Especificação formal de classes, relações e restrições de um domínio, usada para compartilhar e inferir conhecimento de maneira consistente.
OPS5
Linguagem historicamente importante no desenvolvimento de sistemas de produção e sistemas especialistas baseados em regras.
Operador
Ação que transforma um estado em outro em um problema de busca.
Overfitting
Fenômeno em que um modelo se ajusta demais aos dados de treinamento e perde capacidade de generalização.
Possibilidade
Noção usada em alguns formalismos para representar o quanto uma hipótese é compatível com a informação disponível, distinta de probabilidade.
PEAS
Esquema de descrição de agentes por medida de desempenho, ambiente, atuadores e sensores.
Política
Regra de decisão que indica qual ação um agente deve escolher em cada estado ou situação.
Ótimo local
Solução melhor do que todas as vizinhas imediatas, mas que pode não ser a melhor solução global do problema.
Ótimo global
Melhor solução de todo o espaço de busca segundo a função objetivo adotada.
Paisagem de otimização
Forma intuitiva de visualizar como os valores da função objetivo variam sobre o espaço de soluções.
T-norma
Família de operadores usados em lógica fuzzy para generalizar a noção de conjunção ou interseção entre graus de pertinência.
Verossimilhança
Medida de quão compatível a evidência observada é com uma hipótese assumida, frequentemente expressa como $P(E \mid H)$.
Predicado
Expressão lógica que representa uma propriedade ou relação sobre objetos.
Processamento de Linguagem Natural
Área da IA dedicada à análise, compreensão e geração de linguagem humana.
Programação em lógica
Paradigma declarativo baseado em fatos, regras e consultas.
Problema aditivo
Problema em que o custo total pode ser modelado como combinação, frequentemente soma, dos custos de subcomponentes.
Rete
Algoritmo eficiente de casamento entre fatos e condições de regras, muito usado em motores de encadeamento para a frente.
Rede semântica
Representação em grafo na qual nós indicam conceitos e arestas indicam relações entre esses conceitos.
Raciocínio não monotônico
Forma de raciocínio em que conclusões podem ser revistas diante de novas informações.
Revisão de crenças
Processo de modificar um conjunto de crenças para incorporar nova informação preservando, quando possível, a consistência e o máximo do conhecimento anterior.
Regra de Bayes
Princípio matemático usado para atualizar probabilidades quando novas evidências são observadas.
Recompensa
Sinal numérico usado em aprendizado por reforço para indicar a qualidade de uma ação ou transição.
Rede neural
Modelo composto por unidades interconectadas com pesos ajustáveis, usado para aprender padrões complexos.
Robótica
Área que estuda sistemas capazes de perceber o ambiente físico e atuar sobre ele.
SLAM
Problema de localização e mapeamento simultâneos, no qual um robô estima sua posição enquanto constrói um mapa do ambiente.
Fator de certeza
Medida heurística usada em sistemas especialistas para representar o quanto uma evidência apoia ou enfraquece uma conclusão.
Slot
Campo ou atributo de uma estrutura como um frame, destinado a armazenar valores, restrições ou referências para outras estruturas.
Solução factível
Solução que satisfaz as restrições do problema e pode ser aceita como válida.
Sistema especialista
Sistema que usa conhecimento explícito de um domínio e inferência para apoiar decisões especializadas.
Sistema de produção
Arquitetura baseada em regras, memória de trabalho e mecanismo de controle, usada para inferir conclusões ou ações.
Simulated annealing
Método de busca local que aceita temporariamente soluções piores para escapar de ótimos locais.
Subsunção
Relação lógica em que uma classe mais específica está contida em uma classe mais geral, base importante em ontologias e hierarquias conceituais.
Circunscrição
Formalismo não monotônico associado à ideia de minimizar exceções ou extensões de certos predicados para representar o que normalmente vale.
Tokenização
Processo de dividir texto em unidades menores, como palavras, subpalavras ou símbolos, para processamento computacional.
Transformer
Arquitetura neural baseada em mecanismos de atenção, central em PLN moderno e em vários modelos generativos.
Vizinhança
Conjunto de soluções consideradas próximas de uma solução atual segundo alguma operação local.
Validação cruzada
Técnica de avaliação em que os dados são particionados em várias partes para estimar desempenho de generalização de um modelo.
Viés indutivo
Preferência implícita ou explícita de um algoritmo por certos tipos de hipóteses durante o aprendizado.
Unificação
Processo de tornar expressões lógicas compatíveis por substituição adequada de variáveis.
Utilidade
Medida de preferência ou valor atribuída a resultados possíveis, usada para comparar ações em agentes de decisão.

Referências:

  1. Russell, Stuart; Norvig, Peter. Inteligência Artificial.
  2. Bratko, Ivan. Prolog Programming for Artificial Intelligence.
  3. Luger, George F. Artificial Intelligence: Structures and Strategies for Complex Problem Solving.
  4. Mitchell, Tom M. Machine Learning.
  5. Bishop, Christopher M. Pattern Recognition and Machine Learning.
  6. Nilsson, Nils J. Principles of Artificial Intelligence.
  7. Introduction to Artificial Intelligence - UC Davis
  8. An Introduction to Problem-Solving Using Search Algorithms
  9. And-Or Graph - Artificial Intelligence
  10. A Gentle Introduction to Function Optimization
  11. Stanford Encyclopedia of Philosophy - Logic and Artificial Intelligence
  12. Stanford Encyclopedia of Philosophy - Defeasible Reasoning
  13. Newell e Simon - The Logic Theory Machine: A Complex Information Processing System
  14. John McCarthy - Programs with Common Sense
  15. John McCarthy - Recursive Functions of Symbolic Expressions and Their Computation by Machine
  16. Newell e Simon - Computer Science as Empirical Inquiry: Symbols and Search
  17. Robert Kowalski - The Early Years of Logic Programming
  18. Hart, Nilsson e Raphael - A Formal Basis for the Heuristic Determination of Minimum Cost Paths
  19. Kirkpatrick, Gelatt e Vecchi - Optimization by Simulated Annealing
  20. Martelli e Montanari - Additive AND/OR Graphs
  21. Problem Decomposition - Search Methods in Artificial Intelligence
  22. Marvin Minsky - A Framework for Representing Knowledge
  23. M. Ross Quillian - Semantic Memory
  24. W3C - OWL Web Ontology Language
  25. Charles Forgy - Rete: A Fast Algorithm for the Many Pattern/Many Object Pattern Match Problem
  26. OPS5: A Rule-Based Programming System
  27. CLIPS Basic Programming Guide
  28. NASA - CLIPS: An Expert System Tool for Delivery and Training
  29. Stanford Encyclopedia of Philosophy - Non-monotonic Logic
  30. Raymond Reiter - A Logic for Default Reasoning
  31. John McCarthy - Circumscription: A Form of Non-Monotonic Reasoning
  32. Stanford Encyclopedia of Philosophy - Defeasible Reasoning
  33. Lotfi A. Zadeh - Fuzzy Sets
  34. Probabilistic Interpretations for MYCIN's Certainty Factors
  35. Stanford Encyclopedia of Philosophy - Fuzzy Logic
  36. Stanford Encyclopedia of Philosophy - Bayes' Theorem
  37. Judea Pearl - Bayesian Networks
  38. Elementary Probability and Naive Bayes Classifiers
  39. Lotfi A. Zadeh - Fuzzy Sets
  40. Stanford Encyclopedia of Philosophy - Fuzzy Logic
  41. The Concept of Fuzzy Set and Membership Function and Basic Properties of Fuzzy Set Operation
  42. IBM Research - Machine Learning
  43. IBM - The games that helped AI evolve
  44. Sutton e Barto - Reinforcement Learning: An Introduction
  45. Mnih et al. - Human-level control through deep reinforcement learning
  46. DENDRAL: A case study of the first expert system for scientific hypothesis formation
  47. Edward Shortliffe - Computer-Based Medical Consultations: MYCIN
  48. Jurafsky e Martin - Speech and Language Processing
  49. Vaswani et al. - Attention Is All You Need
  50. Probabilistic Robotics
  51. A Comprehensive Survey of Visual SLAM Algorithms