Simple Inference Engine in C++

artikel ini pertama kali dipublikasikan pada situs gamedevid.org pada tanggal 8 Januari 2007.



beberapa waktu lalu gw lagi nyari-nyari referensi tentang mesin inferensi di http://www.sourceforge.net dan nemu contoh implementasi mesin inferensi yang cukup sederhana dalam bahasa Ruby -> SIE (Simple Inference Engine). karena gw lagi ngutak-atik irrlicht yang notabene pake C++ akhirnya gw port ke dalam C++ dengan memanfaatkan STL dan irrXML 1.2.mesin inferensi dan sistem pakarmesin inferensi merupakan elemen inti dari sistem pengambilan keputusan berbasis kaidah dalam intelejensia buatan. sistem pengambilan keputusan sendiri merupakan salah satu instans dari sistem berbasis pengetahuan (knowledge-based system) yang istilah populernya adalah sistem pakar (expert system).sistem pakar punya arsitektur umum yaitu terdiri dari 4 komponen :- knowledge base, atau mungkin lebih tepatnya rule-base
- working memory
- mesin inferensi
- user interface

rulebase, dalam bahasa indonesia berarti basis kaidah. isinya koleksi kaidah yang bisa di-inferensikan. setiap kaidah umumnya terdiri dari 2 bagian yaitu anteseden dan konsekuen dan dideskripsikan sebagai kaidah if-then seperti berikut :

IF anteseden THEN konsekuen

anteseden sederhananya adalah ekspresi boolean terhadap kebenaran suatu fakta. evaluasi kebenaran suatu fakta menggunakan acuan fakta-fakta yang ‘diketahui’ dalam ‘working memory’

konsekuen adalah aksi-aksi yang dieksekusi jika kondisi dalam anteseden terpenuhi. aksi yang dapat dilakukan bisa berupa penalaran fakta baru (fact assertion), pembantahan/penghapusan fakta dari working memory (fact retraction), ataupun modifikasi terhadap fakta yang ada

working memory, merupakan koleksi fakta yang didefinisikan sejak awal, atau dibuat secara run-time dari proses inferensi terhadap knowledge base.

mesin inferensi, mesin ini yang memproses kumpulan fakta dan kumpulan kaidah sehingga dibangkitkan fakta-fakta baru. kondisi berhenti mesin inferensi bisa saja ketika fakta tertentu yang menjadi tujuan(goal) muncul, ataupun tidak ada lagi aturan yang bisa dieksekusi (fired) berdasarkan fakta yang ada. untuk melakukan inferensi ada dua cara :

- inferensi maju (forward chaining), algoritma ini dimulai dengan
mencari kaidah yang sesuai dengan fakta yang ‘diketahui’.
kaidah yang dievaluasi akan menghasilkan fakta baru yang selanjut
nya akan menyebabkan kaidah lainnya untuk dievaluasi. algoritma
ini akan berhenti jika tidak ada lagi fakta yang memenuhi kaidah
dalam basis kaidah.

- inferensi mundur (backward chaining), algoritma ini merupakan
sistem pembuktian teorem (theorem proving). cara kerja algoritma
ini dimulai dengan fakta yang ingin dibuktikan kebenarannya,
lalu kaidah-kaidah yang ‘dicurigai’ akan membuktikan fakta tsb.
akan dievaluasi. algoritma ini akan berhenti jika fakta yang menjadi
goal berhasil dibuktikan atau tidak berhasil dibuktikan.

user interface, antarmuka untuk interaksi dengan pengguna. misalnya dalam kasus sistem pakar jaman dulu, antarmukanya dialog [i]terminal-like[/i] antara user(manusia) dengan ‘pakar’

Representasi Pengetahuan
fakta bisa didefinisikan sebagai suatu simbol (string?) yang punya nilai kebenaran (boolean?). simbol bisa jadi berupa suatu term/’nama’, proposisi dalam logika orde pertama (First Order Logic) seperti dalam prolog, sebuah pasangan (2-tuple) , atau triple OAV (object-attribute-value)<nama_objek,nama_atribut,nilai_atribut>, jaringan semantik (simbol dan relasi {is-a, part-of, has, de el el.}), atau berupa frame yaitu gabungan triple OAV ke dalam sistem slot, jadi setiap objek punya koleksi slot yang merupakan pasangan <attribute,value>.

mesin inferensi yang gw bikin pake representasi pasangan <attribute,value> dengan operasi evaluasinya hanya ’sama dengan’ (untuk atribut <a,v> maksudnya jadi apakah variabel A nilainya sama dengan V bernilai true atau tidak).

gile, teorinya panjang juga ya..? udah lah, segini aja. kalo yang mo penjelasan lebih lanjut, baca buku tentang AI aja

Time to code
contoh file masukan dalam XML

<knowledgebase></knowledgebase>
<!-- contoh goal -->
 <goal></goal>
  <attribute></attribute>type.disease
  <text></text>Based on rudimentary knowledge, I believe the child has type.disease     
 
<!-- contoh kaidah -->
 <rules></rules>
  <rule></rule>
   <name></name>1
   <conditions></conditions>
    <condition></condition>
     <attribute></attribute>active.temp.over.101
     <value></value>yes     
 
   <actions></actions>
    <action></action>
     <attribute></attribute>fever
     <value></value>yes     
 
<!-- contoh pertanyaan -->
 <questions></questions>
  <question></question>
   <attribute></attribute>squeaky.breath
   <text></text>Does the child squeake as he breaths?
   <response></response>yes
   <response></response>no

Knowledge Representation
representasi pengetahuannya pake model pair

class CKnowledgeAV
{
   public:
	   CKnowledgeAV();
	   CKnowledgeAV( string Name, string Value );
	   ~CKnowledgeAV();     
 
	   string getValue();
	   void setValue(string Value);     
 
	   string getName();
	   string toString();     
 
   protected:
	string name;
	string value;
};

Kaidah dan Pertanyaan
kelas kaidah

typedef map<string,></string,> knowledgebase;
typedef map<string,></string,>::iterator kb_iterator;     
 
class CQuestion;
class CRule
{
public:
	CRule(string Name);
	~CRule();
	void addCondition(CKnowledgeAV* cond);
	void addAction(CKnowledgeAV* act);
	string toString() ;
	string getName();
	bool isActive();
	void setActive(bool bValue);
	bool deactivate();     
 
	int getConditionCount();
	bool isConditionMatch(knowledgebase knowledge);
	bool isConditionSatisfied(knowledgebase knowledge);
	bool isResolvable(map<string,></string,> questions );
	vector<string></string> getConditionAttributes();     
 
	void OnRuleFire(knowledgebase * knowledge);     
 
	knowledgebase getConditions();
	knowledgebase getActions();     
 
protected:
	string    name;
	bool	active;
           knowledgebase condition; //antecedent
	knowledgebase action; //consequent
};

kelas pertanyaan di-sekip aja..

Mesin Inferensi
kelas mesin inferensi, di-embed ke XML Parser

//modification from simple inference engine in ruby
class CXMLRuleReader
{
	public:
		CXMLRuleReader(const char * filename);
		~CXMLRuleReader();
		void parse();
		ie_state run();
		void setQuestionHandler(IQuestionHandler* handler) ;
		ie_state getStatus();     
 
protected:
		map<string,></string,> rules;
		map<string,></string,> facts;
		map<string,></string,> questions;
		IQuestionHandler* qHandler;     
 
		ie_state status;
		CRule* current_rule;
		CQuestion* current_question;
		string fact_attr, fact_val;
		string q_attr;//needed for consult to user     
 
		string goal_attr;
		string goal_text;     
 
		IrrXMLReader* m_xml;     
 
		//control to continue inference process
		bool isGoalKnown();
		bool isFactKnown(string fact_attr);
		bool isQuestionExists(string fact_attr);
		CQuestion* getQuestion(string attr);
		void consult(string attr);
};

algoritma inferensi

ie_state
CXMLRuleReader::run()
{
	bool didsomething = false;
	map<string,></string,>::iterator pos;
	int active_rule_count = rules.size();
	status = IE_MORE;
	while ((active_rule_count &gt; 0) &amp;&amp; (status == IE_MORE))
	for (pos = rules.begin(); pos != rules.end(); ++pos){
		CRule* r = pos-&gt;second;
		if ( r-&gt;isActive() ){
			if ( facts.size() &gt; 0 ){
				//printFactsKnown();
			} //if     
 
				//try to resolve current rule
				vector<string></string> rule_conds = r-&gt;getConditionAttributes();
				bool rule_resolvable = true;
				for (int i = 0; i<rule_conds.size();></rule_conds.size();>					if ( !isFactKnown( rule_conds[i] ) )
						if ( isQuestionExists( rule_conds[i]) )
							consult( rule_conds[i] );
						else{
							rule_resolvable = false;
							break;
						}
				} //for
				if ( !rule_resolvable ){
					//continue to next rule
					continue;
				} //if     
 
				//check if rule can be fired
				if ( r-&gt;isConditionSatisfied( facts ) ){
					r-&gt;OnRuleFire( &amp;facts );
					r-&gt;deactivate();
					active_rule_count--;
					//filter out non fireable rules
					//forall rule
					for (map<string,></string,>::iterator p = rules.begin(); p != rules.end(); ++p){
						CRule* rule = p-&gt;second;
						knowledgebase kb = rule-&gt;getConditions();
						//forall condition in rule that exist in knowledge base
						for (kb_iterator kpos = kb.begin(); kpos != kb.end(); ++kpos){
							//if attribute known and doesnt satisfied then deactivate rule
							CKnowledgeAV* f = kpos-&gt;second;
							if ( isFactKnown(kpos-&gt;first) ){
								if ( f-&gt;getValue() != facts[kpos-&gt;first]-&gt;getValue() ){
								r-&gt;deactivate();
									break;
								} //if
							} //if
						} //for     
 
					} //for
				} //if     
 
				if ( isGoalKnown() ){
					string tmpresult = goal_text;
					CKnowledgeAV* fact = facts[goal_attr];
					tmpresult = tmpresult.replace(tmpresult.find(goal_attr), goal_attr.length(), fact-&gt;getValue());
					printFactsKnown();
					status = IE_COMPLETE;
					return status;
				} //if     
 
		} //if r.isactive
	} //for     
 
	//no more rules
	return IE_COMPLETE;
}

main program

int main(int argc, char *argv[])
{
	CXMLRuleReader* rules = new CXMLRuleReader(argv[1]);
	rules-&gt;parse();
	IQuestionHandler* handler = new CQuestionConsole();
	rules-&gt;setQuestionHandler( handler );
	rules-&gt;run();     
 
	delete rules;
	delete handler;
	return 0;
}

1 Response to “Simple Inference Engine in C++”


  1. 1 Supono Jun 5th, 2007 at 9:46 am

    Thx, ilmunya, smoga bermanfaat, terutama bagi saya yang sedang yari bahan-bahan tentang AI

Leave a Reply




Kron terbaru

Disclaimer

blog ini merupakan blog pribadi. Tulisan yang dipublikasikan merupakan pendapat berdasarkan pengalaman pribadi penulis. dengan membaca tulisan yang ada di sini penulis dilepaskan dari tanggung-jawab terhadap segala kesan, kerusakan, dan keburukan lainnya setelah membaca blog ini. jika ingin mengutip, silakan sertakan link yang merujuk ke blog ini. Tulisan di blog ini dibuat berdasarkan kapasitas penulis sebagai individu.

Perihal

Nama : Peb Ruswono Aryan
Sebutan : Peb, Pebbie, pe-e-be (peb dieja per huruf)
Kelamin : Male
Tahun Lahir : 1986
Pekerjaan : Tukang Pijat... Keyboard laptop ;;)
Hobi : tidur, minum susu
Olah raga : Wushu, Renang
Habitat : Lab GAIB Informatika ITB, RadioKampus ITB, codena.co.id

lembaran lain

Cari

 

April 2007
S M T W T F S
    May »
1234567
891011121314
15161718192021
22232425262728
2930  
  • about me

  • Blogroll

  • Digital Mark Reader (DMR)

  • GameDevId

  • Inside ITB

  • reklame