/// <summary> /// Creates a PropNet for the game with the given description. /// </summary> public static PropNet Create(IList<Expression> description, IComponentFactory componentFactory) { Console.WriteLine("Building propnet..."); _componentFactory = componentFactory; DateTime startTime = DateTime.UtcNow; description = GdlCleaner.Run(description); description = DeORer.Run(description); description = VariableConstrainer.ReplaceFunctionValuedVariables(description); description = Relationizer.Run(description); description = CondensationIsolator.Run(description); if (Logger.IsDebugEnabled) foreach (var gdl in description) Logger.Debug(gdl); //We want to start with a rule graph and follow the rule graph. Start by finding general information about the game ISentenceDomainModel model = SentenceDomainModelFactory.CreateWithCartesianDomains(description); //Restrict domains to values that could actually come up in rules. //See chinesecheckers4's "count" relation for an example of why this could be useful. model = SentenceDomainModelOptimizer.RestrictDomainsToUsefulValues(model); Logger.Debug("Setting constants..."); //TODO: ConstantChecker constantChecker = ConstantCheckerFactory.createWithForwardChaining(model); IConstantChecker constantChecker = ConstantCheckerFactory.CreateWithProver(model); Logger.Debug("Done setting constants"); HashSet<String> sentenceFormNames = SentenceForms.GetNames(model.SentenceForms); bool usingBase = sentenceFormNames.Contains("base"); bool usingInput = sentenceFormNames.Contains("input"); //For now, we're going to build this to work on those with a particular restriction on the dependency graph: //Recursive loops may only contain one sentence form. This describes most games, but not all legal games. IDictionary<ISentenceForm, ICollection<ISentenceForm>> dependencyGraph = model.DependencyGraph; Logger.Debug("Computing topological ordering... "); //ConcurrencyUtils.checkForInterruption(); IEnumerable<ISentenceForm> topologicalOrdering = GetTopologicalOrdering(model.SentenceForms, dependencyGraph, usingBase, usingInput); Logger.Debug("done"); List<TermObject> roles = GameContainer.GameInformation.GetRoles(); var components = new Dictionary<Fact, IComponent>(); var negations = new Dictionary<Fact, IComponent>(); IConstant trueComponent = _componentFactory.CreateConstant(true); IConstant falseComponent = _componentFactory.CreateConstant(false); var functionInfoMap = new Dictionary<ISentenceForm, FunctionInfo>(); var completedSentenceFormValues = new Dictionary<ISentenceForm, ICollection<Fact>>(); var sentenceFormAdder = new SentenceFormAdder(_componentFactory, DoesProcessor, TrueProcessor, TempFact); foreach (ISentenceForm form in topologicalOrdering) { //ConcurrencyUtils.checkForInterruption(); Logger.Debug("Adding sentence form " + form); if (constantChecker.IsConstantForm(form)) { Logger.Debug(" (constant)"); //Only add it if it's important if (form.Name.Equals(GameContainer.Parser.TokLegal) || form.Name.Equals(GameContainer.Parser.TokGoal) || form.Name.Equals(GameContainer.Parser.TokInit)) { //Add it foreach (Fact trueSentence in constantChecker.GetTrueSentences(form)) { var trueProp = _componentFactory.CreateProposition(trueSentence); trueProp.AddInput(trueComponent); trueComponent.AddOutput(trueProp); components[trueSentence] = trueComponent; } } Logger.Debug("Checking whether {0} is a functional constant...", form); AddConstantsToFunctionInfo(form, constantChecker, functionInfoMap); AddFormToCompletedValues(form, completedSentenceFormValues, constantChecker); continue; } Logger.Debug(string.Empty); //TODO: Adjust "recursive forms" appropriately //Add a temporary sentence form thingy? ... var temporaryComponents = new Dictionary<Fact, IComponent>(); var temporaryNegations = new Dictionary<Fact, IComponent>(); sentenceFormAdder.AddSentenceForm(form, model, components, negations, trueComponent, falseComponent, usingBase, usingInput, ImmutableHashSet.Create(form), temporaryComponents, temporaryNegations, functionInfoMap, constantChecker, completedSentenceFormValues); //TODO: Pass these over groups of multiple sentence forms if (temporaryComponents.Any()) Logger.Debug("Processing temporary components..."); ProcessTemporaryComponents(temporaryComponents, temporaryNegations, components, negations, trueComponent, falseComponent); AddFormToCompletedValues(form, completedSentenceFormValues, components); //TODO: Add this, but with the correct total number of components (not just Propositions) Console.WriteLine(" {0} components added", completedSentenceFormValues[form].Count); } //Connect "next" to "true" Logger.Debug("Adding transitions..."); AddTransitions(components); //Set up "init" proposition Logger.Debug("Setting up 'init' proposition..."); SetUpInit(components, trueComponent, falseComponent); //Now we can safely... RemoveUselessBasePropositions(components, negations, trueComponent, falseComponent); Logger.Debug("Creating component set..."); var componentSet = new HashSet<IComponent>(components.Values); CompleteComponentSet(componentSet); //ConcurrencyUtils.checkForInterruption(); Logger.Debug("Initializing propnet object..."); //Make it look the same as the PropNetFactory results, until we decide how we want it to look NormalizePropositions(componentSet); var propnet = new PropNet(roles, componentSet); Logger.Debug("Done setting up propnet; took {0}ms, has {1} components and {2} links", (DateTime.UtcNow - startTime).TotalMilliseconds, componentSet.Count, propnet.GetNumLinks()); Logger.Debug("Propnet has {0} ands; {1} ors; {2} nots", propnet.GetNumAnds(), propnet.GetNumOrs(), propnet.GetNumNots()); if (ConfigurationManager.AppSettings["OutputPropNet"] == "true") propnet.RenderToFile("propnet.dot"); return propnet; }