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.io.Serializable;
030: import java.util.HashMap;
031:
032: /** AllocationResultAggregator is a class which specifies how allocationresults
033: * should be aggregated. Currenlty used by Workflow.computeAllocationResult
034: * @see org.cougaar.planning.ldm.plan.AllocationResult
035: **/
036:
037: public interface AllocationResultAggregator extends Serializable,
038: AspectType // for Constants
039: {
040: double SIGNIFICANT_CONFIDENCE_RATING_DELTA = 0.0001;
041:
042: /** @return AllocationResult The computed AllocationResult
043: * @param wf The workflow that is using this aggregator to compute it's AllocationResult
044: * @param tst The TaskScoreTable associated with this workflow
045: * @param currentar The current AllocationResult
046: * @see Workflow
047: * @see TaskScoreTable
048: **/
049: AllocationResult calculate(Workflow wf, TaskScoreTable tst,
050: AllocationResult currentar);
051:
052: /** static accessor for a default/generic AllocationResultAggregator that does
053: * a simple summation of all measures (including extensions) found in all allocationresults in the
054: * subtasks of the workflow.
055: */
056: AllocationResultAggregator SUM = new Sum();
057:
058: AllocationResultAggregator DEFAULT = new DefaultARA();
059:
060: // implementation of a default/generic AllocationResultAggregator
061: class Sum implements AllocationResultAggregator {
062: public Sum() {
063: }
064:
065: public AllocationResult calculate(Workflow wf,
066: TaskScoreTable tst, AllocationResult currentar) {
067: // write new implementation - stub for now.
068: return null;
069: }
070: } // end of Sum class
071:
072: /** Does the right computation for workflows which are made up of
073: * equally important tasks with no inter-task constraints.
074: * START_TIME is minimized.
075: * END_TIME is maximized.
076: * DURATION is overall END_TIME - overall START_TIME.
077: * COST is summed.
078: * DANGER is maximized.
079: * RISK is maximized.
080: * QUANTITY is summed.
081: * INTERVAL is summed.
082: * TOTAL_QUANTITY is summed.
083: * TOTAL_SHIPMENTS is summed.
084: * CUSTOMER_SATISFACTION is averaged.
085: * READINESS is minimized.
086: * Any extended aspect types are ignored.
087: *
088: * For AuxiliaryQuery information, if all the query values are the same
089: * across subtasks or one subtask has query info it will be place in the
090: * aggregate result. However, if there are conflicting query values, no
091: * information will be put in the aggregated result.
092: *
093: * returns null when there are no subtasks or any task has no result.
094: **/
095: class DefaultARA implements AllocationResultAggregator {
096: private static final String UNDEFINED = "UNDEFINED";
097:
098: public AllocationResult calculate(Workflow wf,
099: TaskScoreTable tst, AllocationResult currentar) {
100: double acc[] = new double[AspectType._ASPECT_COUNT];
101: acc[START_TIME] = Double.MAX_VALUE;
102: acc[END_TIME] = 0.0;
103: // duration is computed from end values of start and end
104: acc[COST] = 0.0;
105: acc[DANGER] = 0.0;
106: acc[RISK] = 0.0;
107: acc[QUANTITY] = 0.0;
108: acc[INTERVAL] = 0.0;
109: acc[TOTAL_QUANTITY] = 0.0;
110: acc[TOTAL_SHIPMENTS] = 0.0;
111: acc[CUSTOMER_SATISFACTION] = 1.0; // start at best
112: acc[READINESS] = 1.0;
113:
114: boolean ap[] = new boolean[AspectType._ASPECT_COUNT];
115:
116: boolean suc = true;
117: double rating = 0.0;
118:
119: if (tst == null)
120: return null;
121: int tstSize = tst.size();
122: if (tstSize == 0)
123: return null;
124:
125: String auxqsummary[] = new String[AuxiliaryQueryType.AQTYPE_COUNT];
126: // initialize all values to UNDEFINED for comparison purposes below.
127: int aql = auxqsummary.length;
128: for (int aqs = 0; aqs < aql; aqs++) {
129: auxqsummary[aqs] = UNDEFINED;
130: }
131:
132: int hash = 0;
133: for (int i = 0; i < tstSize; i++) {
134: AllocationResult ar = tst.getAllocationResult(i);
135: if (ar == null)
136: return null; // bail if undefined
137:
138: suc = suc && ar.isSuccess();
139: rating += ar.getConfidenceRating();
140:
141: int[] definedaspects = ar.getAspectTypes();
142: int al = definedaspects.length;
143: for (int b = 0; b < al; b++) {
144: // accumulate the values for the defined aspects
145: switch (definedaspects[b]) {
146: case START_TIME:
147: acc[START_TIME] = Math.min(acc[START_TIME], ar
148: .getValue(START_TIME));
149: ap[START_TIME] = true;
150: hash |= (1 << START_TIME);
151: break;
152: case END_TIME:
153: acc[END_TIME] = Math.max(acc[END_TIME], ar
154: .getValue(END_TIME));
155: ap[END_TIME] = true;
156: hash |= (1 << END_TIME);
157: break;
158: // compute duration later
159: case COST:
160: acc[COST] += ar.getValue(COST);
161: ap[COST] = true;
162: hash |= (1 << COST);
163: break;
164: case DANGER:
165: acc[DANGER] = Math.max(acc[DANGER], ar
166: .getValue(DANGER));
167: ap[DANGER] = true;
168: hash |= (1 << DANGER);
169: break;
170: case RISK:
171: acc[RISK] = Math.max(acc[RISK], ar
172: .getValue(RISK));
173: ap[RISK] = true;
174: hash |= (1 << RISK);
175: break;
176: case QUANTITY:
177: acc[QUANTITY] += ar.getValue(QUANTITY);
178: ap[QUANTITY] = true;
179: hash |= (1 << QUANTITY);
180: break;
181: // for now simply add the repetitve task values
182: case INTERVAL:
183: acc[INTERVAL] += ar.getValue(INTERVAL);
184: ap[INTERVAL] = true;
185: hash |= (1 << INTERVAL);
186: break;
187: case TOTAL_QUANTITY:
188: acc[TOTAL_QUANTITY] += ar
189: .getValue(TOTAL_QUANTITY);
190: ap[TOTAL_QUANTITY] = true;
191: hash |= (1 << TOTAL_QUANTITY);
192: break;
193: case TOTAL_SHIPMENTS:
194: acc[TOTAL_SHIPMENTS] += ar
195: .getValue(TOTAL_SHIPMENTS);
196: ap[TOTAL_SHIPMENTS] = true;
197: hash |= (1 << TOTAL_SHIPMENTS);
198: break;
199: //end of repetitive task specific aspects
200: case CUSTOMER_SATISFACTION:
201: acc[CUSTOMER_SATISFACTION] += ar
202: .getValue(CUSTOMER_SATISFACTION);
203: ap[CUSTOMER_SATISFACTION] = true;
204: hash |= (1 << CUSTOMER_SATISFACTION);
205: break;
206: case READINESS:
207: acc[READINESS] = Math.min(acc[READINESS], ar
208: .getValue(READINESS));
209: ap[READINESS] = true;
210: hash |= (1 << READINESS);
211: break;
212: }
213: }
214:
215: // Sum up the auxiliaryquery data. If there are conflicting data
216: // values, send back nothing for that type. If only one subtask
217: // has information about a querytype, send it back in the
218: // aggregated result.
219: for (int aq = 0; aq < AuxiliaryQueryType.AQTYPE_COUNT; aq++) {
220: String data = ar.auxiliaryQuery(aq);
221: if (data != null) {
222: String sumdata = auxqsummary[aq];
223: // if sumdata = null, there has already been a conflict.
224: if (sumdata != null) {
225: if (sumdata.equals(UNDEFINED)) {
226: // there's not a value yet, so use this one.
227: auxqsummary[aq] = data;
228: } else if (!data.equals(sumdata)) {
229: // there's a conflict, pass back null
230: auxqsummary[aq] = null;
231: }
232: }
233: }
234: }
235:
236: } // end of looping through all subtasks
237:
238: // compute duration IFF defined.
239: if (ap[START_TIME] && ap[END_TIME]) {
240: acc[DURATION] = acc[END_TIME] - acc[START_TIME];
241: ap[DURATION] = true;
242: hash |= (1 << DURATION);
243: } else {
244: // redundant
245: acc[DURATION] = 0.0;
246: ap[DURATION] = false;
247: }
248:
249: if (tstSize > 0) {
250: acc[CUSTOMER_SATISFACTION] /= tstSize;
251: rating /= tstSize;
252: }
253:
254: boolean delta = false;
255:
256: // only check the defined aspects and make sure that the currentar is not null
257: if (currentar == null) {
258: delta = true; // if the current ar == null then set delta true
259: } else {
260: int[] caraspects = currentar.getAspectTypes();
261: if (caraspects.length != acc.length) {
262: //if the current ar length is different than the length of the new
263: // calculations (acc) there's been a change
264: delta = true;
265: } else {
266: int il = caraspects.length;
267: for (int i = 0; i < il; i++) {
268: int da = caraspects[i];
269: if (ap[da] && acc[da] != currentar.getValue(da)) {
270: delta = true;
271: break;
272: }
273: }
274: }
275:
276: if (!delta) {
277: if (currentar.isSuccess() != suc) {
278: delta = true;
279: } else if (Math.abs(currentar.getConfidenceRating()
280: - rating) > SIGNIFICANT_CONFIDENCE_RATING_DELTA) {
281: delta = true;
282: }
283: }
284: }
285:
286: if (delta) {
287: int keys[] = _STANDARD_ASPECTS;
288: int al = AspectType._ASPECT_COUNT;
289:
290: // see if we should compress the results array
291: int lc = 0;
292: for (int b = 0; b < al; b++) {
293: if (ap[b])
294: lc++;
295: }
296:
297: if (lc < al) { // need to compress the arrays
298: double nv[] = new double[lc];
299:
300: // slow, big, general case
301: /*
302: {
303: int nk[] = new int[lc];
304: int i = 0;
305: for (int b = 0; b<al; b++) {
306: if (ap[b]) {
307: nv[i] = acc[b];
308: nk[i] = keys[b];
309: i++;
310: }
311: }
312: acc = nv;
313: keys = nk;
314: }
315: */
316:
317: // lazy cache the key patterns
318: synchronized (hack) {
319: Integer ihash = new Integer(hash);
320: KeyHolder kh = (KeyHolder) hack.get(ihash);
321: if (kh == null) {
322: //System.err.println("Caching key "+hash);
323: int nk[] = new int[lc];
324: int i = 0;
325: for (int b = 0; b < al; b++) {
326: if (ap[b]) {
327: nv[i] = acc[b];
328: nk[i] = keys[b];
329: i++;
330: }
331: }
332: acc = nv;
333: keys = nk;
334: kh = new KeyHolder(nk);
335: hack.put(ihash, kh);
336: } else {
337: keys = kh.keys;
338: int i = 0;
339: for (int b = 0; b < al; b++) {
340: if (ap[b]) {
341: nv[i] = acc[b];
342: i++;
343: }
344: }
345: acc = nv;
346: }
347: }
348:
349: }
350:
351: AllocationResult artoreturn = new AllocationResult(
352: rating, suc, keys, acc);
353:
354: for (int aqt = 0; aqt < aql; aqt++) {
355: String aqdata = auxqsummary[aqt];
356: if ((aqdata != null) && (aqdata != UNDEFINED)) {
357: artoreturn.addAuxiliaryQueryInfo(aqt, aqdata);
358: }
359: }
360: return artoreturn;
361: } else {
362: return currentar;
363: }
364: }
365: }
366:
367: int[] K02 = new int[] { 0, 2 };
368: int[] K012 = new int[] { 0, 1, 2 };
369: int[] K0126 = new int[] { 0, 1, 2, 6 };
370:
371: HashMap hack = new HashMap();
372:
373: final class KeyHolder {
374: public int[] keys;
375:
376: public KeyHolder(int keys[]) {
377: this.keys = keys;
378: }
379: }
380: }
|