コード例 #1
0
        private bool TT_Check_All(KnowledgeBase kb, string alpha, List <string> symbols, Dictionary <string, bool> model)
        {
            Console.WriteLine(String.Join(";", symbols.ToArray()));

            if (symbols.Count == 0)
            {
                model.ToList().ForEach(x => Console.WriteLine(x.Key + ": " + x.Value));
                if (PL_true(kb, model))
                {
                    if (PL_true(alpha, model))
                    {
                        _modelCount++;
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(true);
                }
            }
            else
            {
                model.ToList().ForEach(x => Console.WriteLine(x.Key + ": " + x.Value));
                string P = symbols[0];

                symbols.RemoveAt(0);
                return(TT_Check_All(kb, alpha, new List <string>(symbols), extend(P, true, model)) && TT_Check_All(kb, alpha, new List <string>(symbols), extend(P, false, model)));
            }
        }
コード例 #2
0
        static private bool PLTrue(KnowledgeBase knowledgeBase, Dictionary <string, bool> model)
        {
            foreach (Sentence Sentence in knowledgeBase.Sentences)
            {
                List <bool>   bSymbols       = Sentence.Symbols.ConvertAll(s => model[s]);
                List <string> logicalSymbols = new List <string>(Sentence.LogicalConnectives);

                // loops through Symbols in the order of operation
                foreach (string s in LogicalConnectives.SymbolsOperationOrder)
                {
                    // set the firts occurance of the symbol to i
                    int i;
                    // will check from back to front for not statements to handel double negetives
                    while ((i = (s == "~")?logicalSymbols.LastIndexOf(s): logicalSymbols.IndexOf(s)) != -1)
                    {
                        bSymbols[i] = LogicalConnectives.Evaluate(s, bSymbols[i], bSymbols[i + 1]);

                        // remove evaluated symbols
                        bSymbols.RemoveAt(i + 1);
                        logicalSymbols.RemoveAt(i);
                    }
                }

                Debug.Assert(bSymbols.Count == 1);

                if (!bSymbols[0])
                {
                    return(false);
                }
            }
            return(true);
        }
コード例 #3
0
        public bool TT_Entails(KnowledgeBase kb, string alpha)
        {
            List <string>             Symbol = createSymbolList(kb, alpha);
            Dictionary <string, bool> model  = new Dictionary <string, bool>();

            return(TT_Check_All(kb, alpha, Symbol, model));
        }
コード例 #4
0
        static private Result TTCheckAll(KnowledgeBase knowledgeBase, string query, List <string> symbols, Dictionary <string, bool> model)
        {
            if (symbols.Count == 0)
            {
                if (PLTrue(knowledgeBase, model))
                {
                    return(new Result((model.Keys.Contains(query))? model[query]: false, count: 1));
                }
                else
                {
                    return(new Result(true));
                }
            }
            else
            {
                List <string> symbolsCopy = symbols.ConvertAll(symbol => String.Copy(symbol));
                string        first       = symbolsCopy[0];
                symbolsCopy.RemoveAt(0);

                Dictionary <string, bool> t = new Dictionary <string, bool>(model);
                Dictionary <string, bool> f = new Dictionary <string, bool>(model);

                t.Add(first, true);
                f.Add(first, false);

                Result r1 = TTCheckAll(knowledgeBase, query, symbolsCopy, t);
                Result r2 = TTCheckAll(knowledgeBase, query, symbolsCopy, f);
                return(new Result(r1.Success && r2.Success, count: r1.Count + r2.Count));
            }
        }
コード例 #5
0
        public string Ask(Symbol query, KnowledgeBase kb)
        {
            var validModels = new List <List <Symbol> >();

            var symbols = kb.Symbols.Values.ToList();

            // Determine which models are valid.
            foreach (var symbolCombination in GetAllSymbolCombinations(kb))
            {
                SetSymbolValues(symbols, symbolCombination);

                if (IsValidModel(kb, symbols))
                {
                    validModels.Add(symbols);
                }
            }

            // Query is true if the query symbol is true in ALL valid models.
            foreach (var validSymbols in validModels)
            {
                var querySymbol = validSymbols.Find(s => s.Name == query.Name);

                if (querySymbol.Value == false)
                {
                    return("NO");
                }
            }

            // Query was true in all valid models, result is true.
            return("YES: " + validModels.Count);
        }
コード例 #6
0
        static private Result BCRecursive(KnowledgeBase knowledgeBase, string target)
        {
            List <Clause> statements      = knowledgeBase.InConclusion(target);
            List <string> symbolsEntailed = new List <string>();
            List <bool>   results         = new List <bool>();

            foreach (Clause c in statements)
            {
                bool result = true;
                foreach (string s in c.Premise)
                {
                    Result r = BCRecursive(knowledgeBase, s);
                    result &= r.Success;
                    if (r.Success)
                    {
                        symbolsEntailed = r.Symbols;
                    }
                }
                results.Add(result);
                if (!symbolsEntailed.Contains(c.Conclusion))
                {
                    symbolsEntailed.Add(c.Conclusion);
                }
            }

            return(new Result(results.All(r => r) && results.Count != 0, symbols: symbolsEntailed));
        }
コード例 #7
0
ファイル: World.cs プロジェクト: LarsOL/Inference-Engine
 public World(Proposition[] Propositions, int amount_args)
 {
     Proposition[] Temp = new Proposition[Propositions.Length - 1];
     Array.Copy(Propositions, Temp, Temp.Length);
     _KnowledgeBase = new KnowledgeBase(Temp);
     _Goal          = Propositions[Propositions.Length - 1];
     Arguments      = new bool?[amount_args];
 }
コード例 #8
0
 static public Result BC(KnowledgeBase knowledgeBase, string query)
 {
     if (!knowledgeBase.IsHornClause)
     {
         throw new Exception("KnowledgeBase must be Horn clause");
     }
     return(BCRecursive(knowledgeBase, query));
 }
コード例 #9
0
        static public Result TT(KnowledgeBase knowledgeBase, string query)
        {
            Result result = TTCheckAll(knowledgeBase, query, knowledgeBase.Symbols, new Dictionary <string, bool> {
                { "", true }
            });

            if (result.Count == 0)
            {
                result.Success = false;
            }
            return(result);
        }
コード例 #10
0
        private bool IsValidModel(KnowledgeBase kb, List <Symbol> symbols)
        {
            foreach (var sentence in kb.Knowledge)
            {
                if (!sentence.IsTrueFor(symbols))
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #11
0
        public bool isPremiseInKB(String symbol)
        {
            foreach (HornClauseClass clause in KnowledgeBase.Where(s => s.GetType().Name != "HornClauseFactClass"))
            {
                List <String> temp = clause.GetPremiseSymbols();
                foreach (String str in temp)
                {
                    if (str == symbol)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
コード例 #12
0
        static private short BCRecursive(KnowledgeBase knowledgeBase, string target, List <Sentence> sentencesChecked, ref List <string> symbolsEntailed)
        {
            List <Sentence> statements = knowledgeBase.InConclusion(target);
            short           results    = 0;

            foreach (Sentence c in statements)
            {
                if (!sentencesChecked.Contains(c))
                {
                    sentencesChecked.Add(c);
                    short result = 1;
                    foreach (string s in c.Premise)
                    {
                        List <Sentence> sentencesCheckedCopy = new List <Sentence>(sentencesChecked);
                        short           r = BCRecursive(knowledgeBase, s, sentencesCheckedCopy, ref symbolsEntailed);

                        result = r;

                        if (r != 1)
                        {
                            break; // can break out of loop cause all statements must be true
                        }
                    }

                    if (!symbolsEntailed.Contains(c.Conclusion))
                    {
                        symbolsEntailed.Add(c.Conclusion);
                    }

                    if (result != 0)
                    {
                        results = result;
                    }
                    else
                    {
                        break;
                    }
                }
                else if (results == 0)
                {
                    results = -1;                    // to indicate overflow on branch so no inference can be drawn from it
                }
            }

            return(results);
        }
コード例 #13
0
        public string Ask(Symbol query, KnowledgeBase kb)
        {
            _kb   = kb;
            _path = new List <string>();

            if (kb.SymbolIsKnown(query))
            {
                return("YES: " + query.Name);
            }

            if (BackwardChain(query))
            {
                return("YES: " + PathString);
            }

            return("NO");
        }
コード例 #14
0
ファイル: Program.cs プロジェクト: ruo2012/InferenceEngine-1
        static void Main(string[] args)
        {
            string methodName = args[0];
            string filename   = args[1];

            InferenceInput input = Parser.ParseInferenceInput(filename);

            var kb = new KnowledgeBase();

            foreach (var clause in input.knowledgeClauses)
            {
                kb.Tell(clause);
            }

            kb.Ask(input.queryClause, methodName);

            Console.ReadLine();
        }
コード例 #15
0
        static public Result BC(KnowledgeBase knowledgeBase, string query)
        {
            if (!knowledgeBase.IsHornClause)
            {
                throw new Exception("KnowledgeBase must be Horn Clause");
            }
            List <string> symbolsEnailed = new List <string>();

            short result = BCRecursive(knowledgeBase, query, new List <Sentence>(), ref symbolsEnailed);

            if (result == 1)
            {
                return(new Result(true, symbols: symbolsEnailed));
            }
            else
            {
                return(new Result(false));
            }
        }
コード例 #16
0
 /// <summary>
 /// Checks if the symboo is the conclusion of an implication or fact
 /// </summary>
 /// <param name="symbol">The string you wish to look for in the KB</param>
 /// <returns>if symbol is found in as a conclusion or fact it will return the clause.
 /// If it isn't found it returns null (error code)</returns>
 public HornClauseClass isConclusionOrFact(String symbol)
 {
     foreach (HornClauseClass clause in KnowledgeBase.Where(s => s.GetType().Name == "HornClauseImplicationClass" || s.GetType().Name == "HornClauseFactClass"))
     {
         if (clause.GetType().Name == "HornClauseImplicationClass")
         {
             if (clause.GetConclusionSymbol() == symbol)
             {
                 return(clause);
             }
         }
         else if (clause.GetType().Name == "HornClauseFactClass")
         {
             if (clause.GetSymbols()[0] == symbol)
             {
                 return(clause);
             }
         }
     }
     return(null);
 }
コード例 #17
0
        private List <List <bool> > GetAllSymbolCombinations(KnowledgeBase kb)
        {
            var result = new List <List <bool> >();

            // Adopted From:
            // https://stackoverflow.com/questions/39734887/generating-all-possible-true-false-combinations
            int numVars = kb.Symbols.Count;

            for (int i = 0; i < (1 << numVars); ++i)
            {
                var combination = new List <bool>();

                for (int j = numVars - 1; j >= 0; --j)
                {
                    combination.Add((i & (1 << j)) != 0);
                }

                result.Add(combination);
            }

            return(result);
        }
コード例 #18
0
        public bool PL_true(KnowledgeBase kb, Dictionary <string, bool> model)
        {
            bool finalResult = true;

            //Console.WriteLine("new model: ----------- ");
            foreach (Clause c in kb.Clauses)
            {
                bool clauseResult = true;
                if (c.Premise == null)
                {
                    clauseResult = PL_true(c.Conclusion, model);
                    //Console.WriteLine(c.Conclusion);
                    //Console.WriteLine("result: " + clauseResult +  ", conclusion: " + PL_true(c.Conclusion, model));
                }
                else
                {
                    bool premiseIsTrue = true;
                    foreach (string symbol in c.Premise)
                    {
                        premiseIsTrue = premiseIsTrue && PL_true(symbol, model);
                        //Console.WriteLine(symbol + ": " + PL_true(symbol, model));
                    }
                    //Console.WriteLine(c.Conclusion + ": " + PL_true(c.Conclusion, model));


                    clauseResult = !(premiseIsTrue && !PL_true(c.Conclusion, model));


                    //Console.WriteLine( String.Join("&", c.Premise.ToArray())+ "=>" + c.Conclusion);
                    //Console.WriteLine("result: " + clauseResult + ", "+ String.Join(" & ", c.Premise.ToArray())+": "+ premiseIsTrue + ", conclusion: " + PL_true(c.Conclusion, model));
                }
                finalResult = finalResult & clauseResult;
            }
            Console.WriteLine("model: " + finalResult);
            return(finalResult);
        }
コード例 #19
0
        private List <string> createSymbolList(KnowledgeBase kb, string alpha)
        {
            List <string> symbolList = new List <string>();

            symbolList.Add(alpha);
            foreach (Clause c in kb.Clauses)
            {
                if (c.Premise != null)
                {
                    foreach (string s in c.Premise)
                    {
                        if (!symbolList.Contains(s))
                        {
                            symbolList.Add(s);
                        }
                    }
                }
                if (!symbolList.Contains(c.Conclusion))
                {
                    symbolList.Add(c.Conclusion);
                }
            }
            return(symbolList);
        }
コード例 #20
0
        private static bool ParseFile(string filename, ref KnowledgeBase knowledgeBase, ref string query)
        {
            // indicate if the file is complete
            bool         tell   = false;
            bool         ask    = false;
            StreamReader reader = new StreamReader(filename);

            string line;
            string ReadState = "";

            while ((line = reader.ReadLine()) != null)
            {
                // read the knowledgeBase
                if (line.Trim().Equals("TELL"))
                {
                    ReadState = "TELL";
                }

                else if (line.Trim().Equals("ASK"))
                {
                    // can only be one ask statement
                    if (!ask)
                    {
                        ReadState = "ASK";
                    }
                    else // there is already a query error in the file
                    {
                        ask = false;
                        break;
                    }
                }

                else if (ReadState.Equals("TELL"))
                {
                    tell = true;

                    // remove spaces form the line
                    line = line.Replace(" ", "");

                    // create an array of sentances
                    string[] sentences = line.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);

                    // add each sentance to the knowledge base
                    foreach (string sentence in sentences)
                    {
                        CreateSentence(ref knowledgeBase, sentence);
                    }
                }

                else if (ReadState.Equals("ASK"))
                {
                    if (line != "")
                    {
                        if (!ask)
                        {
                            query = line.Trim();
                            ask   = true;
                        }
                        else // there is already a query error in the file
                        {
                            ask = false;
                            break;
                        }
                    }
                }
            }


            reader.Close();

            // ensure that query is in the knowledge base and there is only one ask statment
            return(ask && tell);
        }
コード例 #21
0
 static public Result DPLLSatisfiable(KnowledgeBase knowledgeBase, string query)
 {
     return(DPLL(knowledgeBase.Sentences, knowledgeBase.Symbols, new Dictionary <string, bool>()));
 }
コード例 #22
0
        private static void CreateSentence(ref KnowledgeBase knowledgeBase, string sentence)
        {
            // handle parentheses
            if (sentence.Contains('(') || sentence.Contains(')'))
            {
                Stack <int> parenthesesIndex = new Stack <int>();

                for (int i = 0; i < sentence.Length; i++)
                {
                    if (sentence[i].Equals('('))
                    {
                        parenthesesIndex.Push(i);
                    }
                    else if (sentence[i].Equals(')'))
                    {
                        if (parenthesesIndex.Count == 0)
                        {
                            throw new Exception("Parentheses in file do not match");
                        }

                        // copy the inner Sentence in the sentace
                        string inbedSentence = sentence.Substring(parenthesesIndex.Peek() + 1, i - parenthesesIndex.Peek() - 1);

                        // create a unique variable to replace the sentance with
                        string replacementVar = string.Format("*{0}", replacementVarIndex++);

                        // replace the inner Sentence with a variable
                        sentence = sentence.Replace(string.Format("({0})", inbedSentence), replacementVar);

                        // set the index back to the where the previous parentheses was
                        i = parenthesesIndex.Peek();

                        // add a new sentance to the knoledge base where the variable is equivilent to the replacement variable
                        CreateSentence(ref knowledgeBase, string.Format("{0}<=>{1}", inbedSentence, replacementVar));

                        parenthesesIndex.Pop();
                    }
                }

                if (parenthesesIndex.Count != 0)
                {
                    throw new Exception("Parentheses in file do not match");
                }
            }

            List <string> symbols = new List <string> {
                sentence
            };
            List <string> logic = new List <string>();

            foreach (string connector in LogicalConnectives.Symbols)
            {
                for (int i = 0; i < symbols.Count; i++)
                {
                    if (symbols[i].Contains(connector))
                    {
                        logic.Insert(i, connector);
                        int index = symbols[i].IndexOf(connector);

                        symbols.Insert(i + 1, symbols[i].Substring(index + connector.Length));
                        symbols[i] = symbols[i].Substring(0, index);
                    }
                }
            }

            for (int i = 0; i < symbols.Count; i++)
            {
                if (symbols[i] == "" && logic[i] != "~")
                {
                    throw new Exception("logical connectives missused");
                }
            }

            knowledgeBase.AddStatement(new Sentence(symbols, logic));
        }
コード例 #23
0
        /*
         * Reads Problem File
         * @Param filename - string that gives name of file to read from
         * @Param solver - string that tells reader what type of engine is being used. Changes
         *      output if more advanced algorithms used.
         */
        public static bool ReadProblem(string filename, string solver)
        {
            List <string> text = new List <string>();

            //tries to read problem file, if it can't returns false
            try
            {
                StreamReader reader = File.OpenText(filename);
                for (int i = 0; i < 4; i++)
                {
                    text.Add(reader.ReadLine());
                }
                reader.Close();
            }
            catch
            {
                Console.WriteLine("Error: Could not read file");
                return(false);
            }
            string[] knowledge = text[1].Split(';');
            knowledge = knowledge.Take(knowledge.Count() - 1).ToArray();
            List <Clause> clauses = new List <Clause>();

            // If basic checking method
            if (solver != "GTT" || solver != "DPLL")
            {
                foreach (string s in knowledge)
                {
                    if (s.Contains("=>"))
                    {
                        List <string> premiseSymbols = new List <string>();
                        int           index          = s.IndexOf("=>");
                        string        premise        = s.Substring(0, index);
                        string        conclusion     = s.Substring(index + 2);
                        conclusion = conclusion.Trim();
                        string[] splitPremise = { "" };
                        if (premise.Contains("&"))
                        {
                            splitPremise = premise.Split('&');
                        }
                        else
                        {
                            splitPremise[0] = premise;
                        }
                        foreach (string symbol in splitPremise)
                        {
                            string trim = symbol.Trim();
                            premiseSymbols.Add(trim);
                        }
                        clauses.Add(new Clause(premiseSymbols, conclusion));
                    }
                    else
                    {
                        string conclusion = s.Trim();
                        clauses.Add(new Clause(conclusion));
                    }
                }
                _query = text[3];
                _kb    = new KnowledgeBase(clauses);


                return(true);
            }
            // if solving method more advanced clauses
            else
            {
                List <LogicalExpression> kb = new List <LogicalExpression>();
                foreach (string s in knowledge)
                {
                    LogicalExpression exp = new LogicalExpression(s);
                    //exp.printInfo();
                    kb.Add(exp);
                }

                _akb   = new AdvancedKnowledgeBase(kb);
                _query = text[3];
                return(true);
            }
        }
コード例 #24
0
        static public Result FC(KnowledgeBase knowledgeBase, string query)
        {
            if (!knowledgeBase.IsHornClause)
            {
                throw new Exception("KnowledgeBase must be Horn Clause");
            }
            // count <- a table where count[c] is the number of symbols in c's premis
            Dictionary <Sentence, int> count = new Dictionary <Sentence, int>();

            foreach (Sentence c in knowledgeBase.Sentences)
            {
                count.Add(c, c.Premise.Count);
            }

            // inferred <- a table, where inferred[s] is initially false for all symbols
            Dictionary <string, bool> inferred = new Dictionary <string, bool>();

            foreach (string s in knowledgeBase.Symbols)
            {
                inferred.Add(s, false);
            }

            // agenda <- a queue of symbols, initially symbols known to be true in KB
            Queue <string> agenda = knowledgeBase.InitiallyTrue();

            List <string> symbolsEntailed = new List <string>();

            // while agenda is not empty
            while (agenda.Count != 0)
            {
                // p <- pop(agenda)
                string p = agenda.Dequeue();
                // store the symbols entailed during FC
                if (!symbolsEntailed.Contains(p))
                {
                    symbolsEntailed.Add(p);
                }
                // if p=q then return true
                if (p == query)
                {
                    return(new Result(true, symbols: symbolsEntailed));
                }
                // if inferred[p] = false then
                if (!inferred[p])
                {
                    // inferred[p] <- true
                    inferred[p] = true;
                    // for each Sentence c in KB where p is in c.Premise do
                    foreach (Sentence c in knowledgeBase.InPremise(p))
                    {
                        // decrement count[c] by the items frequency in list
                        count[c] -= c.Premise.FindAll(i => i.Equals(p)).Count;
                        // if count[c] = 0 than add c.Conclusion to agenda
                        if (count[c] == 0)
                        {
                            agenda.Enqueue(c.Conclusion);
                        }
                    }
                }
            }

            return(new Result(false));
        }
コード例 #25
0
 /*
  * Constructor for Forward Chaining Algorithm
  * @param kb - a knowledge base
  * @param Query - A string for the query to ask
  */
 public ForwardChaining(KnowledgeBase kb, string Query)
 {
     _knowledgeBase = kb;
     _query         = Query;
 }
コード例 #26
0
ファイル: World.cs プロジェクト: LarsOL/Inference-Engine
 /*
  * public bool[] Arguments
  * {
  *  get
  *  {
  *      return Arguments;
  *  }
  *  set
  *  {
  *    //  if (Arguments == null || value.Length != Arguments.Length)
  *    //      throw new System.ArgumentException("Wrong size arguments array");
  *      Arguments = value;
  *  }
  * } */
 public World(KnowledgeBase KnowledgeBase, Proposition Goal)
 {
     _KnowledgeBase = KnowledgeBase;
     _Goal          = Goal;
 }
コード例 #27
0
 public View(ref KnowledgeBase kb)
 {
     _kb = kb;
 }
コード例 #28
0
 /*
  * Constructor for the TruthTable Engine
  * @param kb - A KnowledgeBase which contains the
  * @param query - A string containing the question to determine
  */
 public TruthTable(KnowledgeBase kb, string query)
 {
     _knowledgeBase = kb;
     _query         = query;
 }
コード例 #29
0
        static int Main(string[] args)
        {
            if (args.Count() != 2)
            {
                Console.WriteLine("ERROR: incorrect arguments");
#if DEBUG
                Console.ReadLine(); //stops the console from closing
#endif
                return(1);
            }

            string method   = args[0];
            string filename = args[1];

            KnowledgeBase knowledgeBase = new KnowledgeBase();
            string        query         = "";

            try
            {
                if (!ParseFile(filename, ref knowledgeBase, ref query))
                {
                    Console.WriteLine("ERROR: incorrect file format");
#if DEBUG
                    Console.ReadLine(); //stops the console from closing
#endif
                    return(2);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: {0}", ex.Message);
#if DEBUG
                Console.ReadLine(); //stops the console from closing
#endif
                return(3);
            }

            Result result;
            try
            {
                switch (method)
                {
                case "TT":
                    result = TruthTableChecking.TT(knowledgeBase, query);
                    break;

                case "FC":
                    result = ForwardChaining.FC(knowledgeBase, query);
                    break;

                case "BC":
                    result = BackwardChaining.BC(knowledgeBase, query);
                    break;

                default:
                    Console.WriteLine("ERROR: invalid method provided");
#if DEBUG
                    Console.ReadLine();     //stops the console from closing
#endif
                    return(4);
                }
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("ERROR: {0}", ex.Message);
#if DEBUG
                Console.ReadLine(); //stops the console from closing
#endif
                return(5);
            }

            if (result.Success)
            {
                string second;
                if (result.Symbols is null)
                {
                    second = result.Count.ToString();
                }
                else
                {
                    second = string.Join(", ", result.Symbols);
                }
                Console.WriteLine("YES: {0}", second);
            }
            else
            {
                Console.WriteLine("NO");
            }
#if DEBUG
            Console.ReadLine(); //stops the console from closing
#endif
            return(0);
        }
コード例 #30
0
        public string Ask(Symbol query, KnowledgeBase kb)
        {
            _kb = kb;
            // count = Dictionary<string, int>
            // Number of premises for each sentence
            var count = new Dictionary <Sentence, int>();

            foreach (var sentence in kb.Knowledge)
            {
                count[sentence] = sentence.LeftSide.Count;
            }

            // inferred = Dictionary<string, bool>
            // Whether each symbol has been inferred yet
            var inferred = new Dictionary <string, bool>();

            foreach (var symbol in kb.Symbols)
            {
                inferred[symbol.Key] = false;
            }

            // agenda = List<Symbol>
            // The inferred symbols. Begins with "known" symbols
            var agenda = new Stack <Symbol>();

            foreach (var symbol in kb.Symbols)
            {
                if (kb.SymbolIsKnown(symbol.Value))
                {
                    agenda.Push(symbol.Value);
                }
            }

            string path = "";

            foreach (var symbol in agenda)
            {
                path += symbol.Name + " ";
            }

            while (agenda.Count > 0)
            {
                var premise = agenda.Pop();

                if (!inferred[premise.Name])
                {
                    inferred[premise.Name] = true;

                    foreach (var sentence in GetSentencesContaining(premise))
                    {
                        --count[sentence];

                        if (count[sentence] == 0)
                        {
                            if (sentence.Implication.Name == query.Name)
                            {
                                return("YES: " + path + query.Name);
                            }

                            agenda.Push(sentence.Implication);

                            path += sentence.Implication.Name + " ";
                        }
                    }
                }
            }

            return(query.Name + ": NO");
        }