1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package zeus.actors;
29
30 import java.util.*;
31 import zeus.util.*;
32 import zeus.concepts.*;
33 import zeus.actors.rtn.Engine;
34 import zeus.actors.rtn.util.DelegationStruct;
35
36
37 /***
38 * The Produced Resources Database is an internal storage component used by
39 * the {@link Planner} in the course of its activities. It is unlikely
40 * that developers will need to call these methods directly.
41 */
42
43 public class ProducedDb
44 {
45 protected Vector[] data = null;
46 protected int[] produced = null;
47 protected PlanRecord owner = null;
48
49
50 public ProducedDb () {
51 ;
52 }
53
54
55 public ProducedDb(PlanRecord owner, PrimitiveTask task) {
56 Assert.notNull(owner);
57 produced = task.numPostconditions();
58 this.owner = owner;
59 data = new Vector[produced.length];
60 }
61
62
63 public synchronized void add(int effect_position, PlanRecord parent,
64 int amount, String goal_id, boolean consumed) {
65 Assert.notFalse(effect_position >= 0 && effect_position < data.length);
66
67 if ( data[effect_position] == null)
68 data[effect_position] = new Vector();
69
70 EffectChain ch;
71 int start;
72 if ( parent != null ) {
73 int precond_position = parent.getConsumedPosition(goal_id);
74 start = parent.getStartTime();
75 Assert.notFalse(availableItems(effect_position,start,consumed) >=
76 amount);
77 ch = new EffectChain(parent,precond_position,amount,start,consumed);
78 parent.replacePrecondition(goal_id,owner,effect_position,amount);
79 }
80 else {
81 start = owner.getEndTime();
82 Assert.notFalse(availableItems(effect_position,start,consumed) >=
83 amount);
84 ch = new EffectChain(goal_id,amount,start,consumed);
85 }
86 data[effect_position].addElement(ch);
87 }
88
89
90 public synchronized void add(int effect_position, EffectChain ch) {
91 Assert.notFalse(effect_position >= 0 && effect_position < data.length);
92 Assert.notFalse(availableItems(effect_position,ch.start,ch.consumed) >=
93 ch.amount);
94
95 if ( data[effect_position] == null)
96 data[effect_position] = new Vector();
97 data[effect_position].addElement(ch);
98 }
99
100
101 public int noItemsProduced(int position) {
102 return produced[position];
103 }
104
105
106 protected synchronized int availableItems(int position, int start,
107 boolean consumed) {
108 if ( data[position] == null ) return produced[position];
109 EffectChain ch;
110 int amount = 0;
111 for(int i = 0; i < data[position].size(); i++ ) {
112 ch = (EffectChain)data[position].elementAt(i);
113 if ( consumed ) {
114 if ( ch.consumed || ch.start > start )
115 amount += ch.amount;
116 }
117 else {
118 if ( ch.consumed && ch.start <= start )
119 amount += ch.amount;
120 }
121 }
122 return produced[position] - amount;
123 }
124
125
126 public synchronized int anySideEffect(int effect_position, PlanRecord parent,
127 Object precond, int required) {
128 int precond_position = -1;
129 String goal_id = null;
130 boolean is_string = false;
131 if ( precond instanceof String ) {
132 goal_id = (String)precond;
133 precond_position = parent.getConsumedPosition(goal_id);
134 is_string = true;
135 }
136 else {
137 precond_position = ((Integer)precond).intValue();
138 }
139
140 int start = parent.getStartTime();
141 boolean consumed = parent.isPreconditionConsumed(precond_position);
142 int available = availableItems(effect_position,start,consumed);
143 if ( available == 0 )
144 return required;
145
146 Core.DEBUG(2,"ProducedDb checking for serendipitous effects");
147
148 if ( data[effect_position] == null )
149 data[effect_position] = new Vector();
150
151 EffectChain ch;
152 int amount = (available >= required) ? required : available;
153 ch = new EffectChain(parent,precond_position,amount,start,consumed);
154 data[effect_position].addElement(ch);
155 if ( is_string )
156 parent.replacePrecondition(goal_id,owner,effect_position,amount);
157 else
158 parent.chainPrecondition(owner,effect_position,amount,precond_position);
159
160 return required - amount;
161 }
162
163
164 public synchronized void hardChain(int effect_position, int required,
165 PlanRecord parent, int precond_position) {
166
167 Core.DEBUG(2,"ProducedDb hardChain effects ...1");
168 Core.DEBUG(2,owner.toString() + "::" + effect_position);
169 Core.DEBUG(2," ==");
170 Core.DEBUG(2,parent.toString() + "::" + precond_position);
171
172 int start = parent.getStartTime();
173 boolean consumed = parent.isPreconditionConsumed(precond_position);
174 int available = availableItems(effect_position,start,consumed);
175
176 if ( available == 0 ) {
177 System.err.println("ProducedDb hardChain effects: available == 0");
178 return;
179 }
180
181 if ( data[effect_position] == null )
182 data[effect_position] = new Vector();
183
184 EffectChain ch;
185 int amount = (available >= required) ? required : available;
186 ch = new EffectChain(parent,precond_position,amount,start,consumed);
187 data[effect_position].addElement(ch);
188 parent.chainPrecondition(owner,effect_position,amount,precond_position);
189 }
190
191
192 public synchronized void hardChain(int effect_position, String key,
193 int amount, int start, boolean consumed) {
194
195 Core.DEBUG(2,"ProducedDb hardChain effects ...2");
196 Core.DEBUG(2,"effect_position: " + effect_position);
197 Core.DEBUG(2,"key: " + key);
198 Core.DEBUG(2,"amount: " + amount);
199 Core.DEBUG(2,"start: " + start);
200 Core.DEBUG(2,"consumed: " + consumed);
201
202 Assert.notFalse(effect_position >= 0 && effect_position < data.length);
203
204 if ( data[effect_position] == null )
205 data[effect_position] = new Vector();
206
207 Core.DEBUG(2,"Current chains...");
208 Core.DEBUG(2,data[effect_position]);
209
210 EffectChain ch;
211 Assert.notFalse(availableItems(effect_position,start,consumed)>=amount);
212 ch = new EffectChain(key,amount,start,consumed);
213 data[effect_position].addElement(ch);
214 }
215
216
217 public void allocatePostconditions(Fact[][] fact) {
218 debug (fact.toString());
219 for(int i = 0; i < fact.length; i++ ) {
220 debug (fact[i].toString());
221 allocatePostcondition(i,fact[i]);}
222 }
223
224
225 protected void allocatePostcondition(int position, Fact[] input) {
226
227 Fact fact = input[0];
228
229 int available;
230 debug ("in producedDB " + String.valueOf(position));
231 debug ("in producedDB " + fact.toString());
232 if ( (available = fact.getNumber()) == 0 ) {
233 Core.USER_ERROR("Warning: integer expected in .fact.no field." +
234 "\nEnsure \'" + OntologyDb.NUMBER + "\' constraints are defined " +
235 "in all task specifications");
236 return;
237 }
238 if ( available < produced[position] ) {
239 Core.USER_ERROR("\nWarning: fewer items produced: " + available +
240 " than expected " + produced[position]);
241 Core.USER_ERROR(fact.pprint());
242 }
243
244 ResourceDb db = owner.getAgentContext().ResourceDb();
245 if ( data[position] == null ) {
246 db.replaceOrAdd(fact);
247 return;
248 }
249
250 Fact f1;
251 Engine engine = owner.getAgentContext().Engine();
252 DelegationStruct ds;
253 EffectChain ch;
254
255 for(int i = 0; available > 0 && i < data[position].size(); i++) {
256 ch = (EffectChain)data[position].elementAt(i);
257 if ( ch.isExternal() && available >= ch.amount ) {
258 if ( ch.consumed ) available = available - ch.amount;
259 f1 = new Fact(Fact.FACT, fact);
260 f1.setNumber(ch.amount);
261 ds = new DelegationStruct(owner.getAgentContext().whoami(),
262 "result", ch.key, f1);
263 debug (ds.toString());
264 engine.add(ds);
265 }
266 }
267 if ( available > 0 ) {
268 fact.setNumber(available);
269 db.replaceOrAdd(fact);
270 }
271 for(int i = 0; i < data[position].size(); i++) {
272 ch = (EffectChain)data[position].elementAt(i);
273 if ( !ch.isExternal() ) {
274 f1 = new Fact(Fact.VARIABLE, fact);
275 f1.setNumber(ch.amount);
276 ch.record.preconditionExists(owner,position,ch.amount,ch.position);
277 }
278 }
279 }
280
281
282 public boolean constrain(Bindings bindings) {
283 boolean status = true;
284 Vector List;
285 EffectChain ch;
286 for(int i = 0; status && i < data.length; i++ ) {
287 List = data[i];
288 for(int j = 0; status && List != null && j < List.size(); j++ ) {
289 ch = (EffectChain)List.elementAt(j);
290 if ( !ch.isExternal() )
291
292
293 status &= ch.record.applyConstraints(bindings);
294 }
295 }
296 return status;
297 }
298
299
300 public PlanRecord getOwner() { return owner; }
301
302
303
304 public synchronized void share(ProducedDb db,
305 PlanRecord parent_image, String key_image,
306 PlanRecord parent, String key) {
307
308 int required;
309 EffectChain ch;
310 for(int i = 0; i < produced.length; i++) {
311 required = db.noItemsProduced(i);
312 for(int j = 0; required > 0 && j < data[i].size(); j++ ) {
313 ch = (EffectChain)data[i].elementAt(j);
314 if ( ch.amount <= required ) {
315
316 data[i].removeElementAt(j--);
317 required = required - ch.amount;
318
319 }
320 else {
321 ch.amount = ch.amount - required;
322
323 ch = new EffectChain(ch);
324 ch.amount = required;
325 required = 0;
326
327 }
328
329 if ( ch.isExternal() ) {
330 if ( ch.key.equals(key) )
331 ch.key = key_image;
332 }
333 else {
334 if ( ch.record == parent )
335 ch.record = parent_image;
336 }
337
338 db.add(i,ch);
339 }
340 }
341 }
342
343
344 public synchronized boolean update(PlanRecord image, PlanRecord record) {
345 EffectChain ch;
346 for(int i = 0; i < data.length; i++ ) {
347 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
348 ch = (EffectChain)data[i].elementAt(j);
349 if ( !ch.isExternal() && ch.record == record ) {
350 ch.record = image;
351 return true;
352 }
353 }
354 }
355 return false;
356 }
357
358
359 public synchronized boolean update(String image, String key) {
360 EffectChain ch;
361 for(int i = 0; i < data.length; i++ ) {
362 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
363 ch = (EffectChain)data[i].elementAt(j);
364 if ( ch.isExternal() && ch.key.equals(key) ) {
365 ch.key = image;
366 return true;
367 }
368 }
369 }
370 return false;
371 }
372
373
374 public synchronized boolean replaceOrAdd(String key, String newKey,
375 int start, int amount,
376 boolean consumed) {
377 EffectChain ch;
378 for(int i = 0; i < data.length; i++ ) {
379 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
380 ch = (EffectChain)data[i].elementAt(j);
381 if ( ch.isExternal() && ch.key.equals(key) ) {
382 Core.DEBUG(2,ch);
383 if ( ch.start == start && ch.amount == amount &&
384 ch.consumed == consumed ) {
385
386 ch.key = newKey;
387 return true;
388 }
389
390
391
392 else if ( ch.start <= start && ch.amount == amount &&
393 ch.consumed == true && consumed == true ) {
394
395 ch.key = newKey;
396 ch.start = start;
397 return true;
398 }
399 else {
400 ch = new EffectChain(newKey,amount,start,consumed);
401 add(i,ch);
402 return true;
403 }
404 }
405 }
406 }
407 ch = new EffectChain(newKey,amount,start,consumed);
408 add(owner.getTask().getActiveEffectPos(),ch);
409 return true;
410 }
411
412
413 public synchronized boolean hasAtMostOneParent(PlanRecord parent, String key) {
414 Vector records = new Vector();
415 Vector keys = new Vector();
416 EffectChain ch;
417 for(int i = 0; i < data.length; i++ ) {
418 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
419 ch = (EffectChain)data[i].elementAt(j);
420 if ( ch.isExternal() ) {
421 if ( !keys.contains(ch.key) )
422 keys.addElement(ch.key);
423 }
424 else {
425 if ( !records.contains(ch.record) )
426 records.addElement(ch.record);
427 }
428 }
429 }
430 Core.DEBUG(3,"ProducedDb hasAtMostOneParent: parent = " + parent + " key = " + key);
431 Core.DEBUG(3,"ProducedDb hasAtMostOneParent: records = " + records);
432 Core.DEBUG(3,"ProducedDb hasAtMostOneParent: keys = " + keys);
433
434 if ( parent != null ) {
435 return keys.isEmpty() && records.size() == 1 &&
436 records.contains(parent);
437 }
438 else {
439 return records.isEmpty() && keys.size() == 1 &&
440 (keys.contains(key) || keys.contains(owner.getGoal().getId()));
441 }
442 }
443
444
445 public synchronized void remove(int effect_position,
446 PlanRecord parent,
447 int precond_position, int amount) {
448 EffectChain ch;
449 for(int j = 0; j < data[effect_position].size(); j++ ) {
450 ch = (EffectChain)data[effect_position].elementAt(j);
451 if ( ch.record == parent && ch.position == precond_position &&
452 ch.amount == amount ) {
453 data[effect_position].removeElementAt(j--);
454 return;
455 }
456 }
457 Assert.notNull(null);
458 }
459
460
461 public synchronized boolean references(PlanRecord parent) {
462 EffectChain ch;
463 for(int i = 0; i < data.length; i++ ) {
464 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
465 ch = (EffectChain)data[i].elementAt(j);
466 if ( !ch.isExternal() && ch.record == parent )
467 return true;
468 }
469 }
470 return false;
471 }
472
473
474 public synchronized PlanRecord firstParent() {
475 EffectChain ch;
476 for(int i = 0; i < data.length; i++ ) {
477 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
478 ch = (EffectChain)data[i].elementAt(j);
479 if ( !ch.isExternal() )
480 return ch.record;
481 }
482 }
483 return null;
484 }
485
486
487 public synchronized String firstKey() {
488 EffectChain ch;
489 for(int i = 0; i < data.length; i++ ) {
490 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
491 ch = (EffectChain)data[i].elementAt(j);
492 if ( ch.isExternal() )
493 return ch.key;
494 }
495 }
496 return null;
497 }
498 public synchronized int firstPosition(PlanRecord parent) {
499 EffectChain ch;
500 for(int i = 0; i < data.length; i++ ) {
501 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
502 ch = (EffectChain)data[i].elementAt(j);
503 if ( !ch.isExternal() && ch.record == parent )
504 return i;
505 }
506 }
507 Assert.notNull(null);
508 return -1;
509 }
510
511
512
513 public synchronized Vector getAllParents() {
514 Vector output = new Vector();
515 EffectChain ch;
516 StringTokenizer st;
517 for(int i = 0; i < data.length; i++ ) {
518 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
519 ch = (EffectChain)data[i].elementAt(j);
520 if ( !ch.isExternal() )
521 output.addElement(ch.record.getGoal().getId());
522 else {
523 st = new StringTokenizer(ch.key,"/");
524 output.addElement(st.nextToken());
525 }
526 }
527 }
528 return output;
529 }
530
531
532 public synchronized void notifyFailed(Vector Tasks, Vector path) {
533 EffectChain ch;
534 for(int i = 0; i < data.length; i++ ) {
535 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
536 ch = (EffectChain)data[i].elementAt(j);
537 data[i].removeElementAt(j--);
538 if ( ch.isExternal() )
539 owner.raiseException(i,ch.key,ch.amount);
540 else {
541 if ( ch.record == owner.getParent() )
542 ch.record.reallocateResource(ch.position,owner,i,
543 ch.amount,Tasks,path);
544 else
545 ch.record.reallocateResource(ch.position,owner,i,
546 ch.amount,null,null);
547 }
548 }
549 }
550 }
551
552
553 public synchronized void softNotifyFailed(Vector Tasks, Vector path,
554 PlannerQueryStruct struct,
555 int mode) {
556 EffectChain ch;
557 for(int i = 0; i < data.length; i++ ) {
558 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
559 ch = (EffectChain)data[i].elementAt(j);
560 data[i].removeElementAt(j--);
561 if ( ch.isExternal() )
562 owner.softRaiseException(i,ch.key,ch.amount,struct,mode);
563 else {
564 if ( ch.record == owner.getParent() )
565 ch.record.softReallocateResource(ch.position,owner,i,
566 ch.amount,Tasks,path,struct,mode);
567 else
568 ch.record.softReallocateResource(ch.position,owner,i,
569 ch.amount,null,null,struct,mode);
570 }
571 }
572 }
573 }
574
575
576
577 public String toString() {
578 String out = "ProducedDb(" + "\n" + owner + "\n";
579 for(int i = 0; i < data.length; i++ ) {
580 if ( data[i] != null )
581 out += "data[" + i + "]: " + data[i] + "\n";
582 }
583 out += ")";
584 return out;
585 }
586
587
588 public synchronized boolean setConsumers(String key, Vector input) {
589 EffectChain ch;
590 ConsumerRecord e;
591 for(int i = 0; i < data.length; i++ ) {
592 for(int j = 0; data[i] != null && j < data[i].size(); j++ ) {
593 ch = (EffectChain)data[i].elementAt(j);
594 if ( ch.isExternal() && ch.key.equals(key) ) {
595 if ( !checkConsumers(ch.start,ch.amount,ch.consumed,input) )
596 return false;
597 data[i].removeElementAt(j--);
598 for(int k = 0; k < input.size(); k++ ) {
599 e = (ConsumerRecord)input.elementAt(k);
600 ch = new EffectChain(e.consumer_id,e.amount,
601 e.start,e.consumed);
602 data[i].addElement(ch);
603 }
604 return true;
605 }
606 }
607 }
608 return false;
609 }
610
611
612 protected synchronized boolean checkConsumers(int start, int amount,
613 boolean consumed, Vector temp) {
614
615 ConsumerRecord e;
616 Vector current = new Vector();
617 for(int i = 0; i < temp.size(); i++ ) {
618 e = (ConsumerRecord)temp.elementAt(i);
619 if ( e.start < start ||
620 !checkCurrent(amount,current,e.start,e.consumed,e.amount) )
621 return false;
622 current.addElement(e);
623 }
624 current = null;
625 return true;
626 }
627
628
629 protected synchronized boolean checkCurrent(int available, Vector current,
630 int start, boolean consumed, int amount) {
631
632 int reserved = 0;
633 ConsumerRecord e;
634 for(int i = 0; i < current.size(); i++ ) {
635 e = (ConsumerRecord)current.elementAt(i);
636 if ( consumed ) {
637 if ( e.consumed || e.start > start )
638 reserved += e.amount;
639 }
640 else {
641 if ( e.consumed && e.start <= start )
642 reserved += e.amount;
643 }
644 }
645 return available - reserved >= amount;
646 }
647
648
649 public void debug(String str) {
650
651 }
652 }