Exercise 1
Set up a Bill of Materials (BOM) beliefset.
Introduction
In this exercise you will create a simplified BOM beliefset to be used within a Planner agent. A BOM is a data structure used in manufacturing to describe the component/subcomponent structure of part assemblies. In this tutorial, the BOM will only capture the component/subcomponent structure: in practice, it will contain much more information, such as the number of a particular component that is required, whether the component is made internally or is outsourced etc.
You will also create a main program to read BOM data provided by the user. This information will be stored in a JACK beliefset which is private to the Planner agent. An alternative mechanism for initialising the beliefset is to use a JACOB file. This alternative is used in Exercise 5.
Instructions
1. Create a directory called practical2/ex1. In this directory, start the JDE and open a new project called BOM.
2. Create a beliefset type called BOM:
- Open the Data Model container in the browser.
- Right-click on the Beliefset Types folder and select Add New Beliefset Type from the pop-up menu. Call the beliefset BOM and add it to the bom package. It is to have two key fields of type String. One field is used to store a component type, and the other field is used to store a subcomponent type. This means that in this beliefset there will be n entries per component, where n is the number of subcomponent types that are used to build that component. Note that we distinguish between subcomponent types and subcomponents. For example, a table may have two subcomponent types (top and leg) but five subcomponents (one top and four legs).
- Use the Edit as JACK File option to add the two key fields and a getSubcomponent query to the beliefset. In Exercise 2 the getSubcomponent query will be used to find a subcomponent of a given component. This means that the subcomponent field is to be an output field in the query. Although this query is not required until Exercise 2, it is added now because a JACK beliefset must have at least one query. Your BOM beliefset should be similar to the following:
package bom; public beliefset BOM extends OpenWorld { #key field String component; #key field String subcomponent; #indexed query getSubcomponent(String component, logical String subcomponent); }
3. We will now use the design tool to define an agent, Planner, that will store component/subcomponent tuples in a private beliefset of type BOM:
- Create a new design diagram called Planner_AD.
- Drag a new agent onto the Planner_AD design canvas. It is to be called Planner and it is to be in the bom package.
- Drag the Named Data icon from the design palette onto the design canvas. The named data is to be called bom and is to be of type bom.BOM.
- Create a private link from the Planner agent to the bom named data on the design canvas.
4. The beliefset will be populated at agent construction time. Consequently the agent's constructor will be passed two strings – the agent's name and the name of a file containing component-subcomponent details. The constructor must read each component-subcomponent relation from the file, and add the information to the agent's BOM beliefset. The code to achieve this can be added to the agent by using the browser to edit the agent as a JACK file. Sample code for the constructor follows:
public Planner(String name, String filename) { super(name); StringTokenizer tokens; String record; String t1,t2; BufferedReader datafile = null; try { datafile = new BufferedReader(new FileReader(filename)); } catch (FileNotFoundException e) { System.err.println("unable to open file "+e.toString()); System.exit(1); } try { while ((record = datafile.readLine())!=null) { tokens = new StringTokenizer(record); t1 = tokens.nextToken(); t2 = tokens.nextToken(); bom.add(t1,t2); } }
catch (Exception e) { System.err.println("error reading bom data into beliefset"); System.exit(1); } }
Make sure that the Planner agent has the following import statements:
import java.io.*; import java.util.*;
5. Add a new file called Program.java to the Other Files folder in the browser. It will create a Planner agent, perhaps as follows:
import java.io.*; import bom.Planner; public class Program { public static void main( String args[] ) { Planner planner = new Planner("planner1","bom.dat"); System.exit(0); } }
If you wish to run the project from within the JDE make sure that you use the full pathname for bom.dat.
6. Create the file bom.dat and populate it with component/subcomponent records. It could contain:
chair back chair seat chair leg chair arm table top table leg cupboard door cupboard drawer cupboard leg cupboard cabinet
7. Compile and run the program. No output is generated by the program at this stage, but it provides the basis for the remaining exercises.
Exercise 2
Use the indexed query to find a component's subcomponents.
Introduction
This step involves the use of indexed queries and a plan with a context() method to print out one of the subcomponents of a component. Initially we use a BDIGoalEvent so that only the first successful applicable plan is executed. This means that if we post only one event (e.g. find a subcomponent of component X), the first plan to have a context that finds a binding for a subcomponent of X will be executed. In that case we will only find (at most) one subcomponent.
Instructions
1. Open the Planner_AD design diagram and
- Drag a new event from the design palette onto the design canvas. This event is to be called FindSubcomponent and is to be added to the bom package.
- Create the following links with the Planner agent:
- A handles link from the FindSubcomponent event;
- A posts link to the FindSubcomponent event;
2. In the Planner_AD design diagram:
- Add a new plan called FindSubcomponentPlan that is in the bom package.
- Create a handles link between the FindSubcomponent event and the FindSubcomponentPlan plan.
- Create a uses link from the plan to the bom named data.
- Create a uses link from the Planner agent to the FindSubcomponentPlan plan.
3. Edit the FindSubcomponent event so that it:
- extends BDIGoalEvent;
- has a String data member component; and
- includes a posting method findSubcomponent(String component) that assigns data to the component data member.
4. Edit the FindSubcomponentPlan plan so that it
- Has a logical variable logical String $subcomp;
- Includes a context method that uses the BOM beliefset's getSubcomponent() query to find a subcomponent for the component passed in with the event. $subcomp is passed into the query. (Note: the plan will only be applicable if the getSubcomponent() query can find an entry for the component in the BOM beliefset);
- Includes a print statement similar to the following in the body of the plan:
System.out.println($subcomp.getValue()+" is a subcomponent of " +ev.component);
5. Modify the Planner agent so that it contains a findSubcomponent(String component) method which will post a FindSubcomponent event using postEventAndWait().
6. Modify the main program so that it makes several invocations of the Planner agent's findSubcomponent() method with the name of a component that is in the agent's BOM beliefset. Ensure that for at least one of the invocations the component is composed of several subcomponent types.
7. Compile and run the program.
Questions
1. Why aren't all the component's subcomponents printed out?
Exercise 3
Use the InferenceGoalEvent class instead of BDIGoalEvent.
Introduction
In this example, you will use an InferenceGoalEvent instead of the BDIGoalEvent. This illustrates two concepts. The first is the difference between these two types of event (i.e. the InferenceGoalEvent will cause all applicable plans to be executed). Secondly, it shows that there is a separate plan instance generated in the applicable set for each of the possible bindings in the context method. This means that in this example we will see all the subcomponents being printed. A separate plan instance will be responsible for printing the message about each subcomponent.
Instructions
1. Modify the FindSubcomponent event so that it is an InferenceGoalEvent and not a BDIGoalEvent.
2. Compile and test the program. The tests should involve at least one component which is composed of four or more subcomponents.
Exercise 4
Use a beliefset callback method.
Introduction
In this exercise you add an order beliefset to your Planner agent and use a beliefset callback method to post a FindSubcomponent event to the agent. This will result in a list of subcomponents being printed for the required new component.
Instructions
1. Use the JDE to create a new beliefset type called Orders that belongs to the bom package. It will have one key field (String orderId) and three non-key fields (String component, int numberRequired, String date). Add at least one query to the beliefset.
2. Open the Planner_AD design diagram and
- Drag a new named data component from the design palette onto the design diagram canvas. Call the named data orders and set its type to be bom.Orders.
- Create a private link from the Planner agent to the orders named data.
3. Modify the Planner agent so that it contains a new method addOrder(String orderId, String component, int numberRequired, String dueDate) that will add a new order into the orders beliefset. Note that the add() method may throw a BeliefSetException, so add must be invoked from inside a try/catch block. You will also need to import aos.jack.jak.beliefset.BeliefSetException. Your addOrder() method should be similar to the following:
public void addOrder(String id, String comp, int n, String dd) { try { orders.add(id,comp,n,dd); } catch (BeliefSetException e) { System.err.println("error entering data in orders db"); System.exit(1); } }
4. Edit the Orders beliefset type and
- add a #posts event FindSubcomponent ev; declaration;
- Add an indexed query that accepts the order ID (String), component type (logical String), number of components required (logical int) and the order date (logical String).
- Add a newfact callback to the orders beliefset. Each time a new fact is added to the beliefset, the callback will print a trace message to indicate that a new order has been added to the beliefset and then post a FindSubcomponent event. An example of a beliefset that includes a newfact callback can be found in the Politician example in the introductory notes.
5. Modify the main program so that it:
- includes the following import statement:
import java.util.*;
- no longer invokes the Planner agent's findSubcomponent method;
- no longer exits; and
- reads in the order data from a datafile and invokes the Planner agent's addOrder method to add the details to the beliefset. Sample code for this follows:
StringTokenizer tokens; String record; String t1,t2,t3,t4; BufferedReader datafile = null; Planner planner = new Planner("planner1","bom.dat"); try { datafile = new BufferedReader(new FileReader("orders.dat")); } catch (FileNotFoundException e) { System.err.println("unable to open file "+e.toString()); System.exit(1); } try { while ( (record = datafile.readLine()) != null ) { tokens = new StringTokenizer(record); t1 = tokens.nextToken(); t2 = tokens.nextToken(); t3 = tokens.nextToken(); t4 = tokens.nextToken(); planner.addOrder(t1,t2,Integer.parseInt(t3),t4); } } catch (Exception e) { System.err.println("error reading orders data "); System.exit(1); }
6. Create a data file that contains several orders. At least one order should be for a component that has four or more subcomponents.
7. Compile and run the program.
Exercise 5
Use a JACOB initialisation file to initialise the BOM beliefset.
Introduction
In this exercise, you will modify the Planner agent's constructor so that it no longer reads the data from the text file used in the earlier exercises. Instead, you will create a file in JACOB ASCII format that is read in either when the beliefset is constructed, or by using the beliefset read method in the agent's constructor.
Instructions
1. Edit the Planner.agent and remove the code to read the BOM data from the filename passed into the constructor.
2. Modify the #private data BOM bom() declaration so that the filename is now passed to the BOM constructor (#private data BOM bom("bom.dat")).
3. Edit the file bom.dat so that it contains the data in JACOB ASCII format. An example data file is shown below.
<TupleTable :tuples( <BOM__Tuple :component "table" :subcomponent "leg" > <BOM__Tuple :component "table" :subcomponent "table_top" > ) >
4. Compile and run the program.
5. It is also possible to explicitly invoke the beliefset's read method to read data in JACOB ASCII format. This means that the filename can then be passed as a parameter to the agent's constructor.
- If necessary, modify the Planner.agent so that the filename is passed in to its constructor.
- Add the line
bom.read(filename);
-
in the Planner agent's constructor.
- Remove the filename from the #private data BOM bom("bom.dat") declaration.
- Compile and run the program.