001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.lib.util;
028:
029: import java.util.ArrayList;
030: import java.util.Date;
031: import java.util.Enumeration;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Map;
036: import java.util.Vector;
037:
038: import org.cougaar.lib.filter.UTILPlugin;
039: import org.cougaar.planning.ldm.PlanningFactory;
040: import org.cougaar.planning.ldm.asset.Asset;
041: import org.cougaar.planning.ldm.plan.AllocationResult;
042: import org.cougaar.planning.ldm.plan.AspectScorePoint;
043: import org.cougaar.planning.ldm.plan.AspectScoreRange;
044: import org.cougaar.planning.ldm.plan.AspectType;
045: import org.cougaar.planning.ldm.plan.AspectValue;
046: import org.cougaar.planning.ldm.plan.Disposition;
047: import org.cougaar.planning.ldm.plan.Plan;
048: import org.cougaar.planning.ldm.plan.PlanElement;
049: import org.cougaar.planning.ldm.plan.Preference;
050: import org.cougaar.planning.ldm.plan.Role;
051: import org.cougaar.planning.ldm.plan.ScoringFunction;
052: import org.cougaar.planning.ldm.plan.Task;
053: import org.cougaar.util.log.Logger;
054:
055: /**
056: * This class contains utility functions for allocations.
057: */
058: public class UTILAllocate {
059: private static final boolean SUCCESS = true;
060: private static final boolean RESCINDMEPLEASE = false;
061: public static final double MEDIUM_CONFIDENCE = 0.5d;
062: public static final double HIGHEST_CONFIDENCE = 1.0d;
063: private static double ONE_DAY = 1000 * 60 * 60 * 24; // millis
064: private static double ONE_OVER_ONE_DAY = 1.0d / ONE_DAY; // millis
065:
066: /**
067: * Set logger
068: */
069: public UTILAllocate(Logger log) {
070: logger = log;
071: expand = new UTILExpand(log);
072: }
073:
074: /**
075: * Creates an Allocation or FailedAllocation
076: * depending on whether start and end dates or cost
077: * exceed preference thresholds.
078: *
079: * @param ldmf the PlanningFactory
080: * @param plan the log plan
081: * @param t the task to allocate
082: * @param asset the asset assigned to handle the task
083: * @param start - start date of allocation
084: * @param end - end date of allocation
085: * @param cost - the monetary cost of the allocation
086: * @param confidence in the allocation
087: * @return PlanElement = Allocation or a FailedDisposition
088: */
089: public PlanElement makeAllocation(UTILPlugin creator,
090: PlanningFactory ldmf, Plan plan, Task t, Asset asset,
091: Date start, Date end, double cost, double confidence,
092: Role assignedRole) {
093: return makeAllocation(creator, ldmf, plan, t, asset,
094: getAspects(start, end, cost), confidence, assignedRole);
095: }
096:
097: /**
098: * <pre>
099: * Creates an Allocation or FailedDisposition
100: * with an allocationResult w/ isSuccess=False or True,
101: * depending on whether any of the start and end dates
102: * exceed preference thresholds.
103: *
104: * Automates the checking of an allocation against its preferences
105: *
106: * Plugins should never have to create AllocationResults directly.
107: * If you want to find the score of a task-allocation result pair
108: * before making the REAL allocation, you can call scoreAgainstPreferences
109: * (GSS).
110: *
111: * Note that returned Allocations will ALWAYS have
112: * an AllocationResult with isSuccess = TRUE.
113: *
114: * FailedDispositions will ALWAYS have isSuccess = FALSE.
115: *
116: * </pre>
117: * @param ldmf the PlanningFactory
118: * @param plan the log plan
119: * @param t the task to allocate
120: * @param asset the asset assigned to handle the task
121: * @param start - start date of allocation
122: * @param end - end date of allocation
123: * @param confidence in the allocation
124: * @return PlanElement = Allocation or a FailedDisposition
125: */
126: public PlanElement makeAllocation(UTILPlugin creator,
127: PlanningFactory ldmf, Plan plan, Task t, Asset asset,
128: Date start, Date end, double confidence, Role assignedRole) {
129: return makeAllocation(creator, ldmf, plan, t, asset,
130: getAspectsFromDates(start, end), confidence,
131: assignedRole);
132: }
133:
134: /**
135: * Creates an Allocation or FailedDisposition
136: * with an allocationResult w/ isSuccess=False or True,
137: * depending on whether any of the aspect values of the
138: * allocation exceed any preference thresholds.
139: *
140: * This automates the checking of an allocation against its preferences.
141: *
142: * Plugins should never have to create AllocationResults directly.
143: * If you want to find the score of a task-allocation result pair
144: * before making the REAL allocation, you can call scoreAgainstPreferences
145: * (GSS).
146: *
147: * Note that returned Allocations will ALWAYS have
148: * an AllocationResult with isSuccess = TRUE.
149: *
150: * FailedDispositions will ALWAYS have isSuccess = FALSE.
151: *
152: * @param ldmf the PlanningFactory
153: * @param plan the log plan
154: * @param t the task to allocate
155: * @param asset the asset assigned to handle the task
156:
157: * @param aspects AspectValue array -- aspect represented as aspectValues
158: * @param confidence in the allocation
159: * @return PlanElement = Allocation or a FailedDisposition
160: */
161: public PlanElement makeAllocation(UTILPlugin creator,
162: PlanningFactory ldmf, Plan plan, Task t, Asset asset,
163: AspectValue[] aspects, double confidence, Role assignedRole) {
164: int[] aspectarray = new int[aspects.length];
165: double[] resultsarray = new double[aspects.length];
166: for (int i = 0; i < aspects.length; i++) {
167: aspectarray[i] = aspects[i].getAspectType();
168: resultsarray[i] = aspects[i].getValue();
169: }
170:
171: return makeAllocation(creator, ldmf, plan, t, asset,
172: aspectarray, resultsarray, confidence, assignedRole);
173: }
174:
175: /**
176: * <pre>
177: * Creates an Allocation or FailedDisposition with an
178: * allocationResult w/ isSuccess=False or True,
179: * depending on whether any of the aspect values of the
180: * allocation exceed any preference thresholds.
181: *
182: * Also will automatically create a FailedDisposition if the asset
183: * passed in is null.
184: *
185: * This automates the checking of an allocation against its preferences.
186: *
187: * Plugins should never have to create AllocationResults directly.
188: * If you want to find the score of a task-allocation result pair
189: * before making the REAL allocation, you can call scoreAgainstPreferences
190: * (GSS).
191: *
192: * Note that returned Allocations will ALWAYS have
193: * an AllocationResult with isSuccess = TRUE.
194: *
195: * FailedDispositions will ALWAYS have isSuccess = FALSE.
196: *
197: * </pre>
198: * @param ldmf the PlanningFactory
199: * @param plan the log plan
200: * @param t the task to allocate
201: * @param asset the asset assigned to handle the task
202: * (Ignored if failed allocation.)
203:
204: * @param aspectarray - array of aspect types
205: * @param resultsarray - array of aspect values
206: * @param confidence in the allocation
207: * @return PlanElement = Allocation or a FailedDisposition
208: */
209: public PlanElement makeAllocation(UTILPlugin creator,
210: PlanningFactory ldmf, Plan plan, Task t, Asset asset,
211: int[] aspectarray, double[] resultsarray,
212: double confidence, Role assignedRole) {
213: AllocationResult estAR = null;
214: PlanElement alloc = null;
215:
216: if ((asset == null)
217: || exceedsPreferences(t, aspectarray, resultsarray)) {
218: estAR = createAllocationResult(RESCINDMEPLEASE, ldmf,
219: aspectarray, resultsarray, confidence);
220:
221: alloc = makeFailedDisposition(creator, ldmf, t, estAR);
222:
223: if (logger.isDebugEnabled())
224: logger.debug("\nMaking FailedDisposition : Task " + t
225: + "\n\tAllocResult "
226: + ARtoString(aspectarray, resultsarray));
227: } else {
228: estAR = createAllocationResult(SUCCESS, ldmf, aspectarray,
229: resultsarray, confidence);
230:
231: alloc = ldmf.createAllocation(plan, t, asset, estAR,
232: assignedRole);
233: if (logger.isDebugEnabled()) {
234: logger.debug("\nMaking Allocation : Task " + t
235: + "\n\tAsset " + asset + "\n\tAllocResult "
236: + ARtoString(aspectarray, resultsarray));
237: try {
238: logger.debug("\tScore "
239: + scoreAgainstPreferences(t, estAR));
240: } catch (NullPointerException npe) {
241: logger
242: .debug("ALPINE Bug : can't take the score of an aspect immediately?");
243: }
244: }
245: }
246: return alloc;
247: }
248:
249: /**
250: * Adds data to an auxiliaryQuery.
251: *
252: * @param pe the planelement of the task that issued the auxiliary query
253: * @param aqType the AuxiliaryQueryType
254: * @param data the data that answers the query
255: */
256:
257: public void addQueryResultToAR(PlanElement pe, int aqType,
258: String data) {
259: AllocationResult ar = pe.getEstimatedResult();
260: ar.addAuxiliaryQueryInfo(aqType, data);
261: }
262:
263: /**
264: * Handy utility function for checking a task's preferences against start and
265: * end dates and cost.
266: *
267: * @param t task to check
268: * @param start date to check against preferences
269: * @param end date to check against preferences
270: * @param cost - the monetary cost of a potential allocation
271: * @return true if either the start or end dates or cost lie
272: * outside the task's preferences.
273: */
274: public boolean exceedsPreferences(Task t, Date start, Date end,
275: double cost) {
276: if (logger.isDebugEnabled())
277: logger.debug("Checking for task " + t.getUID()
278: + " against start " + start + " end " + end
279: + " and cost " + cost);
280: return exceedsPreferences(t, getAspects(start, end, cost));
281: }
282:
283: /**
284: * Handy utility function for checking a task's preferences against start and
285: * end dates.
286: *
287: * @param t task to check
288: * @param start date to check against preferences
289: * @param end date to check against preferences
290: * @return true if either the start or end dates lie
291: * outside the task's preferences.
292: */
293: public boolean exceedsPreferences(Task t, Date start, Date end) {
294: if (logger.isDebugEnabled())
295: logger.debug("Checking for task " + t.getUID()
296: + " against start " + start + " end " + end);
297: return exceedsPreferences(t, getAspectsFromDates(start, end));
298: }
299:
300: /**
301: * Check a task's preferences against given aspect values.
302: *
303: * @param t task to check
304: * @param aspectValues array of AspectValues
305: * @return boolean -- true if exceeds any preference
306: * @see org.cougaar.planning.ldm.plan.AspectType
307: * @see org.cougaar.planning.ldm.plan.AspectValue
308: */
309: public boolean exceedsPreferences(Task t, AspectValue[] aspectValues) {
310: int[] aspectarray = new int[aspectValues.length];
311: double[] resultsarray = new double[aspectValues.length];
312: for (int i = 0; i < aspectValues.length; i++) {
313: aspectarray[i] = aspectValues[i].getAspectType();
314: resultsarray[i] = aspectValues[i].getValue();
315: }
316: return exceedsPreferences(t, aspectarray, resultsarray);
317: }
318:
319: /**
320: * <pre>
321: * Check a task's preferences against given aspect values.
322: *
323: * Throws an informative exception if somehow the
324: * the aspect types being checked are not the same set as the task's
325: * preferences. E.g. if the task has only a START_TIME preference
326: * and one of the allocation aspects is COST.
327: * This should never happen -- one
328: * should only assign aspects against a task's preferences.
329: *
330: * If debug is set, warns to stdout if set of preferences types doesn't match set
331: * of aspect values.
332: *
333: * </pre>
334: * @param t task to check
335: * @param aspectTypes array of aspect types
336: * @param aspectValues array of aspect values
337: * @return boolean -- true if any preference is exceeded
338: * @see org.cougaar.planning.ldm.plan.AspectType
339: */
340: public boolean exceedsPreferences(Task t, int[] aspectTypes,
341: double[] aspectValues) {
342: boolean prefExceeded = false;
343:
344: Enumeration prefs;
345: synchronized (t) {
346: prefs = t.getPreferences();
347: } // bug #2125
348: Map map = new HashMap();
349: int aspectType = -1;
350:
351: for (; prefs.hasMoreElements();) {
352: Preference pref = (Preference) prefs.nextElement();
353: map.put(new Integer(pref.getAspectType()), pref);
354: }
355:
356: try {
357: // check each aspect value against its preference threshold
358: for (int i = 0; i < aspectTypes.length && !prefExceeded; i++) {
359: aspectType = aspectTypes[i];
360: Integer aspectTypeInt = new Integer(aspectType);
361: Preference pref = (Preference) map
362: .remove(aspectTypeInt);
363:
364: AspectValue av = AspectValue.newAspectValue(aspectType,
365: aspectValues[i]);
366: double score = pref.getScoringFunction().getScore(av);
367:
368: if (score > (ScoringFunction.HIGH_THRESHOLD - 0.000001d)) {
369: prefExceeded = true;
370: if (logger.isDebugEnabled()) {
371: logger
372: .debug("UTILAllocate.exceedsPreferences - score "
373: + score
374: + " exceeds threshold "
375: + ScoringFunction.HIGH_THRESHOLD
376: + " for " + t.getUID());
377: AspectValue lower = AspectValue.newAspectValue(
378: aspectType, 0.0d);
379: AspectValue upper = AspectValue.newAspectValue(
380: aspectType, 1000000000.0d);
381: print(av, pref, score,
382: pref.getScoringFunction()
383: .getDefinedRange(), pref
384: .getScoringFunction()
385: .getValidRanges(lower, upper));
386: }
387: }
388: }
389: } catch (NullPointerException npe) {
390: // thrown when the hash table returns a null preference
391: // for an aspect type
392: throw new UTILRuntimeException(
393: "exceedsPreferences : For task "
394: + t.getUID()
395: + " making alloc w/ aspect <"
396: + aspectType
397: + "> - but task doesn't have this preference!");
398: }
399:
400: // !map.isEmpty() isn't a problem if we've exceeded preferences already,
401: // since by design the rest of the map doesn't get processed after one
402: // preference has been exceeded.
403:
404: if (!prefExceeded && !map.isEmpty()) {
405: for (Iterator i = map.keySet().iterator(); i.hasNext();) {
406: // Report when there are preferences without matching aspect values.
407: // It's a responsibility of the allocator to fill in aspect values for all prefs.
408:
409: logger
410: .debug("UTILAllocate.exceedsPreferences - Task "
411: + t
412: + " from "
413: + t.getSource()
414: + " has preference of aspect type "
415: + (Integer) i.next()
416: + " but no value of this type found in list of reported values."
417: + "\nPerhaps missing an aspect value when calling makeAllocation?");
418: expand.setAlloc(this );
419: expand.showPlanElement(t);
420: }
421: }
422: return prefExceeded;
423: }
424:
425: /**
426: * This should be used when the preference thresholds are exceeded, or
427: * the cumulative
428: * score for all preferences exceeds some threshold.
429: *
430: * This form lets the tasked cluster say how the preferences were exceeded.
431: *
432: * @param ldmf PlanningFactory for making the plan elements
433: * @param t Task that failed to be allocated
434: * @param failedAR AllocationResult stating how the preferences would have been
435: * exceeded.
436: * @return FailedDisposition
437: * @see #makeFailedDisposition (PlanningFactory, Task)
438: */
439: public Disposition makeFailedDisposition(UTILPlugin creator,
440: PlanningFactory ldmf, Task t, AllocationResult failedAR) {
441: Disposition falloc = ldmf.createFailedDisposition(ldmf
442: .getRealityPlan(), t, failedAR);
443:
444: return falloc;
445: }
446:
447: /**
448: * <pre>
449: * When you just can't allocate!
450: *
451: * This should be used when the preference thresholds are exceeded, or
452: * the cumulative
453: * score for all preferences exceeds some threshold.
454: *
455: * Generally the other makeFailedDisposition should be used --
456: * the tasking/superior cluster should be told not just that the allocation failed,
457: * but what aspect values made it fail. This function does not let you specify
458: * the aspect results.
459: *
460: * </pre>
461: * @param ignoredCreator - currently ignored slot that could be used for debugging
462: * @param ldmf PlanningFactory for making the plan elements
463: * @param task Task that failed to be allocated
464: * @return FailedDisposition
465: * @see #makeFailedDisposition (PlanningFactory, Task, AllocationResult)
466: */
467: public Disposition makeFailedDisposition(UTILPlugin ignoredCreator,
468: PlanningFactory ldmf, Task task) {
469: Enumeration prefEnum;
470: synchronized (task) {
471: prefEnum = task.getPreferences();
472: } // bug #2125
473: List aspectValues = new ArrayList();
474: while (prefEnum.hasMoreElements()) {
475: Preference pref = (Preference) prefEnum.nextElement();
476: ScoringFunction sfunc = pref.getScoringFunction();
477: aspectValues.add(sfunc.getBest().getAspectValue());
478: }
479:
480: AspectValue[] aspectValueArray = (AspectValue[]) aspectValues
481: .toArray(new AspectValue[aspectValues.size()]);
482:
483: AllocationResult failedAR = ldmf.newAVAllocationResult(
484: HIGHEST_CONFIDENCE, RESCINDMEPLEASE, aspectValueArray);
485: Disposition falloc = ldmf.createFailedDisposition(ldmf
486: .getRealityPlan(), task, failedAR);
487:
488: return falloc;
489: }
490:
491: /**
492: * <pre>
493: * Freeform allocation result creation.
494: *
495: * Protected because plugin should not need to call this.
496: *
497: * Workaround for COUGAAR bug (MB5.2) where asking for aspect values
498: * will throw null pointer exception.
499: *
500: * </pre>
501: * @param isSuccess sets whether allocation obeyed preferences or not
502: * @param ldmf PlanningFactory for making the plan elements
503: * @param aspectarray - array of aspect type IDs (ints from AspectType)
504: * @param resultsarray - results for those aspects, in same order as aspect types
505: * @param confidence of allocation
506: * @return allocation result with aspect results
507: */
508: protected AllocationResult createAllocationResult(
509: boolean isSuccess, PlanningFactory ldmf, int[] aspectarray,
510: double[] resultsarray, double confidence) {
511: AllocationResult myestimate = null;
512:
513: // myestimate = ldmf.newAllocationResult(confidence,
514: // isSuccess, aspectarray, resultsarray);
515: myestimate = ldmf.newAVAllocationResult(confidence, isSuccess,
516: getAspectsFromArrays(aspectarray, resultsarray));
517: return myestimate;
518: }
519:
520: public AllocationResult cloneAllocResultAsSuccess(
521: PlanningFactory ldmf, AllocationResult toClone) {
522: return ldmf.newAVAllocationResult(
523: toClone.getConfidenceRating(), true, toClone
524: .getAspectValueResults());
525:
526: }
527:
528: /**
529: * Utility function for creating AspectValues from start and end date.
530: *
531: * @param start date
532: * @param end date
533: * @return AspectValue array representing dates.
534: */
535: public AspectValue[] getAspectsFromDates(Date start, Date end) {
536: AspectValue[] aspects = new AspectValue[2];
537: aspects[0] = AspectValue.newAspectValue(AspectType.START_TIME,
538: start.getTime());
539: aspects[1] = AspectValue.newAspectValue(AspectType.END_TIME,
540: end.getTime());
541: return aspects;
542: }
543:
544: /**
545: * Utility function for creating AspectValues from start, end date, and cost.
546: *
547: * @param start date
548: * @param end date
549: * @param cost
550: * @return AspectValue array representing dates and cost.
551: */
552: public AspectValue[] getAspects(Date start, Date end, double cost) {
553: AspectValue[] aspects = new AspectValue[3];
554: aspects[0] = AspectValue.newAspectValue(AspectType.START_TIME,
555: start.getTime());
556: aspects[1] = AspectValue.newAspectValue(AspectType.END_TIME,
557: end.getTime());
558: aspects[2] = AspectValue.newAspectValue(AspectType.COST, cost);
559: return aspects;
560: }
561:
562: /**
563: * Utility function for creating AspectValues from start, end date, cost and quantity.
564: *
565: * @param start date
566: * @param end date
567: * @param cost
568: * @param quantity
569: * @return AspectValue array representing dates, cost, and quantity.
570: */
571: public AspectValue[] getAspects(Date start, Date end, double cost,
572: long quantity) {
573: AspectValue[] aspects = new AspectValue[4];
574: aspects[0] = AspectValue.newAspectValue(AspectType.START_TIME,
575: start.getTime());
576: aspects[1] = AspectValue.newAspectValue(AspectType.END_TIME,
577: end.getTime());
578: aspects[2] = AspectValue.newAspectValue(AspectType.COST, cost);
579: aspects[3] = AspectValue.newAspectValue(AspectType.QUANTITY,
580: quantity);
581: return aspects;
582: }
583:
584: /**
585: * Utility function for creating AspectValues from type and value arrays
586: *
587: * @param aspectarray type array
588: * @param resultsarray value array
589: * @return AspectValue array
590: */
591: public AspectValue[] getAspectsFromArrays(int[] aspectarray,
592: double[] resultsarray) {
593: AspectValue[] aspects = new AspectValue[aspectarray.length];
594:
595: for (int i = 0; i < aspectarray.length; i++)
596: aspects[i] = AspectValue.newAspectValue(aspectarray[i],
597: resultsarray[i]);
598:
599: return aspects;
600: }
601:
602: // Scoring -------------------------------------------------------------
603:
604: /**
605: * Score of a task's preferences against an allocation result
606: *
607: * @return the total score of the allocation result
608: * against the task's preferences
609: */
610: protected double scoreAgainstPreferences(Task t,
611: AllocationResult allocResult) {
612: return scoreAgainstPreferences(t, allocResult
613: .getAspectValueResults());
614: }
615:
616: /**
617: * Score of a task's preferences against start and
618: * end dates, and cost
619: *
620: * @param t task to check
621: * @param start date to score against preferences
622: * @param end date to score against preferences
623: * @param cost - the monetary cost of a potential allocation
624: * @return double score
625: */
626: public double scoreAgainstPreferences(Task t, Date start, Date end,
627: double cost) {
628: if (logger.isDebugEnabled())
629: logger.debug("Scoring task " + t.getUID()
630: + " against start " + start + " end " + end
631: + " and cost " + cost);
632: return scoreAgainstPreferences(t, getAspects(start, end, cost));
633: }
634:
635: /**
636: * Score of a task's preferences against start and
637: * end dates.
638: *
639: * Hoefully this form would be called most often...
640: *
641: * @param t task to check
642: * @param start date to score against preferences
643: * @param end date to score against preferences
644: * @return double score
645: */
646: public double scoreAgainstPreferences(Task t, Date start, Date end) {
647: if (logger.isDebugEnabled())
648: logger.debug("Scoring task " + t.getUID()
649: + " against start " + start + " end " + end);
650: return scoreAgainstPreferences(t, getAspectsFromDates(start,
651: end));
652: }
653:
654: /**
655: * Score a task's preferences against given aspect values.
656: *
657: * @param t task to check
658: * @param aspectValues array of AspectValues
659: * @return double -- the score
660: * @see org.cougaar.planning.ldm.plan.AspectType
661: * @see org.cougaar.planning.ldm.plan.AspectValue
662: */
663: public double scoreAgainstPreferences(Task t,
664: AspectValue[] aspectValues) {
665: int[] aspectarray = new int[aspectValues.length];
666: double[] resultsarray = new double[aspectValues.length];
667: for (int i = 0; i < aspectValues.length; i++) {
668: aspectarray[i] = aspectValues[i].getAspectType();
669: resultsarray[i] = aspectValues[i].getValue();
670: }
671: return scoreAgainstPreferences(t, aspectarray, resultsarray);
672: }
673:
674: /**
675: * <pre>
676: * Score a task's preferences against given aspect values.
677: *
678: * Throws an informative exception if somehow the
679: * the aspect types being checked are not the same set as the task's
680: * preferences. E.g. if the task has only a START_TIME preference
681: * and one of the allocation aspects is COST, then this method
682: * will throw an exception. This should never happen -- one
683: * should only assign aspects against a task's preferences.
684: *
685: * Protects against COUGAAR bug : sometimes preference weight
686: * gets lost... (ends up = 0).
687: *
688: * </pre>
689: * @param t task to check
690: * @param aspectTypes array of aspect types
691: * @param aspectValues array of aspect values
692: * @return double -- score of these aspect values against the task's preferences
693: * @see org.cougaar.planning.ldm.plan.AspectType
694: * @see org.cougaar.planning.ldm.plan.AspectValue
695: * @see org.cougaar.planning.ldm.plan.Preference
696: */
697: public double scoreAgainstPreferences(Task t, int[] aspectTypes,
698: double[] aspectValues) {
699:
700: int aspectType = -1;
701: Map hash = new HashMap();
702: double total = 0.0d;
703:
704: synchronized (t) { // bug #2125
705: for (Enumeration prefs = t.getPreferences(); prefs
706: .hasMoreElements();) {
707: Preference pref = (Preference) prefs.nextElement();
708: hash.put(new Integer(pref.getAspectType()), pref);
709: }
710: }
711:
712: try {
713: for (int i = 0; i < aspectTypes.length; i++) {
714: aspectType = aspectTypes[i];
715: Preference pref = (Preference) hash.get(new Integer(
716: aspectType));
717: AspectValue av = AspectValue.newAspectValue(aspectType,
718: aspectValues[i]);
719: double score = pref.getScoringFunction().getScore(av);
720: double weight = (pref.getWeight() == 0) ? 1 : pref
721: .getWeight();
722: total += score * weight;
723: }
724: } catch (NullPointerException npe) {
725: // thrown when the hash table returns a null preference
726: // for an aspect type
727: throw new UTILRuntimeException(
728: "scoreAgainstPreferences : For task "
729: + t.getUID()
730: + " scoring against aspect <"
731: + aspectType
732: + "> - but task doesn't have this aspect preference!");
733: }
734: return total;
735: }
736:
737: /**
738: * Checks plan element's allocation result to see if it's a failed
739: * plan element.
740: *
741: * @param pe the allocation to check
742: * @return true if the allocation need to be rescinded
743: * Also returns false if there is no report alloc result
744: * attached to allocation
745: * @see org.cougaar.lib.filter.UTILAllocatorPluginAdapter#handleRescindedAlloc
746: * @see org.cougaar.lib.callback.UTILAllocationCallback#reactToChangedAlloc
747: * @see org.cougaar.lib.util.UTILAllocate#makeAllocation
748: */
749: public boolean isFailedPE(PlanElement pe) {
750: AllocationResult reportedResult = pe.getReportedResult();
751: if (reportedResult == null) {
752: // It's ok for an allocation to be in the changed list multiple times,
753: // so this is a legal occurrence.
754: return false;
755: }
756:
757: boolean need = !reportedResult.isSuccess();
758: if (logger.isDebugEnabled() && need) {
759: logger.debug("UTILAllocate.isFailedPE - found failed task "
760: + pe.getTask().getUID() + "-"
761: + pe.getTask().getVerb());
762: }
763: return need;
764: }
765:
766: /**
767: * Is there a better place for this?
768: */
769: public static Vector enumToVector(Enumeration e) {
770: Vector retval = new Vector();
771:
772: if (e == null)
773: return retval;
774:
775: for (; e.hasMoreElements();)
776: retval.addElement(e.nextElement());
777:
778: return retval;
779: }
780:
781: /**
782: * Is there a better place for this?
783: */
784: public Vector iterToVector(Iterator i) {
785: Vector retval = new Vector();
786:
787: if (i == null)
788: return retval;
789:
790: for (; i.hasNext();)
791: retval.addElement(i.next());
792:
793: return retval;
794: }
795:
796: public static List enumToList(Enumeration e) {
797: List retval = new ArrayList();
798:
799: if (e == null)
800: return retval;
801:
802: for (; e.hasMoreElements();)
803: retval.add(e.nextElement());
804:
805: return retval;
806: }
807:
808: protected static String ARtoString(int[] aspectTypes,
809: double[] aspectValues) {
810: String retval = "";
811: for (int i = 0; i < aspectTypes.length; i++) {
812: retval = retval + "\n\t"
813: + printTypeValue(aspectTypes[i], aspectValues[i]);
814: }
815:
816: return retval;
817: }
818:
819: protected static String printTypeValue(int type, double value) {
820: String retval = "";
821: switch (type) {
822: case AspectType.START_TIME:
823: retval = "START_TIME";
824: retval = retval + "/" + new Date((long) value);
825: break;
826: case AspectType.END_TIME:
827: retval = "END_TIME";
828: retval = retval + "/" + new Date((long) value);
829: break;
830: case AspectType.COST:
831: retval = "COST";
832: retval = retval + "/$" + (long) value;
833: break;
834: default:
835: retval = "" + type;
836: retval = retval + "/" + (long) value;
837: break;
838: }
839:
840: return retval;
841: }
842:
843: protected void print(AspectValue av, Preference pref, double score,
844: AspectScoreRange definedRange, Enumeration validRanges) {
845: double prefval = pref.getScoringFunction().getBest().getValue();
846: String prefstr = "" + prefval;
847: String type = "" + av.getAspectType();
848: String value = "" + prefval;
849: boolean isDate = false;
850: switch (av.getAspectType()) {
851: case AspectType.START_TIME:
852: type = "START_TIME";
853: value = "" + new Date((long) av.getValue());
854: prefstr = "" + new Date((long) prefval);
855: isDate = true;
856: break;
857: case AspectType.END_TIME:
858: type = "END_TIME";
859: value = "" + new Date((long) av.getValue());
860: prefstr = "" + new Date((long) prefval);
861: isDate = true;
862: break;
863: case AspectType.COST:
864: type = "COST";
865: value = "$" + (long) av.getValue();
866: prefstr = "$" + (long) prefval;
867: break;
868: }
869:
870: if (score == ScoringFunction.HIGH_THRESHOLD) {
871: logger.debug("Aspect " + type + "/" + value
872: + " exceeds preference (best = " + prefstr + ")");
873: if ((av.getAspectType() == AspectType.START_TIME)
874: || (av.getAspectType() == AspectType.END_TIME)) {
875: logger.debug("\tDifference (pref-aspect) "
876: + (prefval - av.getValue()) / 60000
877: + " minutes, valid ranges : ");
878: } else
879: logger.debug("\tDifference (pref-aspect) "
880: + (prefval - av.getValue())
881: + ", valid ranges : ");
882:
883: for (; validRanges.hasMoreElements();) {
884: AspectScoreRange range = (AspectScoreRange) validRanges
885: .nextElement();
886: AspectScorePoint start = range.getRangeStartPoint();
887: AspectScorePoint end = range.getRangeEndPoint();
888: double startValue = start.getValue();
889: double endValue = end.getValue();
890:
891: if (isDate)
892: logger.debug("<" + new Date((long) (startValue))
893: + "-" + new Date((long) (endValue)) + "> ");
894: else
895: logger.debug("<" + startValue + "-" + endValue
896: + "> ");
897: }
898: logger.debug("");
899: }
900: }
901:
902: protected Logger logger;
903: protected UTILExpand expand;
904: }
|