예제 #1
0
        /// <summary>
        /// Finds the state with the lowest value in fScores
        /// </summary>
        /// <param name="set">A list of CemaStates</param>
        /// <param name="fScores">A dictionary of CemaStates and their fScores</param>
        /// <param name="randomBest">Given equal value choices return one at random versus the first found</param>
        /// <returns>Lowest cost state</returns>
        private GoapState FindBest(List <GoapState> set, Dictionary <string, double> fScores, bool randomBest)
        {
            GoapState lowestState = null;
            double    lowest      = double.MaxValue;
            int       bestCount   = 1;

            //loop through all states in the list
            foreach (GoapState state in set)
            {
                double value = fScores[state.idCode];

                if ((value == lowest) && (randomBest))
                {
                    bestCount++;
                    Random rnd = new Random();
                    if (rnd.NextDouble() < (1 / (double)bestCount))
                    {
                        lowestState = state;
                        lowest      = value;
                    }
                }
                //keep the best score
                if (value < lowest)
                {
                    lowestState = state;
                    lowest      = value;
                    bestCount   = 1;
                }
            }

            return(lowestState);
        }
예제 #2
0
        public void setSolution(GoapState cState, string solutionMt, string nowMt, string backgroundMt)
        {
            // Make the description in cState the focus
            prologEngine.markKBScratchpad(solutionMt);

            prologEngine.clearKB(solutionMt);
            prologEngine.clearConnectionsFromMt(solutionMt);
            if (backgroundMt != null)
            {
                prologEngine.connectMT(solutionMt, backgroundMt);
            }
            // foreach (string moduleMt in cState.modList)
            // {
            //     prologEngine.connectMT(solutionMt, moduleMt);
            // }
            string goalCode = "";

            foreach (string p in cState.missingList)
            {
                goalCode += String.Format("precond({0}).\n", p);
            }
            prologEngine.appendKB(goalCode, solutionMt);

            List <string> solutionMissingList = missingInMt(solutionMt, nowMt);

            //List<string> solutionViolationList = violationsInMt(problemMt);

            cState.missingList = solutionMissingList;
            //cState.violationList = solutionViolationList;
        }
예제 #3
0
        public void commitSolution(GoapState cState, string solutionMt, string nowMt, string backgroundMt)
        {
            prologEngine.markKBScratchpad(solutionMt);
            planNode = cState;
            // Modules/Actions are in reverse order from now to goal so flip them
            cState.modList.Reverse();

            // Make final connections
            if (backgroundMt != null)
            {
                prologEngine.connectMT(solutionMt, backgroundMt);
            }
            foreach (string moduleMt in cState.modList)
            {
                prologEngine.connectMT(solutionMt, moduleMt);
            }

            // Post stats and planner state
            string postScript = "";

            postScript += String.Format("g({0}).\n", cState.costSoFar());
            postScript += String.Format("h({0}).\n", cState.distToGoal());
            postScript += String.Format("f({0}).\n", cState.costSoFar() + cState.distToGoal() * problemWorstCost);
            postScript += String.Format("worst({0}).\n", problemWorstCost);
            postScript += String.Format("openedNodes({0}).\n", openSet.Count);
            postScript += String.Format("closedNodes({0}).\n", closedSet.Count);
            postScript += String.Format("totalNodes({0}).\n", openSet.Count + closedSet.Count);

            if (cState.distToGoal() == 0)
            {
                postScript += "planstate(solved).\n";
            }
            else
            {
                postScript += "planstate(unsolved).\n";
            }

            prologEngine.appendKB(postScript, solutionMt);


            // post the modules used
            string modString = "";

            if (cState.modList.Count > 0)
            {
                foreach (string m in cState.modList)
                {
                    modString += m + " ";
                }
                prologEngine.appendListPredToMt("modlist", modString, solutionMt);
            }
            else
            {
                prologEngine.appendKB("modlist([]).\n", solutionMt);
            }

            string planSequence = "";
            int    planCount    = 0;

            if (cState.modList.Count > 0)
            {
                foreach (string m in cState.modList)
                {
                    planSequence += String.Format("planraw({0}).\n", m);
                }
                foreach (string m in cState.modList)
                {
                    planSequence += String.Format("planseq({0},{1}).\n", planCount, m);
                    planCount++;
                }
                prologEngine.appendKB(planSequence, solutionMt);
            }
            else
            {
                prologEngine.appendKB("planraw(nop).\n planseq(0,nop).\n", solutionMt);
            }
            //post anything missing.

            if (cState.missingList.Count > 0)
            {
                string missingString = "";
                foreach (string m in cState.missingList)
                {
                    missingString += " " + m;
                }
                prologEngine.appendListPredToMt("missing", missingString, solutionMt);
            }
            else
            {
                prologEngine.appendKB("missing([]).\n", solutionMt);
            }
            tickEnd = Environment.TickCount;
            int elapsed    = tickEnd - tickBegin;
            int totalNodes = openSet.Count + closedSet.Count;

            SIProlog.ConsoleWriteLine("Planning time = {0}", elapsed);
            SIProlog.ConsoleWriteLine("Planning list = '{0}'", modString);

            SIProlog.ConsoleWriteLine("Planning tials = {0}", trials);
            SIProlog.ConsoleWriteLine("TotalNodes = {0}", totalNodes);
            if (trials > 0)
            {
                SIProlog.ConsoleWriteLine("Planning ms/trials = {0}", ((double)elapsed / (double)trials));
            }
            if (totalNodes > 0)
            {
                double mspn = ((double)elapsed / (double)totalNodes);
                SIProlog.ConsoleWriteLine("Planning ms/nodes = {0}", mspn);
                if (mspn > 0)
                {
                    SIProlog.ConsoleWriteLine("Planning @ nodes/sec = {0}", 1000 / mspn);
                }
            }
            if (elapsed > 0)
            {
                SIProlog.ConsoleWriteLine("Planning trials/ms = {0}", ((double)trials / (double)elapsed));
                SIProlog.ConsoleWriteLine("Planning nodes/ms = {0}", ((double)totalNodes / (double)elapsed));
            }

            SIProlog.ConsoleWriteLine(postScript);
            prologEngine.markKBNonScratchPad(solutionMt);
        }
예제 #4
0
        // GOAP is different from CEMA in:
        // - backward planning process looking for a defined nowMt
        // - sequence of action modules matters
        // - "state" is the set of unmet goal conditions
        // - a goal state has no conditions in it

        // In Mt's:
        //   state(prop) : prop is true
        //   precond(prop) : is a goal to make true
        //   effect(prop) : applying mt will make prop true
        //   cost(n) : using mt will cost n, default is 1

        // Using an A* search with
        //   h(n)= number of unmet conditions
        //   g(n)= number of modules used so far
        //   f(n) = h(n)+g(n)
        // note: g(n) could be defined by the sum of a cost predicate in each module

        // Requires
        // - an MT defining the goal state spec using precond(p)
        // - an MT defining the current state using state(p)
        // - an MT defining the background context logic if any
        // - an MT having all module Mt's visible
        // - a set of module mt's containing
        //    - module(module_mt_name)
        //    - optionally cost(module_cost)
        //    - set/list of precond(proposition)
        //    - set/list of effect(proposition)
        //    - any other information that defines that module

        // - System will return
        //    - a sequence of module mt's that provide a solution
        //    - a solution mt with a genlMt to all the solution modules

        // TODO's:
        // + return BTXML fragment representing plan
        // - possible single first action for replanning agents

        public bool constructPlan(string goalMt, string nowMt, string moduleMt, string backgroundMt, string solutionMt)
        {
            tickBegin = Environment.TickCount;

            List <Dictionary <string, string> > bingingsList = new List <Dictionary <string, string> >();

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

            // Collect Module List
            string query = "module(MODMT)";

            prologEngine.askQuery(query, moduleMt, out bingingsList);
            foreach (Dictionary <string, string> bindings in bingingsList)
            {
                foreach (string k in bindings.Keys)
                {
                    if (k == "MODMT")
                    {
                        totalModuleList.Add(bindings[k]);
                    }
                }
            }

            // Find worst cost
            // h(n)*problemWorstCost should be admissible for A*
            problemWorstCost = -1;

            if (worstWeighting)
            {
                string costQuery = "cost(COST)";
                prologEngine.askQuery(costQuery, moduleMt, out bingingsList);
                foreach (Dictionary <string, string> bindings in bingingsList)
                {
                    foreach (string k in bindings.Keys)
                    {
                        if (k == "COST")
                        {
                            double newCost = double.Parse(bindings[k].Trim());
                            if (newCost > problemWorstCost)
                            {
                                problemWorstCost = newCost;
                            }
                        }
                    }
                }
                if (problemWorstCost == -1)
                {
                    problemWorstCost = 1;
                }
            }
            else
            {
                problemWorstCost = 1;
            }

            List <string> missingList = missingInMt(goalMt, nowMt);

            GoapState start = new GoapState(new List <string>(), missingList);

            // get initial Eval
            setSolution(start, solutionMt, nowMt, backgroundMt);

            if ((missingList.Count == 0))
            {
                commitSolution(start, solutionMt, nowMt, backgroundMt);
                return(true); // nothing is missing so done
            }

            closedSet = new List <GoapState>();
            openSet   = new List <GoapState>();

            //cost expended so far
            Dictionary <string, double> gScores = new Dictionary <string, double>();

            //Estimate how far to go
            Dictionary <string, double> hScores = new Dictionary <string, double>();

            //combined f(n) = g(n)+h(n)
            Dictionary <string, double> fScores = new Dictionary <string, double>();

            gScores.Add(start.idCode, 0);
            hScores.Add(start.idCode, start.distToGoal() * problemWorstCost);
            fScores.Add(start.idCode, (gScores[start.idCode] + hScores[start.idCode]));

            openSet.Add(start);
            trials = 0;

            while (openSet.Count != 0)
            {
                trials++;
                if (trials > limitTrials)
                {
                    break;
                }

                //we look for the node within the openSet with the lowest f score.
                GoapState bestState = this.FindBest(openSet, fScores, nondeterministic);
                setSolution(bestState, solutionMt, nowMt, backgroundMt);

                // if goal then we're done
                if (bestState.distToGoal() == 0)
                {
                    // return with the solutionMt already connected
                    commitSolution(bestState, solutionMt, nowMt, backgroundMt);
                    return(true);
                }
                openSet.Remove(bestState);
                closedSet.Add(bestState);

                // Not the final solution and too expensive
                if (bestState.totalCost > limitCost)
                {
                    continue;
                }

                // get the list of modules we have not used
                List <string> validModules = bestState.validNextMods(totalModuleList);
                foreach (string nextModule in validModules)
                {
                    // only consider those that provide something missing
                    if (!isRelevantMt(nextModule, bestState.missingList))
                    {
                        continue;
                    }

                    double nextCost = getModuleCost(nextModule);

                    // Ok nextModule is relevant so clone bestState and extend
                    List <string> nextModList = new List <string>();
                    foreach (string m in bestState.modList)
                    {
                        nextModList.Add(m);
                    }
                    nextModList.Add(nextModule);
                    List <string> nextGoalSet = transformAct(nextModule, bestState.missingList);

                    GoapState nextState = new GoapState(nextModList, nextGoalSet);
                    nextState.totalCost = bestState.totalCost + nextCost;
                    // measure the quality of the next state
                    setSolution(nextState, solutionMt, nowMt, backgroundMt);

                    //skip if it has been examined
                    if (closedSet.Contains(nextState))
                    {
                        continue;
                    }

                    if (!openSet.Contains(nextState))
                    {
                        openSet.Add(nextState);
                        gScores[nextState.idCode] = nextState.costSoFar();
                        hScores[nextState.idCode] = nextState.distToGoal() * problemWorstCost;
                        fScores[nextState.idCode] = (gScores[nextState.idCode] + hScores[nextState.idCode]);
                    }
                }
                openSet.Sort();
            }
            // an impossible task appently
            commitSolution(start, solutionMt, nowMt, backgroundMt);
            return(false);
        }