/// <summary> /// Optimizes an already-existing propnet by removing useless leaves. These are components that have no /// outputs, but have no special meaning in GDL that requires them to stay. /// </summary> /// <param name="pn"></param> public static void LopUselessLeaves(PropNet pn) { //Approach: Collect useful propositions based on a backwards //search from goal/legal/terminal (passing through transitions) var usefulComponents = new HashSet<IComponent>(); //TODO: Also try with queue? var toAdd = new Stack<IComponent>(); toAdd.Push(pn.TerminalProposition); usefulComponents.Add(pn.InitProposition); //Can't remove it... IEnumerable<IProposition> goalProps = pn.GoalPropositions.Values.SelectMany(goalProp => goalProp); foreach (IProposition prop in goalProps) toAdd.Push(prop); IEnumerable<IProposition> legalProps = pn.LegalPropositions.Values.SelectMany(legalProp => legalProp); foreach (IProposition prop in legalProps) toAdd.Push(prop); while (toAdd.Any()) { IComponent curComp = toAdd.Pop(); if (usefulComponents.Contains(curComp)) //We've already added it continue; usefulComponents.Add(curComp); foreach (IComponent input in curComp.Inputs) toAdd.Push(input); } //Remove the components not marked as useful var allComponents = new List<IComponent>(pn.Components); foreach (IComponent c in allComponents) if (!usefulComponents.Contains(c)) pn.RemoveComponent(c); }
/// <summary> /// Potentially optimizes an already-existing propnet by removing propositions with no special meaning. The inputs and outputs /// of those propositions are connected to one another. This is unlikely to improve performance unless values of every single /// component are stored (outside the propnet). /// </summary> /// <param name="pn"></param> public static void RemoveAnonymousPropositions(PropNet pn) { var toSplice = new List<IProposition>(); var toReplaceWithFalse = new List<IProposition>(); foreach (IProposition p in pn.Propositions) { //If it's important, continue to the next proposition if (p.Inputs.Count == 1 && p.GetSingleInput() is ITransition) //It's a base proposition continue; Fact sentence = p.Name; Fact relation = sentence; int name = relation.RelationName; var parser = GameContainer.Parser; if (name == parser.TokLegal || name == parser.TokGoal || name == parser.TokDoes || name == parser.TokInit || name == parser.TokTerminal || sentence.RelationName == GameContainer.SymbolTable["INIT"]) continue; if (p.Inputs.Count < 1) { //Needs to be handled separately... //because this is an always-false true proposition //and it might have and gates as outputs toReplaceWithFalse.Add(p); continue; } if (p.Inputs.Count != 1) throw new Exception(string.Format("Might have falsely declared {0} to be unimportant?", p.Name)); //Not important //System.out.println("Removing " + p); toSplice.Add(p); } foreach (IProposition p in toSplice) { //Get the inputs and outputs... HashSet<IComponent> inputs = p.Inputs; HashSet<IComponent> outputs = p.Outputs; //Remove the proposition... pn.RemoveComponent(p); //And splice the inputs and outputs back together if (inputs.Count > 1) throw new Exception("Programmer made a bad assumption here... might lead to trouble?"); foreach (IComponent input in inputs) foreach (IComponent output in outputs) { input.AddOutput(output); output.AddInput(input); } } foreach (IProposition p in toReplaceWithFalse) throw new Exception(string.Format("Should be replacing {0} with false, but should do that in the OPNF, really; better equipped to do that there", p)); }
/// <summary> /// Optimizes an already-existing propnet by removing propositions of the form (init ?x). Does NOT remove the proposition "INIT". /// </summary> /// <param name="pn"></param> public static void RemoveInits(PropNet pn) { var toRemove = (from p in pn.Propositions let relation = p.Name where relation.RelationName == GameContainer.Parser.TokInit select p).ToList(); foreach (IProposition p in toRemove) pn.RemoveComponent(p); }