/// <summary> /// Since this clause is full of disjunctions, might as well flatten them /// </summary> private void Flatten() { bool anyChanges = true; while (anyChanges) { anyChanges = false; BlockIterator.TerminableForEach(RootBlock, (currentBlock) => { if (currentBlock.ContentType == ContentType.Nested) { Block next = currentBlock.NextBlock, current = currentBlock.Isolate(true).GetContent() as Block; anyChanges = true; next.ExtendFront(current); if (currentBlock.Equals(RootBlock)) { RootBlock = current; } return(false); } return(true); }); } }
public HornClauses(List <Block> clauses) : this() { foreach (var clause in clauses) { if (clause.NextBlock == clause && clause.PreviousBlock == clause) { Facts.Add(clause.GetContent(true).ToString()); continue; } // safe against nested symbols inside clause or multiple clauses pointing at 1 symbol var symbol = clause.PreviousBlock.GetContent(true).ToString(); var unvisited = new List <Block> { clause }; if (!Implications.ContainsKey(symbol)) { Implications.Add(symbol, new List <List <string> >()); } // if a horn clause is pointing at the same symbol as some other horn clauses, // add current clause's requirements to a new list instead of combining them together Implications[symbol].Add(new List <string>()); // recursion using while loop, flatten down all nested symbols (if any) // as well as pushing clause's requirements for future reference while (unvisited.Count != 0) { BlockIterator.TerminableForEach(unvisited[0], (block) => { switch (block.ContentType) { case ContentType.Logic: if ((block.GetContent() as PropositionalLogic).IsImplication) { return(false); } break; case ContentType.Normal: Implications[symbol].Last().Add(block.GetContent(true).ToString()); break; case ContentType.Nested: unvisited.Add(block.GetContent() as Block); break; } return(true); }); unvisited.RemoveAt(0); } } }
/// <summary> /// Remove any symbols inside clause, guarantee to also remove its trailing connective. /// <para>Eg: a||b||c into b||c if removing a or a||c if removing b</para> /// </summary> /// <param name="clauses"></param> /// <param name="symbol"></param> /// <returns></returns> private List <Block> RemoveSymbol(List <Block> clauses, Block symbol, bool newList = true) { // must specify a fresh copy on demand here because blocks are also objects // that have memory addresses var result = !newList ? clauses : clauses.Select((b) => ClauseParser.Parse(b.ToString())).ToList(); string rawSymbol = symbol.GetContent(true).ToString(); for (int i = 0; i < result.Count; ++i) { var root = result[i]; if (root == null) { continue; } // remove either a symbol or the whole rootBlock BlockIterator.TerminableForEach(root, (currentBlock) => { if (currentBlock.GetContent(true).ToString() == rawSymbol) { // remove the whole clause if it contains the exact content of the symbol // passed through in this method // (true in a disjunctive clause means true as a whole) if (currentBlock.IsNegated == symbol.IsNegated) { result.RemoveAt(i--); return(false); } // remove only this symbol if it does not have the same negation // because when this happens, the symbol within stored list turns out to be false // which is removable in a sea of disjunctions bool isEOL = currentBlock.NextBlock == root; var unaffectedBlock = isEOL ? currentBlock.PreviousBlock.PreviousBlock : currentBlock.NextBlock.NextBlock; // block list contains only 1 block if (unaffectedBlock == currentBlock) { currentBlock.Isolate(true); result[i] = null; return(false); } if (isEOL) { // a||b into b if remove a unaffectedBlock.RemoveBack(true); unaffectedBlock.RemoveBack(true); } else { // a||b||c into a||c if remove b unaffectedBlock.RemoveFront(true); unaffectedBlock.RemoveFront(true); } if (root == currentBlock) { result[i] = unaffectedBlock; return(false); } } return(true); }); } return(result); }