/// <summary>
        /// Returns an ImmutableConstantChecker with contents identical to the given ConstantChecker.
        /// May not actually make a copy if the input is immutable.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public static ImmutableConstantChecker CopyOf(IConstantChecker other)
        {
            var immutableConstantChecker = other as ImmutableConstantChecker;
            if (immutableConstantChecker != null)
                return immutableConstantChecker;

            ISentenceFormModel model = other.SentenceFormModel;
            var sentencesByForm = new MultiDictionary<ISentenceForm, Fact>(false);
            foreach (ISentenceForm form in other.ConstantSentenceForms)
                sentencesByForm[form] = other.GetTrueSentences(form);

            return new ImmutableConstantChecker(ImmutableSentenceFormModel.CopyOf(model), sentencesByForm);
        }
 private static void AddFormToCompletedValues(ISentenceForm form, Dictionary<ISentenceForm, ICollection<Fact>> completedSentenceFormValues,
     IConstantChecker constantChecker)
 {
     completedSentenceFormValues[form] = new List<Fact>(constantChecker.GetTrueSentences(form));
 }
 private static void AddConstantsToFunctionInfo(ISentenceForm form, IConstantChecker constantChecker,
                                                IDictionary<ISentenceForm, FunctionInfo> functionInfoMap)
 {
     functionInfoMap[form] = FunctionInfoImpl.Create(form, constantChecker);
 }
Example #4
0
 public static FunctionInfo Create(ISentenceForm form, IConstantChecker constantChecker)
 {
     return new FunctionInfoImpl(form, constantChecker.GetTrueSentences(form));
 }
Example #5
0
        public void AddSentenceForm(ISentenceForm form, ISentenceDomainModel model,
            IDictionary<Fact, IComponent> components,
            IDictionary<Fact, IComponent> negations, IConstant trueComponent, IConstant falseComponent,
            bool usingBase, bool usingInput, ISet<ISentenceForm> recursionForms,
            IDictionary<Fact, IComponent> temporaryComponents, IDictionary<Fact, IComponent> temporaryNegations,
            Dictionary<ISentenceForm, FunctionInfo> functionInfoMap, IConstantChecker constantChecker,
            Dictionary<ISentenceForm, ICollection<Fact>> completedSentenceFormValues)
        {
            //This is the meat of it (along with the entire Assignments class).
            //We need to enumerate the possible propositions in the sentence form...
            //We also need to hook up the sentence form to the inputs that can make it true.
            //We also try to optimize as we go, which means possibly removing the
            //proposition if it isn't actually possible, or replacing it with
            //true/false if it's a constant.

            ISet<Fact> alwaysTrueSentences = model.GetSentencesListedAsTrue(form);
            ISet<Implication> rules = model.GetRules(form);

            foreach (Fact alwaysTrueSentence in alwaysTrueSentences)
            {
                //We add the sentence as a constant
                if (alwaysTrueSentence.RelationName == GameContainer.Parser.TokLegal
                    || alwaysTrueSentence.RelationName == GameContainer.Parser.TokNext
                    || alwaysTrueSentence.RelationName == GameContainer.Parser.TokGoal)
                {
                    var prop = _componentFactory.CreateProposition(alwaysTrueSentence);
                    //Attach to true
                    trueComponent.AddOutput(prop);
                    prop.AddInput(trueComponent);
                    //Still want the same components;
                    //we just don't want this to be anonymized
                }
                //Assign as true
                components[alwaysTrueSentence] = trueComponent;
                negations[alwaysTrueSentence] = falseComponent;
            }

            //For does/true, make nodes based on input/base, if available
            if (usingInput && form.Name.Equals(GameContainer.Parser.TokDoes))
            {
                //Add only those propositions for which there is a corresponding INPUT
                ISentenceForm inputForm = form.WithName(GameContainer.SymbolTable["input"]);
                foreach (Fact inputSentence in constantChecker.GetTrueSentences(inputForm))
                {
                    Fact doesSentence = _doesProcessor.ProcessBaseFact(inputSentence);
                    var prop = _componentFactory.CreateProposition(doesSentence);
                    components[doesSentence] = prop;
                }
                return;
            }
            if (usingBase && form.Name.Equals(GameContainer.Parser.TokTrue))
            {
                ISentenceForm baseForm = form.WithName(GameContainer.SymbolTable["base"]);
                foreach (Fact baseSentence in constantChecker.GetTrueSentences(baseForm))
                {
                    Fact trueSentence = _trueProcessor.ProcessBaseFact(baseSentence);
                    IProposition prop = _componentFactory.CreateProposition(trueSentence);
                    components[trueSentence] = prop;
                }
                return;
            }

            //var recursiveFormCache = new RecursionFormsCache(recursionForms);

            var inputsToOr = new Dictionary<Fact, HashSet<IComponent>>();
            foreach (Implication rule in rules)
            {
                AssignmentsImpl assignments = AssignmentsFactory.GetAssignmentsForRule(rule, model, functionInfoMap,
                    completedSentenceFormValues);

                //Calculate vars in live (non-constant, non-distinct) conjuncts
                ISet<TermVariable> varsInLiveConjuncts = GetVarsInLiveConjuncts(rule,
                    constantChecker.ConstantSentenceForms);
                foreach (var head in rule.Consequent.VariablesOrEmpty)
                    varsInLiveConjuncts.Add(head);
                var varsInRule = new HashSet<TermVariable>(rule.VariablesOrEmpty);
                bool preventDuplicatesFromConstants = varsInRule.Count > varsInLiveConjuncts.Count;

                bool[] constantFormCheck = new bool[rule.Antecedents.Constituents.Length];
                for (int i = 0; i < rule.Antecedents.Constituents.Length; i++)
                {
                    Expression literal = rule.Antecedents.Constituents[i];
                    var fact = literal as Fact;
                    var negated = literal as Negation;
                    if (fact != null || negated != null)
                    {
                        if (negated != null)
                            fact = (Fact) negated.Negated;

                        ISentenceForm conjunctForm = model.GetSentenceForm(fact);
                        if (constantChecker.IsConstantForm(conjunctForm))
                            constantFormCheck[i] = true;
                    }
                }

                for (var asnItr = (AssignmentIteratorImpl) assignments.GetEnumerator(); asnItr.MoveNext();)
                {
                    TermObjectSubstitution assignment = asnItr.Current;
                    if (assignment == null)
                        continue; //Not sure if this will ever happen

                    //ConcurrencyUtils.checkForInterruption();

                    var sentence = (Fact) rule.Consequent.ApplySubstitution(assignment);

                    //Now we go through the conjuncts as before, but we wait to hook them up.
                    var componentsToConnect = new List<IComponent>(rule.Consequent.Arity);
                    for (int i = 0; i < rule.Antecedents.Constituents.Length; i++)
                    {
                        Expression literal = rule.Antecedents.Constituents[i];
                        var fact = literal as Fact;
                        if (fact != null)
                        {
                            if (fact.RelationName != GameContainer.Parser.TokDistinct)
                            {
                                //Get the sentence post-substitutions
                                var transformed = (Fact) literal.ApplySubstitution(assignment);

                                //Check for constant-ness
                                //ISentenceForm conjunctForm = model.GetSentenceForm(transformed);
                                //if (constantChecker.IsConstantForm(conjunctForm))
                                if (constantFormCheck[i])
                                {
                                    if (!constantChecker.IsTrueConstant(transformed))
                                    {
                                        List<TermVariable> varsToChange = GetVarsInConjunct(literal);
                                        asnItr.ChangeOneInNext(varsToChange, assignment);
                                        componentsToConnect.Add(null);
                                    }
                                    continue;
                                }

                                //If conj is null and this is a sentence form we're still handling, hook up to a temporary sentence form
                                IComponent conj;
                                if (!components.TryGetValue(transformed, out conj))
                                    temporaryComponents.TryGetValue(transformed, out conj);

                                if (conj == null && InSentenceFormGroup(transformed, recursionForms))
                                {
                                    //Set up a temporary component
                                    var tempProp = _componentFactory.CreateProposition(transformed);
                                    temporaryComponents[transformed] = tempProp;
                                    conj = tempProp;
                                }
                                //Let's say this is false; we want to backtrack and change the right variable
                                if (conj == null || IsThisConstant(conj, falseComponent))
                                {
                                    List<TermVariable> varsInConjunct = GetVarsInConjunct(literal);
                                    asnItr.ChangeOneInNext(varsInConjunct, assignment);
                                    //These last steps just speed up the process
                                    //telling the factory to ignore this rule
                                    componentsToConnect.Add(null);
                                    continue; //look at all the other restrictions we'll face
                                }

                                componentsToConnect.Add(conj);
                            }
                        }
                        else
                        {
                            var negation = literal as Negation;
                            if (negation != null)
                            {
                                //Add a "not" if necessary
                                //Look up the negation
                                var inner = (Fact) negation.Negated;
                                var transformed = (Fact) inner.ApplySubstitution(assignment);

                                //Add constant-checking here...
                                //ISentenceForm conjunctForm = model.GetSentenceForm(transformed);
                                //if (constantChecker.IsConstantForm(conjunctForm))
                                if (constantFormCheck[i])
                                {
                                    if (constantChecker.IsTrueConstant(transformed))
                                    {
                                        List<TermVariable> varsToChange = GetVarsInConjunct(negation);
                                        asnItr.ChangeOneInNext(varsToChange, assignment);
                                        componentsToConnect.Add(null);
                                    }
                                    continue;
                                }

                                IComponent conj;
                                negations.TryGetValue(transformed, out conj);
                                if (IsThisConstant(conj, falseComponent))
                                {
                                    //We need to change one of the variables inside
                                    List<TermVariable> varsInConjunct = GetVarsInConjunct(inner);
                                    asnItr.ChangeOneInNext(varsInConjunct, assignment);
                                    //ignore this rule
                                    componentsToConnect.Add(null);
                                    continue;
                                }
                                if (conj == null)
                                    temporaryNegations.TryGetValue(transformed, out conj);

                                //Check for the recursive case:
                                if (conj == null && InSentenceFormGroup(transformed, recursionForms))
                                {
                                    IComponent positive;
                                    if (!components.TryGetValue(transformed, out positive))
                                        temporaryComponents.TryGetValue(transformed, out positive);

                                    if (positive == null)
                                    {
                                        //Make the temporary proposition
                                        var tempProp = _componentFactory.CreateProposition(transformed);
                                        temporaryComponents[transformed] = tempProp;
                                        positive = tempProp;
                                    }
                                    //Positive is now set and in temporaryComponents
                                    //Evidently, wasn't in temporaryNegations
                                    //So we add the "not" gate and set it in temporaryNegations
                                    var not = _componentFactory.CreateNot();
                                    //Add positive as input
                                    not.AddInput(positive);
                                    positive.AddOutput(not);
                                    temporaryNegations[transformed] = not;
                                    conj = not;
                                }
                                if (conj == null)
                                {
                                    IComponent positive;
                                    components.TryGetValue(transformed, out positive);
                                    //No, because then that will be attached to "negations", which could be bad

                                    if (positive == null)
                                    {
                                        //So the positive can't possibly be true (unless we have recurstion)
                                        //and so this would be positive always
                                        //We want to just skip this conjunct, so we continue to the next

                                        continue; //to the next conjunct
                                    }

                                    //Check if we're sharing a component with another sentence with a negation
                                    //(i.e. look for "nots" in our outputs and use those instead)
                                    INot existingNotOutput = GetNotOutput(positive);
                                    if (existingNotOutput != null)
                                    {
                                        componentsToConnect.Add(existingNotOutput);
                                        negations[transformed] = existingNotOutput;
                                        continue; //to the next conjunct
                                    }

                                    var not = _componentFactory.CreateNot();
                                    not.AddInput(positive);
                                    positive.AddOutput(not);
                                    negations[transformed] = not;
                                    conj = not;
                                }
                                componentsToConnect.Add(conj);
                            }
                            else
                            {
                                throw new Exception("Unwanted Expression type");
                            }
                        }
                    }
                    if (!componentsToConnect.Contains(null))
                    {
                        //Connect all the components
                        IProposition andComponent = _componentFactory.CreateProposition(_tempFact);

                        Andify(componentsToConnect, andComponent, trueComponent);
                        if (!IsThisConstant(andComponent, falseComponent))
                        {
                            if (!inputsToOr.ContainsKey(sentence))
                                inputsToOr[sentence] = new HashSet<IComponent>();
                            inputsToOr[sentence].Add(andComponent);
                            //We'll want to make sure at least one of the non-constant
                            //components is changing
                            if (preventDuplicatesFromConstants)
                                asnItr.ChangeOneInNext(varsInLiveConjuncts, assignment);
                        }
                    }
                }
            }

            //At the end, we hook up the conjuncts
            foreach (var entry in inputsToOr)
            {
                //ConcurrencyUtils.checkForInterruption();

                Fact sentence = entry.Key;
                HashSet<IComponent> inputs = entry.Value;
                var realInputs = new HashSet<IComponent>();
                foreach (IComponent input in inputs)
                    if (input is IConstant || !input.Inputs.Any())
                        realInputs.Add(input);
                    else
                    {
                        realInputs.Add(input.GetSingleInput());
                        input.GetSingleInput().RemoveOutput(input);
                        input.RemoveAllInputs();
                    }

                var prop = _componentFactory.CreateProposition(sentence);
                Orify(realInputs, prop, falseComponent);
                components[sentence] = prop;
            }

            //True/does sentences will have none of these rules, but
            //still need to exist/"float"
            //We'll do this if we haven't used base/input as a basis
            if (form.Name.Equals(GameContainer.Parser.TokTrue) || form.Name.Equals(GameContainer.Parser.TokDoes))
                foreach (Fact sentence in model.GetDomain(form)) //ConcurrencyUtils.checkForInterruption();
                    components[sentence] = _componentFactory.CreateProposition(sentence);
        }
Example #6
0
        private static bool GoodCondensationSetByHeuristic(ICollection<Expression> minSet, Implication rule, ISentenceDomain model,
            IConstantChecker checker, UnusedSentenceNameSource sentenceNameSource)
        {
            //We actually want the sentence model here so we can see the domains
            //also, if it's a constant, ...
            //Anyway... we want to compare the heuristic for the number of assignments
            //and/or links that will be generated with or without the condensation set
            //Heuristic for a rule is A*(L+1), where A is the number of assignments and
            //L is the number of literals, unless L = 1, in which case the heuristic is
            //just A. This roughly captures the number of links that would be generated
            //if this rule were to be generated.
            //Obviously, there are differing degrees of accuracy with which we can
            //represent A.
            //One way is taking the product of all the variables in all the domains.
            //However, we can do better by actually asking the Assignments class for
            //its own heuristic of how it would implement the rule as-is.
            //The only tricky aspect here is that we need an up-to-date SentenceModel,
            //and in some cases this could be expensive to compute. Might as well try
            //it, though...

            //Heuristic for the rule as-is:

            long assignments = AssignmentsImpl.GetNumAssignmentsEstimate(rule,
                SentenceDomainModels.GetVarDomains(rule, model, SentenceDomainModels.VarDomainOpts.IncludeHead),
                checker);
            int literals = rule.Consequent.Arity;
            if (literals > 1)
                literals++;

            //We have to "and" the literals together
            //Note that even though constants will be factored out, we're concerned here
            //with getting through them in a reasonable amount of time, so we do want to
            //count them. TODO: Not sure if they should be counted in L, though...
            long curRuleHeuristic = assignments * literals;
            //And if we split them up...
            List<Implication> newRules = ApplyCondensation(minSet, rule, sentenceNameSource);
            Implication r1 = newRules[0], r2 = newRules[1];

            //Augment the model
            ISentenceDomain newModel = AugmentModelWithNewForm(model, newRules);

            long a1 = AssignmentsImpl.GetNumAssignmentsEstimate(r1,
                SentenceDomainModels.GetVarDomains(r1, newModel, SentenceDomainModels.VarDomainOpts.IncludeHead), checker);
            long a2 = AssignmentsImpl.GetNumAssignmentsEstimate(r2,
                SentenceDomainModels.GetVarDomains(r2, newModel, SentenceDomainModels.VarDomainOpts.IncludeHead), checker);
            int l1 = r1.Consequent.Arity; if (l1 > 1) l1++;
            int l2 = r2.Consequent.Arity; if (l2 > 1) l2++;

            //Whether we split or not depends on what the two heuristics say
            long newRulesHeuristic = a1 * l1 + a2 * l2;
            return newRulesHeuristic < curRuleHeuristic;
        }
Example #7
0
        private static ISet<Expression> GetCondensationSet(Implication rule, ISentenceDomain model, IConstantChecker checker,
                                                           UnusedSentenceNameSource sentenceNameSource)
        {
            //We use each variable as a starting point
            List<TermVariable> varsInRule = rule.VariablesOrEmpty.ToList();
            List<TermVariable> varsInHead = rule.Consequent.VariablesOrEmpty.ToList();
            var varsNotInHead = new List<TermVariable>(varsInRule);
            varsNotInHead.RemoveAll(varsInHead.Contains);

            foreach (TermVariable var in varsNotInHead)
            {
                var minSet = new HashSet<Expression>();
                foreach (Expression literal in rule.Antecedents.Conjuncts)
                    if (literal.VariablesOrEmpty.Contains(var))
                        minSet.Add(literal);

                //#1 is already done
                //Now we try #2
                var varsNeeded = new HashSet<TermVariable>();
                var varsSupplied = new HashSet<TermVariable>();
                foreach (Expression literal in minSet)
                {
                    if (literal is Negation)
                    {
                        foreach (var variable in literal.VariablesOrEmpty)
                            varsNeeded.Add(variable);
                    }
                    else if (literal is Fact)
                    {
                        if (((Fact)literal).RelationName == GameContainer.Parser.TokDistinct)
                            foreach (var variable in literal.VariablesOrEmpty)
                                varsNeeded.Add(variable);
                        else
                            foreach (var variable in literal.VariablesOrEmpty)
                                varsSupplied.Add(variable);
                    }
                }
                varsNeeded.RemoveWhere(varsSupplied.Contains);
                if (varsNeeded.Any())
                    continue;

                var candidateSuppliersList = new List<ISet<Expression>>();
                foreach (TermVariable varNeeded in varsNeeded)
                {
                    var suppliers = new HashSet<Expression>();
                    foreach (Expression literal in rule.Antecedents.Conjuncts)
                        if (literal is Fact)
                            if (literal.VariablesOrEmpty.Contains(varNeeded))
                                suppliers.Add(literal);
                    candidateSuppliersList.Add(suppliers);
                }

                //TODO: Now... I'm not sure if we want to minimize the number of literals added, or the number of variables added
                //Right now, I don't have time to worry about optimization. Currently, we pick one at random
                //TODO: Optimize this
                var literalsToAdd = new HashSet<Expression>();
                foreach (ISet<Expression> suppliers in candidateSuppliersList)
                    if (!suppliers.Intersect(literalsToAdd).Any())
                        literalsToAdd.Add(suppliers.First());

                minSet.UnionWith(literalsToAdd);

                if (GoodCondensationSetByHeuristic(minSet, rule, model, checker, sentenceNameSource))
                    return minSet;

            }
            return null;
        }