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.planning.ldm.plan;
028:
029: import java.util.ArrayList;
030: import java.util.Arrays;
031: import java.util.Enumeration;
032: import java.util.List;
033: import java.util.ListIterator;
034:
035: import org.cougaar.planning.ldm.asset.Asset;
036:
037: /** Simple Aggregator for AllocationResults specified with AspectValues.
038: * Particularly useful for results with TypedQuantityAspects.
039: * Does the right computation for workflows which are made up of
040: * equally important tasks with no inter-task constraints.
041: * START_TIME is minimized.
042: * END_TIME is maximized.
043: * DURATION is overall END_TIME - overall START_TIME.
044: * COST is summed.
045: * DANGER is maximized.
046: * RISK is maximized.
047: * QUANTITY is summed.
048: * INTERVAL is summed.
049: * TOTAL_QUANTITY is summed.
050: * TOTAL_SHIPMENTS is summed.
051: * CUSTOMER_SATISFACTION is averaged.
052: * TYPED_QUANTITY is summed for each type(asset).
053: *
054: * For AuxiliaryQuery information, if all the query values are the same
055: * across subtasks or one subtask has query info it will be place in the
056: * aggregate result. However, if there are conflicting query values, no
057: * information will be put in the aggregated result.
058: *
059: * returns null when there are no subtasks or any task has no result.
060: *
061: *
062: **/
063: public class SimpleAspectValueARA implements AllocationResultAggregator {
064: public AllocationResult calculate(Workflow wf, TaskScoreTable tst,
065: AllocationResult currentar) {
066: List aggregAR = new ArrayList();
067: boolean suc = true;
068: double rating = 0.0;
069: int count = 0;
070:
071: Enumeration tasks = wf.getTasks();
072: if (tasks == null || (!tasks.hasMoreElements()))
073: return null;
074:
075: String auxqsummary[] = new String[AuxiliaryQueryType.AQTYPE_COUNT];
076: // initialize all values to UNDEFINED for comparison purposes below.
077: final String UNDEFINED = "UNDEFINED";
078: for (int aqs = 0; aqs < auxqsummary.length; aqs++) {
079: auxqsummary[aqs] = UNDEFINED;
080: }
081:
082: while (tasks.hasMoreElements()) {
083: Task t = (Task) tasks.nextElement();
084: count++;
085: AllocationResult ar = tst.getAllocationResult(t);
086: if (ar == null) {
087: return null; // bail if undefined
088: }
089:
090: suc = suc && ar.isSuccess();
091: rating += ar.getConfidenceRating();
092:
093: AspectValue[] someresults = ar.getAspectValueResults();
094:
095: for (int b = 0; b < someresults.length; b++) {
096: AspectValue sumav = null;
097: AspectValue srav = someresults[b];
098: int this at = srav.getAspectType();
099: for (ListIterator lit = aggregAR.listIterator(); lit
100: .hasNext();) {
101: AspectValue this av = (AspectValue) lit.next();
102: if (this av.getAspectType() == this at) {
103: if (this at != TYPED_QUANTITY) {
104: sumav = this av;
105: } else {
106: // check the asset
107: Asset tqasset = ((TypedQuantityAspectValue) this av)
108: .getAsset();
109: if (tqasset
110: .equals(((TypedQuantityAspectValue) srav)
111: .getAsset())) {
112: sumav = this av;
113: }
114: }
115: }
116: }
117: // if we still don't have a matching sum AspectValue, make a new one for this aspect
118: if (sumav == null) {
119: sumav = srav; // First time, just clone the value
120: aggregAR.add(sumav);
121: } else {
122: switch (this at) {
123: case START_TIME:
124: double nst = Math.min(sumav.getValue(), srav
125: .getValue());
126: sumav = sumav.dupAspectValue(nst);
127: break;
128: case END_TIME:
129: case DANGER:
130: case RISK:
131: double newmaxv = Math.max(sumav.getValue(),
132: srav.getValue());
133: sumav = sumav.dupAspectValue(newmaxv);
134: break;
135: default:
136: // if its anything else its a simple summation, even for TYPED_QUANTITY
137: double newsumv = sumav.getValue()
138: + srav.getValue();
139: sumav = sumav.dupAspectValue(newsumv);
140: }
141: }
142: } // end of for loop for allocationresult aspecttypes
143:
144: // Sum up the auxiliaryquery data. If there are conflicting data
145: // values, send back nothing for that type. If only one subtask
146: // has information about a querytype, send it back in the
147: // aggregated result.
148: for (int aq = 0; aq < AuxiliaryQueryType.AQTYPE_COUNT; aq++) {
149: String data = ar.auxiliaryQuery(aq);
150: if (data != null) {
151: String sumdata = auxqsummary[aq];
152: if (sumdata.equals(UNDEFINED)) {
153: // there's not a value yet, so use this one.
154: auxqsummary[aq] = data;
155: } else if (!data.equals(sumdata)) {
156: // there's a conflict, pass back null
157: auxqsummary[aq] = null;
158: }
159: }
160: }
161:
162: } // end of while looping through tasks.
163:
164: // now make AspectVales for DURATION and CUSTOMER_SATISFACTION
165: double overallstart = 0.0;
166: double overallend = 0.0;
167: for (ListIterator l = aggregAR.listIterator(); l.hasNext();) {
168: AspectValue timeav = (AspectValue) l.next();
169: int timeavaspect = timeav.getAspectType();
170: if (timeavaspect == START_TIME) {
171: overallstart = timeav.getValue();
172: } else if (timeavaspect == END_TIME) {
173: overallend = timeav.getValue();
174: }
175: }
176: // if the start time and end time are defined, find or create a duration aspectvalue
177: AspectValue theduration = null;
178: if ((overallstart != 0.0) && (overallend != 0.0)) {
179: for (ListIterator litdur = aggregAR.listIterator(); litdur
180: .hasNext();) {
181: AspectValue durav = (AspectValue) litdur.next();
182: if (DURATION == durav.getAspectType()) {
183: theduration = durav;
184: // reset the value
185: durav = durav.dupAspectValue(overallend
186: - overallstart);
187: }
188: }
189: // if we didn't find a duration av, create one
190: if (theduration == null) {
191: AspectValue duration = AspectValue.newAspectValue(
192: AspectType.Duration, overallend - overallstart);
193: aggregAR.add(duration);
194: }
195: }
196:
197: // if there is a CUSTOMER_SATISFACTION av, divide the total sum by the number of tasks
198: for (ListIterator litcs = aggregAR.listIterator(); litcs
199: .hasNext();) {
200: AspectValue csav = (AspectValue) litcs.next();
201: if (CUSTOMER_SATISFACTION == csav.getAspectType()) {
202: csav = csav.dupAspectValue(csav.getValue() / count);
203: }
204: }
205:
206: rating /= count;
207:
208: boolean delta = true;
209: if (currentar != null) {
210: AspectValue[] currentavs = currentar
211: .getAspectValueResults();
212: List currentlist = Arrays.asList(currentavs);
213: if (currentlist.equals(aggregAR)
214: && currentar.getConfidenceRating() == rating
215: && currentar.isSuccess() == suc) {
216: // there are no changes
217: delta = false;
218: }
219: }
220:
221: if (delta) {
222: AspectValue[] newreturnresults = (AspectValue[]) aggregAR
223: .toArray(new AspectValue[aggregAR.size()]);
224: AllocationResult artoreturn = new AllocationResult(rating,
225: suc, newreturnresults);
226: // fill in the auxquery stuff
227: for (int aqt = 0; aqt < auxqsummary.length; aqt++) {
228: String aqdata = auxqsummary[aqt];
229: if ((aqdata != null) && (aqdata != UNDEFINED)) {
230: artoreturn.addAuxiliaryQueryInfo(aqt, aqdata);
231: }
232: }
233: return artoreturn;
234: } else {
235: return currentar;
236: }
237: }
238: }
|