Test Goals

A test goal checks whether the agent believes something. Unlike other ways of checking beliefs, a test goal does not have to give up when the agent does not know the answer: it gives the agent a chance to find out, by running a plan.

A test goal is written as ? followed by a formula:

?price("apple", int P);

How a test goal is evaluated

When a plan reaches a test goal, ASTRA does the following:

  1. It checks the agent’s beliefs, including any inference rules. If the formula holds, the test goal succeeds straight away, any variables in it (such as P above) are bound, and the plan continues with the next statement.

  2. If the formula does not hold, it raises a test goal event (+?price("apple", P)) and suspends the plan until the event has been handled.

  3. The event is handled by a test goal plan whose triggering event matches, in the same way as a sub-goal is handled by a goal plan. When that plan finishes, the test goal succeeds and the original plan continues.

  4. If no plan can handle the event, or the plan fails, the test goal fails, and so does the plan that contains it. This is reported as a failure of the enclosing goal, so it can be handled with a ^!goal(...) plan.

Writing test goal plans

A test goal plan has a triggering event that starts with +?:

plan +?price(string Item, int Price) : catalogue(Item, int Q) {
    Price = Q;
    +price(Item, Price);
}

A test goal plan should do two things:

  • Bind the variables in its triggering event. The values of the head variables (here Price) are passed back to the test goal, in the same way that results are passed back from a sub-goal. If the plan does not bind them, they are still unbound when the original plan continues.

  • Usually, add the belief that it has found out. The next time the agent tests the same formula, the belief is already held, so the plan is not needed again.

Use the plan’s context to say when it can find the answer: if no test goal plan is applicable, the test goal fails.

Example

This agent knows the price of apples, and has a catalogue in which it can look up the price of other items. It shows the price of four items, one of which is in neither place:

agent Prices {
    module Console C;
    module System S;

    types prices {
        formula price(string, int);
        formula catalogue(string, int);
    }

    initial price("apple", 10);
    initial catalogue("pear", 15), catalogue("fig", 20);

    plan +!main(list args) {
        !show("apple");
        !show("pear");
        !show("pear");
        !show("kiwi");
        S.exit();
    }

    plan +!show(string Item) {
        ?price(Item, int P);
        C.println(Item + " costs " + P);
    }

    plan ^!show(string Item) {
        C.println("no price for " + Item);
    }

    plan +?price(string Item, int Price) : catalogue(Item, int Q) {
        C.println("looking up " + Item + " in the catalogue");
        Price = Q;
        +price(Item, Price);
    }
}
[main] apple costs 10
[main] looking up pear in the catalogue
[main] pear costs 15
[main] pear costs 15
[main] no price for kiwi
  • The price of apples is a belief, so the first test goal succeeds without using a plan.

  • The price of pears is not, so the test goal plan looks it up and adds it as a belief. The second time, the belief is used directly.

  • Kiwis are not in the catalogue, so the test goal plan is not applicable. The test goal fails, the !show("kiwi") goal fails, and the ^!show(...) plan handles the failure.

Test goals compared with other checks

ASTRA has several ways of checking a formula against the agent’s beliefs. They differ in what happens when the formula does not hold:

Statement

If the formula holds

If it does not hold

if (f) { ... }

Runs the if branch, with the variables in f bound

Runs the else branch (if any)

query(f);

Continues, with the variables in f bound

Fails the plan, without trying to find out

?f;

Continues, with the variables in f bound

Raises a +?f event so that a test goal plan can find out; fails if none can

wait(f);

Continues, with the variables in f bound

Suspends the plan until f holds (or until an optional timeout)

Use a test goal when not knowing something is a problem that the agent may be able to solve. Use query(...) when the information must already be known, if when the agent should behave differently depending on whether it is known, and wait(...) when it will become known later, for example through perception. The Practical Reasoning Programming Style uses test goals and wait(...) to confirm that a goal has been achieved.

Things to know

  • A test goal plan is trusted. When a test goal plan finishes, the test goal succeeds: ASTRA does not check the formula again. If the plan might finish without finding the answer, end it with a query(...) on the belief, so that the plan (and therefore the test goal) fails when the answer was not found:

    plan +?price(string Item, int Price) {
        // ... try to find the price ...
        query(price(Item, int Found));
        Price = Found;
    }
    
  • Results come from the head variables. A test goal is bound from the beliefs when it succeeds straight away, but from the test goal plan’s head variables when a plan is used. Binding those variables in the plan is what makes the answer available to the plan that asked.