Reflexão sobre o primeiro experimento

Ao contrário do que ocorreu no applet visto na aula, a execução das regras não foi interrompida quando a informação que queríamos descobrir (a marca do carro) foi encontrada. O motor de inferência continuou encontrando a mesma informação diversas vezes, porque sempre havia regras que podiam ser disparadas com os objetos da base de objetos.

Diversas correções podem ser feitas para eliminar este "problema". Uma das alternativas seria tornar a pré-condição das regras que estão sendo disparadas falsa, para que elas não voltem a entrar no conjunto de conflito. Desta forma, poderíamos alterar, por exemplo, a regra Automovel para que a mesma só dispare quando a informação que ela está querendo encontrar ainda não existir:

rule Automovel {
  declarations
    aula.Transporte t;
  preconditions
    t.getNumeroRodas() == 4;
    t.getMotor();
    t.getTipoTransporte() == null;
  actions
    t.setTipoTransporte("automovel");
    modified(t);
}

As outras regras poderiam ser modificadas de maneira similar.

Uma outra alternativa para se falsificar as pré-condições das regras seria remover o objeto da base assim que a informação que se deseja obter dele for conseguida. Por exemplo, a regra CarroEsporte poderia ser reescrita da seguinte forma:

rule CarroEsporte {
  declarations
    aula.Transporte t;
  preconditions
    t.getTipoTransporte() != null;
    t.getTipoTransporte().equals("automovel");
    t.getNumeroPortas() == 2;
    t.getTamanho() == 1;
  actions
    t.setMarca("Carro Esporte");
    retract(t);
}

Além de falsificar as pré-condições, existe ainda uma outra forma de se resolver o problema da mesma regra ser disparada mais de uma vez. Utilizando uma estratégia de resolução de conflitos de modo que cada regra só seja disparada uma única vez, este problema pode ser resolvido. O programa exemplo, poderia ser reescrito para implementar a política de ordenamento de regras OneShot, com alterações mínimas:

import jeops.engine.KnowledgeBase;
import jeops.engine.OneShotRuleSorter;

/**
 * Classe utilitária usada na entrada de dados via
 * teclado pelo usuário.
 *
 * @author Carlos Figueira Filho (csff@di.ufpe.br)
 */
public class ProgTransporte {
	
	/**
	 * Método inicial da classe.
	 *
	 * @param args argumentos de linha de comando. Não é necessário
	 *          nenhum.
	 */
	public static void main(String[] args) {

		KnowledgeBase kb = new KnowledgeBase("transportes.rules", new OneShotRuleSorter());

		int numeroPortas = 2;
		int numeroRodas = 4;
		int tamanho = 1;  // pequeno
		boolean temMotor = true;
		Transporte t = new Transporte(temMotor, numeroPortas, numeroRodas, tamanho);
		kb.assert(t);
		kb.run();
		System.out.println("Tipo do transporte: " + t.getTipoTransporte());
		System.out.println("Marca do transporte: " + t.getMarca());

	}
}