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.io.Serializable;
030: import java.util.Enumeration;
031:
032: import org.cougaar.planning.ldm.plan.AllocationResult;
033: import org.cougaar.planning.ldm.plan.AllocationResultAggregator;
034: import org.cougaar.planning.ldm.plan.AspectType;
035: import org.cougaar.planning.ldm.plan.AspectValue;
036: import org.cougaar.planning.ldm.plan.AuxiliaryQueryType;
037: import org.cougaar.planning.ldm.plan.Location;
038: import org.cougaar.planning.ldm.plan.TaskScoreTable;
039: import org.cougaar.planning.ldm.plan.Workflow;
040:
041: /** Does the right computation for workflows which are made up of
042: * equally important tasks with no inter-task constraints.
043: * START_TIME is minimized.
044: * END_TIME is maximized.
045: * DURATION is overall END_TIME - overall START_TIME.
046: * COST is summed.
047: * DANGER is maximized.
048: * RISK is maximized.
049: * QUANTITY is summed.
050: * INTERVAL is summed.
051: * TOTAL_QUANTITY is summed.
052: * TOTAL_SHIPMENTS is summed.
053: * CUSTOMER_SATISFACTION is averaged.
054: * Any extended aspect types are ignored.
055: *
056: * For AuxiliaryQuery information, if all the query values are the same
057: * across subtasks or one subtask has query info it will be place in the
058: * aggregate result. However, if there are conflicting query values, no
059: * information will be put in the aggregated result.
060: *
061: * returns null when there are no subtasks or any task has no result.
062: **/
063: public class UTILAllocationResultAggregator implements
064: AllocationResultAggregator, Serializable {
065: // dummy location
066: private static final class UndefinedLocation implements Location,
067: Serializable {
068: private Object readResolve() {
069: return UNDEFINED_LOCATION;
070: }
071: }
072:
073: public static final Location UNDEFINED_LOCATION = new UndefinedLocation();
074: public static final AspectValue UNDEFINED_POD = AspectValue
075: .newAspectValue(POD, UNDEFINED_LOCATION);
076:
077: /** These are the aspects we handle **/
078: static final int[] _UTIL_ASPECTS = { START_TIME, END_TIME, COST,
079: DANGER, RISK, QUANTITY, INTERVAL, TOTAL_QUANTITY,
080: TOTAL_SHIPMENTS, CUSTOMER_SATISFACTION, READINESS,
081: POD_DATE, POD };
082:
083: /** This is a map from AspectType to acc index - if only we had macros! **/
084: private static final int[] AM = new int[AspectType.N_CORE_ASPECTS];
085: static {
086: for (int i = 0; i < _UTIL_ASPECTS.length; i++) {
087: AM[_UTIL_ASPECTS[i]] = i;
088: }
089: }
090:
091: public AllocationResult calculate(Workflow wf, TaskScoreTable tst,
092: AllocationResult currentar) {
093: AspectValue[] acc = new AspectValue[_UTIL_ASPECTS.length];
094:
095: acc[AM[START_TIME]] = AspectValue.newAspectValue(START_TIME,
096: Long.MAX_VALUE);
097: acc[AM[END_TIME]] = AspectValue.newAspectValue(START_TIME, 0L);
098: // duration is computed from end values of start and end
099: acc[AM[COST]] = AspectValue.newAspectValue(START_TIME, 0);
100: acc[AM[DANGER]] = AspectValue.newAspectValue(DANGER, 0);
101: acc[AM[RISK]] = AspectValue.newAspectValue(RISK, 0);
102: acc[AM[QUANTITY]] = AspectValue.newAspectValue(QUANTITY, 0);
103: acc[AM[INTERVAL]] = AspectValue.newAspectValue(INTERVAL, 0);
104: acc[AM[TOTAL_QUANTITY]] = AspectValue.newAspectValue(
105: TOTAL_QUANTITY, 0.0);
106: acc[AM[TOTAL_SHIPMENTS]] = AspectValue.newAspectValue(
107: TOTAL_SHIPMENTS, 0.0);
108: acc[AM[CUSTOMER_SATISFACTION]] = AspectValue.newAspectValue(
109: CUSTOMER_SATISFACTION, 1.0); // start at best
110: acc[AM[READINESS]] = AspectValue.newAspectValue(READINESS, 1.0);
111: acc[AM[POD_DATE]] = AspectValue.newAspectValue(POD_DATE, 0L);
112: acc[AM[POD]] = UNDEFINED_POD;
113:
114: int count = 0;
115: boolean suc = true;
116: double rating = 0.0;
117:
118: Enumeration tasks = wf.getTasks();
119: if (tasks == null || (!tasks.hasMoreElements()))
120: return null;
121:
122: String auxqsummary[] = new String[AuxiliaryQueryType.AQTYPE_COUNT];
123: // initialize all values to UNDEFINED for comparison purposes below.
124: final String UNDEFINED = "UNDEFINED";
125: for (int aqs = 0; aqs < auxqsummary.length; aqs++) {
126: auxqsummary[aqs] = UNDEFINED;
127: }
128:
129: int tstSize = tst.size();
130: for (int i = 0; i < tstSize; i++) {
131: count++;
132: AllocationResult ar = tst.getAllocationResult(i);
133:
134: if (ar == null) {
135: return null; // bail if undefined
136: }
137:
138: suc = suc && ar.isSuccess();
139: rating += ar.getConfidenceRating();
140:
141: int[] definedaspects = ar.getAspectTypes();
142: for (int b = 0; b < definedaspects.length; b++) {
143: // accumulate the values for the defined aspects
144: switch (definedaspects[b]) {
145: case START_TIME:
146: acc[AM[START_TIME]] = acc[AM[START_TIME]]
147: .dupAspectValue(Math.min(
148: acc[AM[START_TIME]].longValue(), ar
149: .getAspectValue(START_TIME)
150: .longValue()));
151: break;
152: case END_TIME:
153: acc[AM[END_TIME]] = acc[AM[END_TIME]]
154: .dupAspectValue(Math.max(acc[AM[END_TIME]]
155: .longValue(), ar.getAspectValue(
156: END_TIME).longValue()));
157:
158: break;
159: case POD_DATE:
160: acc[AM[POD_DATE]] = acc[AM[POD_DATE]]
161: .dupAspectValue(Math.max(acc[AM[POD_DATE]]
162: .longValue(), ar.getAspectValue(
163: POD_DATE).longValue()));
164: break;
165: case DURATION:
166: break;
167:
168: case COST:
169: acc[AM[COST]] = acc[AM[COST]]
170: .dupAspectValue(acc[AM[COST]].floatValue()
171: + ar.getAspectValue(COST)
172: .floatValue());
173: break;
174: case DANGER:
175: acc[AM[DANGER]] = acc[AM[DANGER]]
176: .dupAspectValue(Math.max(acc[AM[DANGER]]
177: .longValue(), ar.getAspectValue(
178: DANGER).longValue()));
179:
180: break;
181: case RISK:
182: acc[AM[RISK]] = acc[AM[RISK]].dupAspectValue(Math
183: .max(acc[AM[RISK]].longValue(), ar
184: .getAspectValue(RISK).longValue()));
185: break;
186: case QUANTITY:
187: acc[AM[QUANTITY]] = acc[AM[QUANTITY]]
188: .dupAspectValue(acc[AM[QUANTITY]]
189: .floatValue()
190: + ar.getAspectValue(QUANTITY)
191: .floatValue());
192: break;
193: // for now simply add the repetitve task values
194: case INTERVAL:
195: acc[AM[INTERVAL]] = acc[AM[INTERVAL]]
196: .dupAspectValue(acc[AM[INTERVAL]]
197: .longValue()
198: + ar.getAspectValue(INTERVAL)
199: .longValue());
200: break;
201: case TOTAL_QUANTITY:
202: acc[AM[TOTAL_QUANTITY]] = acc[AM[TOTAL_QUANTITY]]
203: .dupAspectValue(acc[AM[TOTAL_QUANTITY]]
204: .floatValue()
205: + ar.getAspectValue(TOTAL_QUANTITY)
206: .floatValue());
207: break;
208: case TOTAL_SHIPMENTS:
209: acc[AM[TOTAL_SHIPMENTS]] = acc[AM[TOTAL_SHIPMENTS]]
210: .dupAspectValue(acc[AM[TOTAL_SHIPMENTS]]
211: .floatValue()
212: + ar
213: .getAspectValue(
214: TOTAL_SHIPMENTS)
215: .floatValue());
216: break;
217: //end of repetitive task specific aspects
218: case CUSTOMER_SATISFACTION:
219: acc[AM[CUSTOMER_SATISFACTION]] = acc[AM[CUSTOMER_SATISFACTION]]
220: .dupAspectValue(acc[AM[CUSTOMER_SATISFACTION]]
221: .floatValue()
222: + ar.getAspectValue(
223: CUSTOMER_SATISFACTION)
224: .floatValue());
225: break;
226: }
227: }
228:
229: // Sum up the auxiliaryquery data. If there are conflicting data
230: // values, send back nothing for that type. If only one subtask
231: // has information about a querytype, send it back in the
232: // aggregated result.
233: for (int aq = 0; aq < AuxiliaryQueryType.AQTYPE_COUNT; aq++) {
234: String data = ar.auxiliaryQuery(aq);
235: if (data != null) {
236: String sumdata = auxqsummary[aq];
237: // if sumdata = null, there has already been a conflict.
238: if (sumdata != null) {
239: if (sumdata.equals(UNDEFINED)) {
240: // there's not a value yet, so use this one.
241: auxqsummary[aq] = data;
242: } else if (!data.equals(sumdata)) {
243: if ((aq == AuxiliaryQueryType.POE_DATE)
244: || (aq == AuxiliaryQueryType.POD_DATE)) {
245: // if we have two different dates, use the earlier one
246: String mydata = "";
247: if (data.compareTo(sumdata) < 0) {
248: mydata = data;
249: } else {
250: mydata = sumdata;
251: }
252: auxqsummary[aq] = mydata;
253: } else
254: // there's a conflict, pass back null
255: // auxqsummary[aq] = "<conflict>";
256: auxqsummary[aq] = null;
257: }
258:
259: }
260: }
261: }
262:
263: } // end of looping through all subtasks
264:
265: acc[AM[DURATION]] = AspectValue.newAspectValue(DURATION,
266: acc[AM[END_TIME]].longValue()
267: - acc[AM[START_TIME]].longValue());
268:
269: acc[AM[CUSTOMER_SATISFACTION]] = acc[AM[CUSTOMER_SATISFACTION]]
270: .dupAspectValue(acc[AM[CUSTOMER_SATISFACTION]]
271: .floatValue()
272: / count);
273:
274: rating /= count;
275:
276: boolean delta = false;
277:
278: // only check the defined aspects and make sure that the currentar is not null
279: if (currentar == null) {
280: delta = true; // if the current ar == null then set delta true
281: } else {
282: int[] caraspects = currentar.getAspectTypes();
283: if (caraspects.length != acc.length) {
284: //if the current ar length is different than the length of the new
285: // calculations (acc) there's been a change
286: delta = true;
287: } else {
288: for (int i = 0; i < caraspects.length; i++) {
289: int da = caraspects[i];
290: if (!acc[AM[da]].equals(currentar
291: .getAspectValue(da))) {
292: delta = true;
293: break;
294: }
295: }
296: }
297:
298: if (!delta) {
299: if (currentar.isSuccess() != suc) {
300: delta = true;
301: } else if (Math.abs(currentar.getConfidenceRating()
302: - rating) > SIGNIFICANT_CONFIDENCE_RATING_DELTA) {
303: delta = true;
304: }
305: }
306: }
307:
308: if (delta) {
309: AllocationResult artoreturn = new AllocationResult(rating,
310: suc, acc);
311: for (int aqt = 0; aqt < auxqsummary.length; aqt++) {
312: String aqdata = auxqsummary[aqt];
313: if ((aqdata != null) && (aqdata != UNDEFINED)) {
314: artoreturn.addAuxiliaryQueryInfo(aqt, aqdata);
315: }
316: }
317: return artoreturn;
318: } else {
319: return currentar;
320: }
321: }
322: }
|