cps721: questions about the 5th assignment.  

Questions related to the 5th assignment

This page contains questions from students and my answers to them. If a question is asked that has already been answered, then I will not post another answer. So if your questions seems to go unanswered, you should check over previous questions.

Can I use "not" in my rules?
You can use negation, for example applied to a fluent, in your rules, but remember that your rules should not begin with negations that are applied to predicates with variables, if variables have not yet been assigned any value. This means that you have to call other predicates first, such that they will retrieve values to variables and, subsequently, you can write negations of predicates at the end of your rule. Recall that a body of each rule is simply conjunction of logical statements and its logical meaning remains the same if you rearrange predicates so that those which have no negation at front of them will be called at the beginning of your rule. You can review the slide 16 "Caution: variables and negation" from the "Prolog basics" that we discussed at the beginning of this course: this slide illustrates my explanations.

Can I submit my solutions of the 5th assignment earlier? I have other work to do next week.
Yes, you are welcome to submit your solutions earlier.

For part 1, one of the goal states took me 4 minutes (without declarative heuristics) to execute even though in the question, it suggests that it should run under a minute. The solution is correct. But am I doing something wrong? I don't consider my computer to be slow.
There might be a minor bug in your program that slows down search that your program does. Print your program and read it very carefully. Compare your program with the specification given in the assignment and clarified on this Web page (see above). If this does not help, put it away, and read again next day. In some cases, you can spot a bug just by reading your program afresh, or with one of your friends. As an alternative approach, you can try to solve several easier, but related planning problems. For example, try goal states that can be reached with fewer actions. In other words, try to solve planning problems that are easier than that one which takes a long time for your computer to solve. For each of this intermediate goal state, record how much time it takes your program to compute a plan. You may notice, that some planning problems can be solved fast, but others takes long time. This may give you an idea that a delay can be due to a particular action, and consequently, may be your precondition rule, or other rules for this action are wrong. Also, when you try a few different goals (with the same initial state) you may catch a bug, if you will see that your program does not compute a plan that it is supposed to compute for some of the goal states. However, exploring different goal states takes time. So, first try to read your program and find a bug. Another useful debuging trick is to try specific sequences of actions, and see if they lead to the goal states as expected. If intuitively you expect a sequence of actions to be a plan solving a problem, but your program says "no", then there is a bug somewhere. You can try to trace a query using combination of "creep" (if you would like to see every step) and "skip" (if you would like to skip some rules altogether when you know there is no bug there). ECLiPSe Prolog release 6 has nice graphical debugger. By exploring different sequences of actions, you can usually locate a bug quickly.

When writing rules for fluents, are we allowed to use fluents for defining other fluents? for example using fluent "f1" and "f2" for defining fluent "f3" ?
No, you cannot write rules that compute whether a fluent is true in a situation S by using in the body of your rule fluents with respect to same situation S. There are counter-examples when rules of this type lead to wrong logical conclusions. You have to write genuine successor state axioms (SSAs) for each of the given fluents. Note that each SSA is a rule such that on the left hand side we write a fluent with respect to the next situation (that results from doing an action in a current situation S), and in the body of the rule we use fluents (and other predicates) that use the current situation S only. Read carefully the example about moving tiles on a grid that we discussed in class. Read also monkey-banana example and situation and fluents implementation of 3 coins puzzle.
Note that rather than saying that we define fluent, we say that we write a SSA for a fluent. Recall that there are two types of SSAs that you have to write. First, rules that say when a fluent becomes true in the next situation thanks to an action A. Sometimes, we say in this case, that an action A has a positive effect on this fluent. Second, rules that say that a fluent remains true in the next situation, if it is true in the current situation, and the most recent action A is not one of those which have a negative effect on the fluent (i.e., not one of those, which can make it false). The rules of the 2nd type express the common and natural property that fleunts persist by default unless there is a reason for a fluent to become false. This is why they can be called default rules.

If I run a query like "poss(actionName(arg1,arg2),S)" should it take a long time to find a solution?
All simple testing queries should be instanteneous. If any of them takes more than a few seconds, there is a bug in your program. This applies only to queries that have no variables, i.e., where arguments are instantiated properly. However, note that S is a variable in your query

        ?- poss(actionName(arg1,arg2),S).
This is wrong. You should type a list of actions instead of S, or simply [], if you are testing if action "actionName(arg1,arg2)" is possible initially. Otherwise, if you have a variable S in this query, you are asking your program to plan for a sequence of actions that leads to a state where "actionName(arg1,arg2)" is possible. Basically, you are asking your program to solve a planning problem. This may take a long time even if your program is not buggy, sine there are no means to guarantee that S is built out of legal_move actions. I would expect that this query may not be answered at all even by a correct program because it will do infinite recursion over lists of situations. So, you should avoid queries that use predicate poss with a variable S as an argument. In contrast, a query like
        ?- poss(actionName(arg1,arg2),[act1, act2]).
should be answered immediately if your program is correct, where act1 and act2 are generic place holders for action terms.

We are not sure on how to ask prolog for the goal state, we are having trouble with the variable of the solve_problem. In your file it is listed as     solve_problem(G,L,N). Should we put the goal state in G and a number in N but do we leave L as a variable? Would our query be something like this? [...skip...]
You should be trying queries like

where the variable ListofActions returns a plan corresponding to a goal state numbered in the 1st argument. The last argument N=7 because 7 should be enough as an upper bound to solve planning problems for all goal states from G=1 to G=4. For goal states with higher numbers you will need a larger upper bound (the last argument) to find a plan.

For the fluent inside(X, C), an object X is inside a container C, you have not introduced a situation S. Why is that?
It's a typo, read the 12th line from the bottom on Page 2 as inside(X,C,S), an object X is inside a container C in a current situation S.

Me and my group are confused about the jackUp and jackDown actions. Do we jackUp the car or are do we jackUp the hub. Changing what we jack(Up/Down) affects the way we implement the 'on' fluent.
In this assignment there are no actions that apply to car since "car" is only a container, but the container is not a fluent. In particular, the actions jackUp/jackDown apply to hubs. However, this is irrelevant to implementing successor state axioms for on(X,Y,S), since these rules should be using variables, not specific constants like hub4. The only constant that you can use in your rules is the constant "ground", but this is the only exception.

For part 2, is this query:  solve_problem(hasImage(sat1,therm,comet2,S),10)   the right way of testing our prolog program?

No, this is wrong query: you cannot write predicate hasImage inside another predicate solve_problem. Once you have completed debugging your program, you should simply query         solve_problem(ListOfActions,10) See examples of queries in slides, e.g., the monkey-banana problem. If you are in the process of debugging, and you are testing a sequence of actions to see if it is a solution according to your program, then provide the specific sequence of actions with constants only as arguments.

In the comet.pl [comet.pl], it has "Declarative Heuristics" written in comments, is that for the bonus question or do we need to add something to that for Part 2 Question 1 and 2?
The space below "Declarative Heuristics" is place-holder reserved for bonus part. If you are solving only the regular part of the assignment, there is no need to write anything there.

For Assignment 5, how are we supposed to deal with mutually recursive fluents?
Read FAQs: Q4/A4. You are allowed to write only precondition rules and SSAs. Review all examples from class. We never wrote any other kinds of rules.

can any objects be put on the ground (meaning wheels, hubcaps, nuts, containers, the wrench, and the jack) or are there only certain objects that can be on the ground?
This is irrelevant to the purposes of implementing precondition axioms for actions jackUp(Obj) and jackDown(Obj) that move things up/down from the ground or to the ground. Notice their argument Obj must be a variable. You have to implement these preconditions axioms following the specifications given in the assignmnet. Revisit examples of precondition axioms discussed in class. We never write them for specific constants, but we always write them in the most generic way.
Moreover, read carefully the specification of actions putOn(N,H) and putOn(W,H). They are possible only if the 2nd argument has type hub, and the 1st argument has either type nuts, or has type wheel. In particular, this means these two actions are not possible if the 2nd argument is the constant ground.
Informally speaking, for the purposes of this question, only certain objects can be "on" the ground. However, the fluent "on" is more generic, since as you can see from the initial state, nuts can be also "on" a hub. In any case, you have to implement successor state rules for the fluent on(X,Y,S) when arguments are variables X,Y, but not specific constants. You implement these rules following the specifications in the assignment. First, consider actions that make this fluent true, for them you write positive effect rules. Second, consider actions that can make this fluent false, for them you write the default rule saying the fluent remains true after doing A in S if it was true in S, unless the action A was one of those which make it false. We dioscussed many examples of successor state rules in class.

For Part 1, in the description of the "tight" fluent:
"tight(N, H, S): nuts N are tight on a hub H in a current situation S."
Are there some additional specifications missing at the end?  E.g., I would expect it to be true if the most recent action was "tighten", or if the previous situation was tight and the most recent action was not "loosen", etc.
Yes, your understanding is correct. The action "tighten" a has positive effect on this fluent, but action "loosen' has a negative effect.

In Part 2 of the assignment, I  just wanted to know if there was a situation that would cause you to lose an image you had taken. For example, would powering down the instrument  (or changing direction etc.) that took the image, cause you to lose the image that you took with it (cause hasImage() to return false).
No, once an image has been taken, it is stored on a hard drive, i.e., it cannot be lost no matter what satellite does.

I was just wondering if we would have to make our satellite turnTo the direction of a space station before calibrating an instrument.
Before action runCalibrateProc() for an instrument can be executed, your satellite has to turn not to a space station, but to one of the available ground stations mentioned in the initial situation. This is because powering an instrument up makes it uncalibrated. There might be different or same ground station targets for different tools. These targets help to calibrate a tool. You have to implement the correct precondition rule for the action runCalibrateProc(), as described in the assignment.

Just to clarify further, can the satellite turn to any arbitrary ground centre before calibration, or only to the ground centre related to the instrument about to turn on?
To calibrate a tool properly, the satellite should turn to the ground station supporting calibration of that tool.