Homework 2 - Coding Robot Behaviors

Solution

  1. Examine the code that starts on page 79 and carries over onto page 80.

    1. Find the undeclared variables and correct them.

      Both parent and child are undeclared. However, only one of these really needs to be used in the code. You can decide which you would like to use. (The variable child matches better with the enumerated type Releaser, which has possible values PRESENT and NOT_PRESENT -- if the agent has a child present it should nurse that child. On the other hand, the variable parent matches better with the method name checkStateParent(), in which the agent apparently checks whether it is a parent or not -- an odd thing to check every couple of seconds!)

      Whichever you decide to use in the code should be declared and used throughout the code. The other should be removed.

    2. Explain how the code conflicts with the statement on page 79 that it "shows what happens in a sequence of behaviors, where the agent eats, then nurses its young, then sleeps, and repeats the sequence." Correct this statement to match the code.

      There are at least two major conflicts with this claim.

      1. The statement fails to mention one of the activities in which the agent engages -- searching for food.
      2. The code does not describe any particular sequence of actions. Instead, the code shows a set of behaviors and releasers that could result in a particular sequence of actions but could just as well result in other sequences.

        For example, if the agent becomes hungry while nursing, it will not complete nursing and move on to sleeping. Instead, it will go back to searching for food and, if food is present, feeding.

        Similarly, if nursed becomes NOT_PRESENT (false) while the agent is sleeping and is not hungry, it will not go back to eating (or searching for food). Instead, it will either nurse or do nothing, depending on whether or not child (or parent, if you decided to use that variable name) is PRESENT.

      Note that these two conflicts come together in a particularly bad way with respect to describing a single sequence of actions that involves searching for food, feeding, etc. This is because, if the agent is hungry and food is present, it will repeat the sub-sequence search then eat (every few seconds) until it is no longer hungry or food is no longer present (however may repetitions this may take). This sub-sequence may or may not have sleeping interleaved with it, depending on whether or not nursed is PRESENT(true).

      (Besides making it difficult to describe as a sequence, this is probably a bad set of releasers and behaviors for an agent to have. Going through a cycle of sleeping, searching for food, and eating all in a matter of seconds, as can happen with this code, is probably not very restful. Nor is searching for food when there is an abundance of food already present, as can happen when the agent is hungry, likely to be a good approach -- it would probably be better off eating then and only searching when no food is present. One could also argue that sleeping should only require having completed nursing if there is a child present. If the agent has no child, nursing should not be a prerequisite. Only if nursed is PRESENT is necessarily true when child is NOT_PRESENT -- an odd way to represent this state of affairs in the world -- will this work out well for the agent.)

      A better statement is that this code shows behaviors where the agent variously searches for food, eats, nurses its young, and sleeps, depending on its circumstances.

    3. Explain how the code conflicts with the statement on page 79 that "[i]f the behavior isn't finished, the releasers remain unchanged and no other behavior is triggered." Correct the code to match this statement.

      The first step needed to make the code match this statement, is to make the make the releasers mutually exclusive. So, for example, we can add the releaser code food==NOT_PRESENT to searchForFood() and the releaser code hungry==NOT_PRESENT to sleep, so that the agent will only feed when hungry and food is present, rather than interleaving searching and sleeping.

      The second step needed is to prevent other factors from changing the releasers. In the current set up, it must be the case that something other than the methods shown cause the agent to become hungry, as none of the methods show that as a result. We would need to prevent that something from happening. (This isn't shown in the code, therefore we can't show its removal in the code.) However, if we do that, we'll also need to have completion of a behavior cause hungry to become PRESENT, otherwise the agent will never get hungry. So, for example, a result of completing sleeping could be that the agent is now hungry. (We could show this as a comment in the code.)

      (Note that, while we can make the code match this statement, we probably shouldn't. One of the strengths of the approach is that the agent ought to be able to respond to changes in the environment that aren't simply the result of completing various tasks. What if the agent runs out of food before it is full, for example? So, to have the releasers remain necessarily unchanged until a behavior is finished is in conflict with a sensor-based approach to action.)

    4. Explain how the code conflicts with the statement on page 80 that "[i]f the agent sleeps and wakes up, but isn't hungry ... the agent will just sit there until it gets hungry." Correct this statement to match the code.

      First, what does the phrase "wakes up" mean? Presumably it doesn't just mean that the agent has slept for two seconds and cycled back up to the top of the loop. Probably it is intended to mean something like "has had enough sleep for now." Unfortunately, there is no releaser in the code that relates to this concept. In the code, the agent simply sleeps when it has finished nursing. The agent will only stop its repeated two second "micro cat naps" (if you will) when nursed becomes NOT_PRESENT (for some reason left unspecified). However, for the sake of argument, assume that "wakes up" means that nursed has become NOT_PRESENT.

      Given this assumption, if the agent wakes up but isn't hungry, it will do nothing iff (if and only if) all of the releaser clauses evaluate to false. However, it is very possible that the releaser clause for nursing will evaluate to true (we know the agent is not hungry and if there is a child present, then this will evaluate to true), in which case the agent will nurse.

      A more accurate statement is that if the agent finds that it is time to nurse (nursed is NOT_PRESENT) but there is no child present and the agent is not hungry, it will do nothing.

      (Note that, while that statement matches the code, it shows that the set of behaviors and releasers specified in the code probably represent a poor set up for an agent to follow. If it is time to nurse but no child is present, the agent should probably find the child.)

  2. Examine the code that starts on page 81 and carries over onto page 82.

    1. Find the undeclared variable and correct it. (Note that is same variable was undeclared in the code found entirely on page 80.)

      Here, parent is left undeclared.

    2. On page 82 there is a statement that in this code "each behavior takes control and runs to completion." (This would only be true if the functions called were modified.) This is a problem, claims the author, because "the agent cannot react to a predator until it has finished the sequence of behaviors." Would her proposed solution that "[c]alls to the fleeing behavior could be inserted between each behavior" really make things better? Explain your answer. Would her proposed solution that "fleeing could be processed on an interrupt basis" really make things better? Explain your answer.

      Inserting calls to the fleeing behavior between the behaviors listed is unlikely to help an agent. The only cases in which this would help are those in which the predator happens to arrive just after the agent has completed one behavior from the search-feed-nurse-sleep list and before it has begun another of them. This is quite unlikely, assuming that it takes more than a couple of seconds for the agent to actually complete one of these behaviors. Much more likely is that the predator will arrive while the agent is in the middle of one of these behaviors and kill the agent as it continues to search for food, feed, nurse, or sleep.

      On the other hand, processing interrupts would certainly help. Interrupts can occur at the rate at which the agent's clock ticks, quite probably fractions of a second, although if the agent's predator detection scheme is in software, it would need to run as a separate process or thread. Nonetheless, multitasking or multithreading this with any of the other behaviors could give the agent at least as good a response time as the previous version of the code (from page 80).

    3. The author claims that starting with an explicit sequence of behaviors then adding fixes, such as processing interrupts, make "the program less general purpose and harder to add [to] and maintain." Comment on this statement, in light of the difficulty the author had in matching code and text for the implicit sequence version that you corrected above.

      You are, of course, free to reach your own conclusions here, but I think that some things are pretty clear:

      1. While people have a tendency to think in terms of sequences, it is a poor idea to try to think of programs written in the reactive paradigm as describing sequences. If you cannot get away from thinking in terms of sequences, you will have trouble adding to and maintaining such programs. (The author gets herself into trouble because she is stuck thinking about sequences, when repeating the same sequence over and over isn't what her programs are intended to do.)
      2. Reactive programs tend to be very special purpose -- all the discussion of "ecological niches" should make it clear that these programs are not "general purpose problem solvers."
      3. If you want to have your robot carry out an explicit sequence of actions, it is much easier to simply code them up as such. Further, there is nothing special purpose about interrupts -- a dedicated process or thread that signals the sequential behavior loop when any given percept is detected can be as general as desired.

      In my opinion, the strength of programming in the reactive paradigm is not that it makes programming particular sequences of actions easy. Rather, it is because we will often want our robots to determine their next actions based on their current percepts, not what they did last, that the reactive paradigm is often appropriate. That is, since we don't know until runtime which sequence the robot should follow, we use the reactive paradigm rather than trying to explicitly program in a sequence.