View Javadoc

1   /*
2   * The contents of this file are subject to the BT "ZEUS" Open Source 
3   * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file 
4   * except in compliance with the Licence. You may obtain a copy of the Licence
5   * from $ZEUS_INSTALL/licence.html or alternatively from
6   * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7   * 
8   * Except as stated in Clause 7 of the Licence, software distributed under the
9   * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or 
10  * implied. See the Licence for the specific language governing rights and 
11  * limitations under the Licence.
12  * 
13  * The Original Code is within the package zeus.*.
14  * The Initial Developer of the Original Code is British Telecommunications
15  * public limited company, whose registered office is at 81 Newgate Street, 
16  * London, EC1A 7AJ, England. Portions created by British Telecommunications 
17  * public limited company are Copyright 1996-9. All Rights Reserved.
18  * 
19  * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20  */
21  
22  
23  
24  package zeus.actors;
25  
26  import java.util.*;
27  import zeus.util.*;
28  import zeus.concepts.*;
29  
30  public class Decomposition extends Hashtable {
31     protected Vector constraints;
32     // REM constraints don't seem to be enforced yet!?
33     protected Vector links;
34     protected int node_pointer = -1;
35     protected String root = null;
36     protected Vector nodeList = new Vector();
37     protected Planner planner = null;
38  
39  
40     // meaningless init  to allow rearch
41     public Decomposition () {
42     ;
43     }
44  
45     public Decomposition(Planner planner, String key, PlanRecord parent,
46                          Vector path, Goal goal, SummaryTask task) {
47  
48        this.planner = planner;
49        links = task.links();
50        constraints = task.constraints();
51  
52        boolean first_time = true;
53        String rightNode, leftNode;
54        Enumeration enum;
55        TaskLink link;
56        Hashtable pairs = new Hashtable();
57        KeyValue st;
58        Vector temp, curr = new Vector();
59        curr.addElement(TaskNode.END);
60        int count = 0;
61        while( !curr.isEmpty() ) {
62           temp = new Vector();
63           enum = links.elements();
64           while( enum.hasMoreElements() ) {
65              link = (TaskLink)enum.nextElement();
66              rightNode = link.getRightNode();
67              if ( curr.contains(rightNode) ) {
68                 leftNode = link.getLeftNode();
69                 if ( !leftNode.equals(TaskNode.BEGIN) ) {
70                    if ( !temp.contains(leftNode) )
71                       temp.addElement(leftNode);
72  
73                    if ( !this.containsKey(leftNode) ) {
74                       this.add(task.getNode(leftNode));
75                       st = new KeyValue(leftNode,count++);
76                       Assert.notFalse( pairs.put(st.key,st) == null );
77                    }
78                    else {
79                       st = (KeyValue)pairs.get(leftNode);
80                       st.value = (double)count++;
81                    }
82  
83                    this.addParentNode(leftNode,rightNode);
84                 }
85              }
86           }
87           if ( first_time ) {
88              determineRoot(key,parent,path,goal,temp);
89              first_time = false;
90           }
91           curr = temp;
92        }
93  
94        // Finally remove all TaskNode.BEGIN & TaskNode.END
95        enum = links.elements();
96        while( enum.hasMoreElements() ) {
97           link = (TaskLink)enum.nextElement();
98           if ( link.referencesNode(TaskNode.BEGIN) ||
99  	      link.referencesNode(TaskNode.END) )
100             links.removeElement(link);
101       }
102 
103       // Then setup node iterator
104       KeyValue tmp = new KeyValue();
105       KeyValue[] data = new KeyValue[pairs.size()];
106       enum = pairs.elements();
107       for(int i = 0; enum.hasMoreElements(); i++ )
108          data[i] = (KeyValue)enum.nextElement();
109 
110       // sort data
111       boolean swapped = true;
112       while( swapped ) {
113          swapped = false;
114          for( int i = 0; i < data.length-1; i++ ) {
115             if ( data[i].value > data[i+1].value ) {
116                tmp.set(data[i]);
117                data[i].set(data[i+1]);
118                data[i+1].set(tmp);
119                swapped = true;
120             }
121         }
122       }
123       for(int i = 0; i < data.length; i++ )
124          nodeList.addElement(data[i].key);
125       node_pointer = 0;
126    }
127 
128    protected void determineRoot(String key, PlanRecord parent, Vector path,
129                                 Goal goal, Vector candidates) {
130 
131       Assert.notFalse(candidates.size() == 1);
132       Fact f1 = goal.getFact();
133       String nodeId;
134       Fact[] produced;
135       DecompositionStruct struct;
136       Bindings b = new Bindings(planner.getAgentContext().whoami());
137       for(int i = 0; i < candidates.size(); i++ ) {
138          nodeId = (String)candidates.elementAt(i);
139          struct = (DecompositionStruct)this.get(nodeId);
140          produced = struct.node.getPostconditions();
141          for(int j = 0; j < produced.length; j++, b.clear()) {
142             if ( !produced[j].isSideEffect() && produced[j].unifiesWith(f1,b) ) {
143                struct.node.resolve(b);
144                root = nodeId;
145                struct.key = key;
146                struct.goal = new Goal(goal);
147                struct.parent_record = parent;
148                struct.path = path;
149                return;
150             }
151          }
152       }
153    }
154 
155    protected void add(TaskNode node) {
156       DecompositionStruct struct;
157       struct = new DecompositionStruct(planner.getAgentContext().whoami(),node);
158       Assert.notFalse( put(node.getName(),struct) == null);
159    }
160 
161    protected void addParentNode(String childId, String parentId) {
162       if ( parentId.equals(TaskNode.END) ) return;
163       DecompositionStruct struct = (DecompositionStruct)get(childId);
164       if ( !struct.parents.contains(parentId) ) {
165          struct.parents.addElement(parentId);
166          addChildNode(parentId,childId);
167       }
168    }
169    protected void addChildNode(String parentId, String childId) {
170       if ( childId.equals(TaskNode.BEGIN) ) return;
171       DecompositionStruct struct = (DecompositionStruct)get(parentId);
172       if ( !struct.children.contains(childId) )
173          struct.children.addElement(childId);
174    }
175 
176    public synchronized String nextNode() {
177       String nodeId;
178       if ( node_pointer < nodeList.size() ) {
179          nodeId = (String)nodeList.elementAt(node_pointer++);
180          Core.DEBUG(2,"nextNode(): id = " + nodeId);
181          return allParentsScheduled(nodeId) ? nodeId : nextNode();
182       }
183       return null;
184    }
185    public synchronized void reset() {
186       node_pointer = 0;
187    }
188 
189    protected TaskLink findLink(String left, String right) {
190       TaskLink link;
191       Enumeration enum = links.elements();
192       while( enum.hasMoreElements() ) {
193          link = (TaskLink)enum.nextElement();
194          if ( link.getLeftNode().equals(left) &&
195               link.getRightNode().equals(right) ) return link;
196       }
197       return null;
198    }
199 
200    protected boolean allParentsScheduled(String nodeId) {
201       String parentId = null;
202       DecompositionStruct struct, st, pt;
203       struct = (DecompositionStruct)get(nodeId);
204       for(int i = 0; i < struct.parents.size(); i++ ) {
205          parentId = (String)struct.parents.elementAt(i);
206          st = (DecompositionStruct)get(parentId);
207          Core.DEBUG(2,"allParentsScheduled(): nodeId = " + nodeId +
208                            " parentId = " + parentId + " parent.scheduled = " +
209                            st.scheduled);
210          if ( !st.scheduled ) return false;
211       }
212 
213       if ( struct.parents.isEmpty() || struct.goal != null )
214          return true;
215 
216       // First, nominate one of your parents as the primary parent
217       struct.current_parent = (String)struct.parents.elementAt(0);
218       pt = (DecompositionStruct)get(struct.current_parent);
219       struct.parent_record = pt.record;
220 
221       // Next, set your key to that of your primary parent
222       struct.key = pt.key;
223 
224       // Next, determine link to primary parent
225       TaskLink link = findLink(nodeId,struct.current_parent);
226       struct.parent_link = link.getId();
227 
228       // Next, set your primary goal to be a subgoal of your primary parent
229       Fact produced = null;
230       produced = pt.node.getPrecondition(link.getRightGroup(),link.getRightArg());
231 
232       if ( pt.record == null ) {
233          // external contract
234          struct.goal = new Goal(pt.image.whichType(),
235                                 planner.getAgentContext().newId("subgoal"),
236                                 produced,
237                                 planner.getAgentContext().whoami());
238 
239          if ( pt.image.isContinuous() ) {
240             int s = pt.image.getStartTime();
241             int e = pt.image.getEndTime();
242             int n = pt.image.getInvocations();
243             int u = (e-s)/n;
244             struct.goal.setStartTime(s);
245             struct.goal.setEndTime(e - u);
246             struct.goal.setInvocations(n);
247          }
248          else {
249             struct.goal.setEndTime(getStartTime(link,pt));
250          }
251          struct.goal.setConfirmTime(pt.image.getConfirmTime());
252          struct.goal.setPriority(pt.image.getPriority());
253          struct.goal.setCost(0);
254          struct.goal.setRootId(pt.image.getRootId());
255       }
256       else {
257          Task task = pt.record.getTask();
258          Fact[] consumed = task.getPreconditions();
259          Bindings b = new Bindings(planner.getAgentContext().whoami());
260          boolean found = false;
261          for(int i = 0; !found && i < consumed.length; i++, b.clear()) {
262             if ( produced.unifiesWith(consumed[i],b) ) {
263                struct.goal = pt.record.createSubgoal(consumed[i],i);
264                found = true;
265             }
266          }
267          Assert.notFalse(found);
268       }
269       int start = struct.goal.getStartTime();
270       int end = struct.goal.getEndTime();
271       // now adjust times so that current struct precedes all its parents
272       TaskLink link1;
273       for(int i = 0; i < struct.parents.size(); i++ ) {
274          parentId = (String)struct.parents.elementAt(i);
275          st = (DecompositionStruct)get(parentId);
276          link1 = findLink(nodeId,parentId);
277          if ( st.record == null ) {
278             if ( st.image.isContinuous() ) {
279                int s = st.image.getStartTime();
280                int e = st.image.getEndTime();
281                int n = st.image.getInvocations();
282                int u = (e-s)/n;
283                start = Math.min(start,s);
284                end = Math.min(end,e-u);
285             }
286             else {
287                end = Math.min(end,getStartTime(link1,st));
288             }
289          }
290          else {
291             if ( st.goal.isContinuous() ) {
292                 start = Math.min(start,st.record.getStartTime());
293                 end = Math.min(end,st.record.getEndTime() -
294                                st.record.getTask().getTime());
295             }
296             else {
297                end = Math.min(end,st.record.getStartTime());
298             }
299          }
300       }
301 
302       struct.goal.setEndTime(end);
303       if ( struct.goal.isContinuous() )
304          struct.goal.setStartTime(start);
305 
306       // Now, compute path
307       struct.path = Misc.copyVector(pt.path);
308       struct.path.addElement(pt.goal.getFact());
309 
310       // Finally remove primary link;
311       links.removeElement(link);
312       return true;
313    }
314 
315    protected int getStartTime(TaskLink link, DecompositionStruct struct) {
316       String itemId = (String)struct.lookupTable.get(link.getId());
317       SuppliedItem item = struct.given.getSuppliedItem(itemId);
318       return item.getEarliestReservationTime();
319    }
320    protected String[] getReservationId(TaskLink link,
321                                        DecompositionStruct struct) {
322       String itemId = (String)struct.lookupTable.get(link.getId());
323       SuppliedItem item = struct.given.getSuppliedItem(itemId);
324       return item.getReservationId();
325    }
326 
327    public Fact[] getPreconditions(String node) {
328       DecompositionStruct struct = (DecompositionStruct)this.get(node);
329       return struct.node.getPreconditions();
330    }
331    public Fact[] getPostconditions(String node) {
332       DecompositionStruct struct = (DecompositionStruct)this.get(node);
333       return struct.node.getPostconditions();
334    }
335 
336    public Vector getPath(String node) {
337       DecompositionStruct struct = (DecompositionStruct)this.get(node);
338       return struct.path;
339    }
340    public Goal getGoal(String node) {
341       DecompositionStruct struct = (DecompositionStruct)this.get(node);
342       return struct.goal;
343    }
344    public String getKey(String node) {
345       DecompositionStruct struct = (DecompositionStruct)this.get(node);
346       return struct.key;
347    }
348    public PlanRecord getParentRecord(String node) {
349       DecompositionStruct struct = (DecompositionStruct)this.get(node);
350       return struct.parent_record;
351    }
352 
353    public void setRecords(String node, Vector records) {
354       DecompositionStruct st = (DecompositionStruct)this.get(node);
355       st.records = records;
356       st.record = (PlanRecord)records.elementAt(0);
357       st.scheduled = true;
358 
359       if ( node.equals(root) ) return;
360 
361       DecompositionStruct pt = (DecompositionStruct)this.get(st.current_parent);
362       if ( pt.record == null ) {
363          String itemId = (String)pt.lookupTable.get(st.parent_link);
364          SuppliedItem item = pt.given.getSuppliedItem(itemId);
365          String[] refs = item.getReservationId();
366 
367          String consumer, consumer_id;
368          String comms_key;
369          int amount, start;
370          boolean consumed;
371 
372          String producer = st.agent;
373          String producer_id = st.record.getGoal().getId();
374          for(int i = 0; i < refs.length; i++ ) {
375             consumer = item.getReservingAgent(refs[i]);
376             consumer_id = item.getReservationGoalId(refs[i]);
377             comms_key = item.getReservationCommsKey(refs[i]);
378 
379             amount = item.getReservedAmount(refs[i]);
380             start = item.getReservationTime(refs[i]);
381             consumed = item.isReservationConsumed(refs[i]);
382             Assert.notFalse(amount > 0);
383 
384             pt.image.addProducer(itemId, refs[i], comms_key,
385                                  producer, producer_id, consumer, consumer_id);
386 
387             st.record.getProducedDb().replaceOrAdd(
388                st.goal.getId(),
389                consumer_id + "/" + refs[i], start, amount, consumed );
390          }
391       }
392    }
393    public boolean allNodesScheduled() {
394       DecompositionStruct struct;
395       Enumeration enum = this.elements();
396       while( enum.hasMoreElements() ) {
397          struct = (DecompositionStruct)enum.nextElement();
398          if ( !struct.scheduled ) return false;
399       }
400       return true;
401    }
402    public void setQueued(String node, boolean set) {
403       DecompositionStruct struct;
404       struct = (DecompositionStruct)get(node);
405       struct.queued = set;
406    }
407    public boolean isQueued(String node) {
408       DecompositionStruct struct;
409       struct = (DecompositionStruct)get(node);
410       return struct.queued;
411    }
412    public boolean isScheduled(String node) {
413       DecompositionStruct struct;
414       struct = (DecompositionStruct)get(node);
415       return struct.scheduled;
416    }
417    public PlanRecord getRecord(String node) {
418       DecompositionStruct struct = (DecompositionStruct)this.get(node);
419       return struct.record;
420    }
421    public PlanRecord getRootRecord() {
422       DecompositionStruct struct = (DecompositionStruct)this.get(root);
423       return struct.record;
424    }
425 
426    public String getNodeWithGoalId(String goalId) {
427       Core.DEBUG(3,"getNodeWithId\n" + this);
428       DecompositionStruct struct;
429       Enumeration enum = this.elements();
430       while( enum.hasMoreElements() ) {
431          struct = (DecompositionStruct)enum.nextElement();
432          if ( struct.goal != null &&
433               struct.goal.getId().equals(goalId) )
434             return struct.node.getName();
435       }
436       return null;
437    }
438    public void setImage(String node, Goal image, String agent,
439                         String delegation_key) {
440       Core.DEBUG(3,"SetImage: node = " + node);
441       Core.DEBUG(3,"SetImage: image = " + image);
442       DecompositionStruct st = (DecompositionStruct)this.get(node);
443       Core.DEBUG(3,"SetImage: st = " + st);
444       SuppliedDb db = image.getSuppliedDb();
445       Core.DEBUG(3,"SetImage: db = " + db);
446       Assert.notFalse(st.given.add(db));
447       Core.DEBUG(3,"SetImage: After assert");
448       st.image = image;
449       st.agent = agent;
450       st.scheduled = true;
451       st.queued = false;
452 
453 /*
454    REM: what if node is the root node of decomposition graph?
455 */
456       String consumer, consumer_id;
457       int amount, start;
458       boolean consumed;
459       String itemId;
460       SuppliedItem item;
461       String[] refs;
462       String producer, producer_id;
463       String comms_key;
464 
465       DecompositionStruct pt = (DecompositionStruct)this.get(st.current_parent);
466       producer = st.agent;
467       producer_id = st.image.getId();
468 
469       if ( pt.record == null ) {
470          itemId = (String)pt.lookupTable.get(st.parent_link);
471          item = pt.given.getSuppliedItem(itemId);
472          refs = item.getReservationId();
473 
474          for(int i = 0; i < refs.length; i++ ) {
475             consumer = item.getReservingAgent(refs[i]);
476             consumer_id = item.getReservationGoalId(refs[i]);
477             comms_key = item.getReservationCommsKey(refs[i]);
478 
479             amount = item.getReservedAmount(refs[i]);
480             start = item.getReservationTime(refs[i]);
481             consumed = item.isReservationConsumed(refs[i]);
482             Assert.notFalse(amount > 0);
483    
484             pt.image.addProducer(itemId, refs[i], comms_key,
485                                  producer, producer_id, consumer, consumer_id);
486 
487             st.image.addConsumer(producer, producer_id, consumer, consumer_id,
488                                  refs[i], comms_key, start, amount, consumed);
489          }
490       }
491       else {
492          String use_ref = planner.getAgentContext().newId("used");
493 
494          consumer = planner.getAgentContext().whoami();
495          consumer_id = pt.goal.getId();
496 
497          start = pt.record.getStartTime();
498          int precond_position = pt.record.getConsumedPosition(producer_id);
499          consumed = pt.record.isPreconditionConsumed(precond_position);
500          amount = pt.record.getAmountUsed(precond_position);
501          Assert.notFalse(amount > 0);
502         
503          st.image.addConsumer( producer, producer_id,
504                                consumer, consumer_id, use_ref, delegation_key,
505                                start, amount, consumed ); 
506 
507          pt.record.getConsumedDb().update( producer_id + "/" + use_ref,
508                                            producer_id );
509       }
510       st.key = delegation_key;
511    }
512 
513    public void enforceLinks() {
514       TaskLink link;
515       LinkInfo info;
516       SuppliedItem item;
517       String[] refs;
518 
519       String itemId, producer, producer_id, consumer, consumer_id, comms_key;
520       int amount, start;
521       boolean consumed;
522 
523       Enumeration enum = links.elements();
524       while( enum.hasMoreElements() ) {
525          link = (TaskLink)enum.nextElement();
526          Core.DEBUG(2,"About to hardChain " + link.getId());
527          info = getLinkInfo(link);
528          if ( info.child.record != null ) {
529             if ( info.parent.record != null ) {
530                info.child.record.getProducedDb().hardChain(
531                   info.effect_position,info.amount,info.parent.record,
532                   info.precond_position
533                );
534             }
535             else {
536                itemId = (String)info.parent.lookupTable.get(link.getId());
537                item = info.parent.given.getSuppliedItem(itemId);
538                refs = item.getReservationId();
539 
540                producer = planner.getAgentContext().whoami();
541                producer_id = info.child.goal.getId();
542                for(int i = 0; i < refs.length; i++ ) {
543                   consumer = item.getReservingAgent(refs[i]);
544                   consumer_id = item.getReservationGoalId(refs[i]);
545                   comms_key = item.getReservationCommsKey(refs[i]);
546 
547                   info.parent.image.addProducer(
548                      itemId, refs[i], comms_key,
549                      producer, producer_id, consumer, consumer_id
550                   );
551 
552                   amount = item.getReservedAmount(refs[i]);
553                   start = item.getReservationTime(refs[i]);
554                   consumed = item.isReservationConsumed(refs[i]);
555                   Assert.notFalse(amount > 0);
556 
557                   info.child.record.getProducedDb().hardChain(
558                      info.effect_position, consumer_id + "/" + refs[i],
559                      amount, start, consumed
560                   );
561                }
562             }
563          }
564          else {
565             if ( info.parent.record != null ) {
566                String use_ref = planner.getAgentContext().newId("used");
567                info.child.image.addConsumer(
568                   info.child.agent, info.child.goal.getId(),
569                   planner.getAgentContext().whoami(), info.parent.goal.getId(),
570                   use_ref, info.child.key,
571                   info.start, info.amount, info.consumed
572                );
573                info.parent.record.getConsumedDb().add(
574                   info.precond_position,info.child.goal.getId() + "/" + use_ref,
575                   info.amount);
576 
577             }
578             else {
579                itemId = (String)info.parent.lookupTable.get(link.getId());
580                item = info.parent.given.getSuppliedItem(itemId);
581                refs = item.getReservationId();
582 
583                producer = info.child.agent;
584                producer_id = info.child.goal.getId();;
585                for(int i = 0; i < refs.length; i++ ) {
586                   consumer = item.getReservingAgent(refs[i]);
587                   consumer_id = item.getReservationGoalId(refs[i]);
588                   comms_key = item.getReservationCommsKey(refs[i]);
589 
590                   info.parent.image.addProducer(
591                      itemId,refs[i],comms_key,
592                      producer,producer_id,consumer,consumer_id
593                   );
594 
595                   amount = item.getReservedAmount(refs[i]);
596                   start = item.getReservationTime(refs[i]);
597                   consumed = item.isReservationConsumed(refs[i]);
598                   Assert.notFalse(amount > 0);
599 
600                   info.child.image.addConsumer(
601                      info.child.agent, info.child.goal.getId(),
602                      consumer, consumer_id,
603                      refs[i], comms_key, start, amount, consumed
604                   );
605                }
606             }
607          }
608       }
609       links.removeAllElements();
610    }
611 
612    protected LinkInfo getLinkInfo(TaskLink link) {
613       LinkInfo info = new LinkInfo();
614       Fact f1;
615       Fact[] data;
616       Bindings b = new Bindings(planner.getAgentContext().whoami());
617 
618       info.child = (DecompositionStruct)get(link.getLeftNode());
619       info.parent = (DecompositionStruct)get(link.getRightNode());
620 
621       if ( info.child.record != null ) {
622          f1 = info.child.node.getPostcondition(link.getLeftGroup(),link.getLeftArg());
623          data = info.child.record.getTask().getPostconditions();
624          for(int i = 0; i < data.length; i++, b.clear()) {
625             if ( f1.unifiesWith(data[i],b) ) {
626                info.effect_position = i;
627                break;
628             }
629          }
630       }
631 
632       if ( info.parent.record != null ) {
633          f1 = info.parent.node.getPrecondition(link.getRightGroup(),link.getRightArg());
634          data = info.parent.record.getTask().getPreconditions();
635          for(int i = 0; i < data.length; i++, b.clear()) {
636             if ( f1.unifiesWith(data[i],b) ) {
637                info.precond_position = i;
638                info.amount = data[i].getNumber();
639                if ( info.amount == 0 ) {
640                   System.err.println("Error: integer expected in " +
641                   "task.precond.fact.no field." +
642                   "\nEnsure \"no\" constraints are defined in all task " +
643                   "specifications >> " + link.getId());
644 
645                   // ERROR FIX
646                   info.amount = 1;
647                }
648                info.consumed = !data[i].isReadOnly();
649                info.start = info.parent.record.getStartTime();
650                break;
651             }
652          }
653       }
654       return info;
655    }
656 
657    public SuppliedDb getSuppliedDb(String node) {
658       DecompositionStruct st = (DecompositionStruct)get(node);
659       if ( st.given != null ) return st.given;
660 
661       st.given = new SuppliedDb(planner.getAgentContext().OntologyDb());
662       st.lookupTable = new Hashtable();
663       Enumeration enum = links.elements();
664       TaskLink link;
665       Fact f1;
666       String me = planner.getAgentContext().whoami();
667       String id;
668       SuppliedItem item;
669       while( enum.hasMoreElements() ) {
670          link = (TaskLink)enum.nextElement();
671          if ( link.getRightNode().equals(node) ) {
672             f1 = st.node.getPrecondition(link.getRightGroup(),link.getRightArg());
673             id = planner.getAgentContext().newId("supplied");
674             item = new SuppliedItem(id,link.getId(),me,f1);
675             st.given.add(item);
676             st.lookupTable.put(link.getId(),id);
677          }
678       }
679       return st.given;
680    }
681 }
682 
683 class LinkInfo {
684    public DecompositionStruct child = null;
685    public DecompositionStruct parent = null;
686    public int effect_position = -1;
687    public int precond_position = -1;
688    public int amount = 0;
689    public int start = -1;
690    public boolean consumed = false;
691 }
692 
693 class DecompositionStruct {
694    public TaskNode node = null;
695    public PlanRecord record = null;
696    public Vector records = null;
697    public String key = null;
698    public Goal goal = null;
699    public Goal image = null;
700    public String agent = null;
701    public String parent_link = null;
702    public Vector path = null;
703    public PlanRecord parent_record = null;
704    public String current_parent = null;
705    public Vector parents = new Vector();
706    public Vector children = new Vector();
707    public boolean scheduled = false;
708    public boolean queued = false;
709    public SuppliedDb given = null;
710    public Hashtable lookupTable = null;
711 
712    public DecompositionStruct(String self, TaskNode node) {
713       Assert.notNull(node);
714       this.node = node;
715       agent = self;
716    }
717    public String toString() {
718       return "(:node " + node.getName() + "\n" +
719              " :records " + records + "\n" +
720              " :record " + record + "\n" +
721              " :key " + key + "\n" +
722              " :goal " + goal + "\n" +
723              " :image " + image + "\n" +
724              " :agent " + agent + "\n" +
725              " :path " + path + "\n" +
726              " :parent_record " + parent_record + "\n" +
727              " :current_parent " + current_parent + "\n" +
728              " :parent_link " + parent_link + "\n" +
729              " :parents " + parents + "\n" +
730              " :children " + children + "\n" +
731              " :scheduled " + scheduled + "\n" +
732              " :queued " + queued + "\n" +
733              " :given " + given + "\n" +
734              " :lookupTable " + lookupTable + "\n" +
735              ")";
736    }
737 }
738