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:
031: import org.cougaar.util.MoreMath;
032:
033: /** AspectValue is the essential "value" abstraction with respect to
034: * evaluation of the goodness or correctness of a particular solution.
035: * AspectValues are no longer mutable and no longer implement AspectType.
036: * @see AllocationResult
037: */
038:
039: public abstract class AspectValue implements Serializable {
040: //
041: // Factories
042: //
043:
044: // MIK - we might want to optimize the "standard" cases to avoid
045: // boxing the primatives.
046:
047: public static final AspectValue newAspectValue(int type, long value) {
048: return newAspectValue(type, new Long(value));
049: }
050:
051: public static final AspectValue newAspectValue(int type,
052: double value) {
053: return newAspectValue(type, new Double(value));
054: }
055:
056: public static final AspectValue newAspectValue(int type, float value) {
057: return newAspectValue(type, new Float(value));
058: }
059:
060: public static final AspectValue newAspectValue(int type, int value) {
061: return newAspectValue(type, new Integer(value));
062: }
063:
064: public static final AspectValue newAspectValue(int type, Object o) {
065: AspectType.Factory f = AspectType.registry.get(type);
066: if (f == null) {
067: throw new IllegalArgumentException("Type " + type
068: + " is not a known Aspect type");
069: } else {
070: try {
071: return f.newAspectValue(o);
072: } catch (IllegalArgumentException iae) {
073: throw new RuntimeException(
074: "Unable to create new AspectValue(" + type
075: + ", " + o + ")", iae);
076: }
077: }
078: }
079:
080: public static final AspectValue newAspectValue(
081: AspectType.Factory type, Object o) {
082: return type.newAspectValue(o);
083: }
084:
085: public static final AspectValue newAspectValue(
086: AspectType.Factory type, long value) {
087: return newAspectValue(type, new Long(value));
088: }
089:
090: public static final AspectValue newAspectValue(
091: AspectType.Factory type, double value) {
092: return newAspectValue(type, new Double(value));
093: }
094:
095: public static final AspectValue newAspectValue(
096: AspectType.Factory type, float value) {
097: return newAspectValue(type, new Float(value));
098: }
099:
100: public static final AspectValue newAspectValue(
101: AspectType.Factory type, int value) {
102: return newAspectValue(type, new Integer(value));
103: }
104:
105: //
106: // pseudo-factories
107: //
108:
109: /** factory for possibly creating a new AspectValue with the same type
110: * but a different value.
111: **/
112: public AspectValue dupAspectValue(double newvalue) {
113: return (doubleValue() == newvalue) ? this : newAspectValue(
114: getType(), newvalue);
115: }
116:
117: public AspectValue dupAspectValue(float newvalue) {
118: return (floatValue() == newvalue) ? this : newAspectValue(
119: getType(), newvalue);
120: }
121:
122: public AspectValue dupAspectValue(long newvalue) {
123: return (longValue() == newvalue) ? this : newAspectValue(
124: getType(), newvalue);
125: }
126:
127: public AspectValue dupAspectValue(int newvalue) {
128: return (intValue() == newvalue) ? this : newAspectValue(
129: getType(), newvalue);
130: }
131:
132: //
133: // accessors
134: //
135:
136: /** Non-preferred alias for #getType()
137: * @note may be deprecated in the future - use getType instead.
138: */
139: public int getAspectType() {
140: return getType();
141: }
142:
143: /** @return int The Aspect Type.
144: * @see org.cougaar.planning.ldm.plan.AspectType
145: */
146: public abstract int getType();
147:
148: /** Non-preferred alias for #doubleValue().
149: * @note may be deprecated in the future - use doubleValue instead.
150: */
151: public double getValue() {
152: return doubleValue();
153: }
154:
155: /** The value of the aspect as a double. */
156: public abstract double doubleValue();
157:
158: /** The value of the aspect as a float **/
159: public abstract float floatValue();
160:
161: /** The value of the aspect as a long **/
162: public abstract long longValue();
163:
164: /** The value of the aspect as an int **/
165: public abstract int intValue();
166:
167: //
168: // comparisons
169: //
170:
171: public boolean nearlyEquals(Object o) {
172: if (o instanceof AspectValue) {
173: AspectValue that = (AspectValue) o;
174: if (this .getAspectType() == that.getAspectType()) {
175: return MoreMath.nearlyEquals(this .getValue(), that
176: .getValue());
177: }
178: }
179: return false;
180: }
181:
182: public boolean isLessThan(AspectValue v) {
183: return (getValue() < v.getValue());
184: }
185:
186: public boolean isGreaterThan(AspectValue v) {
187: return (getValue() > v.getValue());
188: }
189:
190: public double minus(AspectValue v) {
191: return getValue() - v.getValue();
192: }
193:
194: public boolean isBetween(AspectValue low, AspectValue hi) {
195: return (!(isLessThan(low) || isGreaterThan(hi)));
196: }
197:
198: //
199: // basic object methods
200:
201: // //Too difficult to maintain
202: // public boolean equals(AspectValue v) {
203: // return (v.getType() == getType() &&
204: // v.getValue() == getValue());
205: // }
206:
207: public boolean equals(Object v) {
208: if (v instanceof AspectValue) {
209: return (getType() == ((AspectValue) v).getType() && getValue() == ((AspectValue) v)
210: .getValue());
211: } else {
212: return false;
213: }
214: }
215:
216: public int hashCode() {
217: return getType() + (((int) getValue()) << 2);
218: }
219:
220: public String toString() {
221: return Double.toString(getValue()) + "[" + getType() + "]";
222: }
223:
224: /////// statics
225:
226: /**
227: * This should be in AspectType, but that's an interface and can't
228: * have methods. This is the closest place that makes any sense and
229: * avoids creating a new class just to convert aspect types into
230: * strings.
231: **/
232: public static String aspectTypeToString(int aspectType) {
233: if (aspectType >= 0
234: && aspectType < AspectType.ASPECT_STRINGS.length) {
235: return AspectType.ASPECT_STRINGS[aspectType];
236: } else {
237: return String.valueOf(aspectType);
238: }
239: }
240:
241: /**
242: * Clone an array of AspectValue. Does not, of course, clone the elements
243: * since they are immutable.
244: * @param avs an array of AspectValue
245: * @return a copy of the array with copies of array element values.
246: **/
247: public static AspectValue[] clone(AspectValue[] avs) {
248: AspectValue[] result = new AspectValue[avs.length];
249: for (int i = 0; i < avs.length; i++) {
250: result[i] = avs[i];
251: }
252: return result;
253: }
254:
255: /**
256: * Compare two arrays of AspectValues. Since the values are not
257: * necessarily in the same order, we first check assuming they are
258: * in the same order. If that fails because they are not in the same
259: * order, we try again reordering the values as needed. Arrays
260: * having repeated AspectTypes produce unspecified results. Such
261: * arrays are intrinsically ambiguous.
262: **/
263: public static boolean equals(AspectValue[] avs1, AspectValue[] avs2) {
264: int len = avs1.length;
265: if (len != avs2.length)
266: return false; // Can't be equal if different length
267: outer: for (int i = 0; i < len; i++) {
268: AspectValue av1 = avs1[i];
269: int type1 = av1.getAspectType();
270: inner: for (int j = 0; j < len; j++) {
271: int k = (i + j) % len;
272: AspectValue av2 = avs2[k];
273: int type2 = av2.getAspectType();
274: if (type1 == type2) {
275: if (av1.equals(av2))
276: continue outer;
277: break inner;
278: }
279: }
280: return false; // Found no match
281: }
282: return true; // Found a match for every aspect
283: }
284:
285: public static boolean nearlyEquals(AspectValue[] avs1,
286: AspectValue[] avs2) {
287: int len = avs1.length;
288: if (len != avs2.length)
289: return false; // Can't be equal if different length
290: outer: for (int i = 0; i < len; i++) {
291: AspectValue av1 = avs1[i];
292: int type1 = av1.getAspectType();
293: inner: for (int j = 0; j < len; j++) {
294: int k = (i + j) % len;
295: AspectValue av2 = avs2[k];
296: int type2 = av2.getAspectType();
297: if (type1 == type2) {
298: if (av1.nearlyEquals(av2))
299: continue outer;
300: break inner;
301: }
302: }
303: return false; // Found no match
304: }
305: return true; // Found a match for every aspect
306: }
307:
308: }
|