//Determine sentence logic based on given model public bool isTrue(sentence s) { if (!s.isAtomicSentence() && s.Children.Count == 0) { s.constructChildren(); } if (s.isAtomicSentence()) { foreach (cell c in m) { if (s.Symbols[0].getSymbol == c.Symbol.getSymbol) { s.BooleanValue = c.BooleanValue; } } } if (s.Children.Count == 2) { if (s.Connectives[s.Connectives.Count - 1].toString == "&") { return(isTrue(s.Children[0]) && isTrue(s.Children[1])); } else { return(!(isTrue(s.Children[0]) && !isTrue(s.Children[1]))); } } return(s.BooleanValue); }
//Construct simpler sentences public void constructChildren() { if ((symbols.Count > 1) && (connectives.Count > 0)) { List <propositionalSymbol> childSymbols = new List <propositionalSymbol>(); List <connective> childConnectives = new List <connective>(); sentence left; sentence right; if ((symbols.Count == 2) && (connectives.Count == 1)) { left = new sentence(symbols[0]); right = new sentence(symbols[1]); } else { right = new sentence(symbols[symbols.Count - 1]); childConnectives = connectives.ToList(); childConnectives.RemoveAt(childConnectives.Count - 1); childSymbols = symbols.ToList(); childSymbols.RemoveAt(childSymbols.Count - 1); left = new sentence(childSymbols, childConnectives); connectives = connectives.GetRange(connectives.Count - 1, 1); //symbols = symbols.GetRange(symbols.Count - 1, 1); } this.children.Add(left); this.children.Add(right); } }
//Check all models based on given symbols public void CheckAll(knowledgeBase kB, sentence query, List <propositionalSymbol> symbols, model model) { if (symbols.Count == 0) { if (model.isTrue(kB)) { if (model.isTrue(query)) { modelEntailments++; } //return model.isTrue(query); } //else return true; } else { propositionalSymbol s = new propositionalSymbol(symbols.First()); //rest of the symbols List <propositionalSymbol> rest = new List <propositionalSymbol>(); rest.AddRange(symbols); rest.RemoveAt(0); //Initialize model for true branch model mleft = new model(); mleft.getCellList.AddRange(model.getCellList); mleft.getCellList.Add(new cell(s, true)); //Initialize model for false branch model mright = new model(); mright.getCellList.AddRange(model.getCellList); mright.getCellList.Add(new cell(s, false)); //Recursive call CheckAll(kB, query, rest, mleft); CheckAll(kB, query, rest, mright); } }
//Backward chaining algorithm public bool BCEntails(knowledgeBase kB, sentence query) { //Initialize list for storing implication clause only List <sentence> implication = new List <sentence>(); int factsCount; //Add query to open list if (!open.Any(x => x.getSymbol == query.Symbols.First().getSymbol)) { open.Add(query.Symbols.First()); } //Return false if the query is not an atomic sentence if (!query.isAtomicSentence()) { return(false); } //Construct simpler sentences in each KB sentences and add atomic sentences to known facts list foreach (sentence s in kB.Sentences) { if (!s.isAtomicSentence()) { if (s.Children.Count == 0) { s.constructChildren(); } implication.Add(s); } else { if (!facts.Any(x => x.getSymbol == s.Symbols.First().getSymbol)) { facts.Add(s.Symbols.First()); } } } //If the query is a known fact in KB if (facts.Any(x => x.getSymbol == query.Symbols.First().getSymbol)) { trace.Add(query.Symbols.First()); return(true); } //Return false if the query is not a conclusion of any of KB sentences if (!implication.Any(x => x.Children.Last().Symbols.First().getSymbol == query.Symbols.First().getSymbol)) { return(false); } //Loop through KB foreach (sentence s in implication) { //Check if query match any conclusions in KB if (s.Children.Last().Symbols.Any(x => x.getSymbol == query.Symbols.First().getSymbol)) { //Check whether if conjunction premise consists of only one single atomic sentence if (s.Children.First().isAtomicSentence()) { //Check if if (!facts.Any(x => x.getSymbol == s.Children.First().Symbols.First().getSymbol)) { if (!open.Any(x => x.getSymbol == s.Children.First().Symbols.First().getSymbol)) { open.Add(s.Children.First().Symbols.First()); } } else { //Check for duplication if (!trace.Any(x => x.getSymbol == s.Children.First().Symbols.First().getSymbol)) { trace.Add(s.Children.First().Symbols.First()); } trace.Add(query.Symbols.First()); facts.Add(query.Symbols.First()); open.RemoveAll(x => x.getSymbol == query.Symbols.First().getSymbol); } } else { factsCount = 0; foreach (propositionalSymbol p in s.Children.First().Symbols) { //Check if symbol is still yet to be known if (open.Any(x => x.getSymbol == p.getSymbol)) { agenda.Enqueue(p); continue; } //Check if each symbol in conjunction premise is a known fact if (facts.Any(x => x.getSymbol == p.getSymbol)) { if (!trace.Any(x => x.getSymbol == p.getSymbol)) { trace.Add(p); } factsCount++; } //Check if conjunction premise fully consists of known facts if (factsCount == s.Children.First().Symbols.Count) { facts.Add(s.Children.Last().Symbols.First()); trace.Add(s.Children.Last().Symbols.First()); open.RemoveAll(x => x.getSymbol == s.Children.Last().Symbols.First().getSymbol); } //Check if symbol is already inferred if (!trace.Any(x => x.getSymbol == p.getSymbol)) { open.Add(p); agenda.Enqueue(p); } } } } } //Make recursive call as long as there is more to expand in the agenda or open list if (agenda.Count != 0) { return(BCEntails(kB, new sentence(agenda.Dequeue()))); } else { if (open.Count == 0) { return(true); } else { sentence openPullFirst = new sentence(open.First()); open.Remove(open.First()); return(BCEntails(kB, openPullFirst)); } } }
//Populate data from text file public void populateData() { int counter = 0; Regex regex = new Regex("[a-zA-Z0-9]"); while ((line = file.ReadLine()) != null) { if (counter == 0) { if (line.ToUpper() == "TELL") { counter++; continue; } else { break; } } if (counter == 1) { sentences = line.TrimEnd(';').Split(';'); foreach (string s in sentences) { KB.Sentences.Add(new sentence(s)); } } if (counter == 2) { if (line.ToUpper() == "ASK") { counter++; continue; } else { break; } } if (counter == 3) { Query = new sentence(line.TrimEnd(';')); } counter++; } //Extract propositional symbols from KB foreach (sentence s in KB.Sentences) { foreach (propositionalSymbol p in s.Symbols) { if (!propositionalSymbols.Any(x => x.getSymbol == p.getSymbol)) { propositionalSymbols.Add(p); } } } //Extract propositional symbols from alpha foreach (propositionalSymbol p in query.Symbols) { if (!propositionalSymbols.Any(x => x.getSymbol == p.getSymbol)) { propositionalSymbols.Add(p); } } propositionalSymbols = propositionalSymbols.OrderBy(p => p.getSymbol).ToList(); }
//Forward chaining algorithm public bool FCEntails(knowledgeBase kB, sentence query) { Dictionary <sentence, int> count = new Dictionary <sentence, int>(); Queue <propositionalSymbol> agenda = new Queue <propositionalSymbol>(); propositionalSymbol p; List <sentence> hornClause = new List <sentence>(); //Construct simpler sentences in each KB sentences and allocate KB atomic sentences into agenda foreach (sentence s in kB.Sentences) { if (!s.isAtomicSentence()) { s.constructChildren(); } else { agenda.Enqueue(s.Symbols.Last()); } } //Allocate horn clause list from KB foreach (sentence s in kB.Sentences) { if (s.isImplicationClause()) { hornClause.Add(s); } } //Count number of symbols on conjunction side foreach (sentence s in hornClause) { count.Add(s, s.Children.First().Symbols.Count); } while (agenda.Count != 0) { p = agenda.Dequeue(); if (!InferredSymbols.Contains(p)) { inferred.Add(p); foreach (sentence s in hornClause) { if (s.Children.First().Symbols.Any(x => x.getSymbol == p.getSymbol)) { count[s]--; if (count[s] == 0) { if (s.Symbols.Last().getSymbol == query.Symbols.First().getSymbol) { inferred.Add(s.Symbols.Last()); return(true); } agenda.Enqueue(s.Symbols.Last()); } } } } } return(false); }
//Check entailment of alpha from KB public void Entails(knowledgeBase kB, sentence query, List <propositionalSymbol> symbols) { CheckAll(kB, query, symbols, new model()); }