001: package org.cougaar.planning.ldm.measure;
002:
003: import java.io.Serializable;
004: import java.text.DecimalFormat;
005: import java.text.NumberFormat;
006:
007: /**
008: * Generic derivative - represents a fraction of any measure over any other, e.g. Volume/Duration
009: * would be equivalent to the current FlowRate class. Could also be other derivates like Volume/Area, etc.
010: *
011: * @see GenericRate for the Measure/Duration shorthand that comes up a lot
012: */
013: public class GenericDerivative<N extends Measure, D extends Measure>
014: implements Serializable, Derivative {
015: private double theValue;
016: private N numerator;
017: private D denominator;
018: private static final NumberFormat format = new DecimalFormat(
019: "#.###");
020:
021: /** No-arg constructor is only for use by serialization **/
022: public GenericDerivative() {
023: }
024:
025: /** @param num An instance of numerator
026: * @param den An instance of denominator
027: **/
028: public GenericDerivative(N num, D den) {
029: double numInCommonUnit = num.getValue(num.getCommonUnit());
030: double denInCommonUnit = den.getValue(den.getCommonUnit());
031: theValue = numInCommonUnit / denInCommonUnit;
032:
033: //System.err.println("num " + numInCommonUnit + " denom " + denInCommonUnit + " value " + theValue);
034: numerator = num;
035: denominator = den;
036: }
037:
038: public int getCommonUnit() {
039: return 0;
040: }
041:
042: /**
043: * TODO : Not sure what to do here.
044: * @paramx denom
045: * @return
046: */
047: /* public <D extends Measure> GenericDerivative newGenericDerivative(D denom) {
048: //return new GenericDerivative<<GenericDerivative<N,D>>,D>(this, denom);
049: return null;
050: }*/
051:
052: public int getMaxUnit() {
053: return numerator.getMaxUnit() * denominator.getMaxUnit();
054: }
055:
056: /** @param unit One of the constant units of **/
057: public final String getUnitName(int unit) {
058: return numerator.getUnitName(unit / denominator.getMaxUnit())
059: + "/"
060: + denominator.getUnitName(unit
061: % denominator.getMaxUnit());
062: }
063:
064: /** @paramx num An instance of num to use as numerator
065: * @paramx den An instance of denom use as denominator
066: * @return generic rate
067: **/
068: /*
069: public static final newGenericDerivative newGenericRate(Measure num, Measure den) {
070: return new newGenericDerivative(num.getValue(0)/den.getValue(0));
071: }
072: */
073:
074: // simple math : addition and subtraction
075: public Measure add(Measure toAdd) {
076: return add((GenericDerivative<N, D>) toAdd);
077: }
078:
079: public Measure subtract(Measure toSubtract) {
080: return subtract((GenericDerivative<N, D>) toSubtract);
081: }
082:
083: public GenericDerivative<N, D> add(GenericDerivative<N, D> toAdd) {
084: if (denominator.equals(toAdd.denominator)) {
085: N newNumer = (N) numerator.add(toAdd.numerator);
086: return newInstance(newNumer, denominator);
087: }
088:
089: D commonDenom = (D) denominator.scale(toAdd.denominator
090: .getNativeValue());
091: double otherNumerUnitless = toAdd.numerator.getNativeValue();
092: double otherDenomUnitless = toAdd.denominator.getNativeValue();
093: double leftNumerator = numerator.getNativeValue()
094: * otherDenomUnitless;
095: double rightNumerator = otherNumerUnitless
096: * denominator.getNativeValue();
097:
098: N newNumer = (N) numerator.valueOf(leftNumerator
099: + rightNumerator);
100:
101: return newInstance(newNumer, commonDenom);
102: }
103:
104: public GenericDerivative<N, D> subtract(
105: GenericDerivative<N, D> toSubtract) {
106: return add((GenericDerivative<N, D>) toSubtract.negate());
107: }
108:
109: public N multiply(D other) {
110: return (N) numerator.scale(other.getNativeValue()
111: / denominator.getNativeValue());
112: }
113:
114: /** @param unit1 One of the constant units of Numer
115: * @param unit2 One of the constant units of Denom
116: **/
117: public double getValue(int unit1, int unit2) {
118: if (unit1 >= 0 && unit1 <= numerator.getMaxUnit() && unit2 >= 0
119: && unit2 <= denominator.getMaxUnit())
120: return (numerator.getValue(unit1) / denominator
121: .getValue(unit2));
122: else
123: throw new UnknownUnitException();
124: }
125:
126: public double getValue(int unit) {
127: if (denominator == null) {
128: return 0;
129: }
130: return getValue(unit / denominator.getMaxUnit(), unit
131: % denominator.getMaxUnit());
132: }
133:
134: public boolean equals(Object o) {
135: return (o instanceof GenericDerivative && theValue == ((GenericDerivative) o).theValue);
136: }
137:
138: public String toString() {
139: if (numerator == null) {
140: return "numerator null";
141: }
142: if (denominator == null) {
143: return "denominator null";
144: }
145: String numeratorUnit = numerator.getUnitName(numerator
146: .getCommonUnit());
147: String denominatorUnit = denominator.getUnitName(denominator
148: .getCommonUnit());
149: String formatted;
150: synchronized (format) {
151: formatted = format.format(getValue(getCommonUnit()));
152: }
153: return formatted + " " + numeratorUnit + "/" + denominatorUnit;
154: }
155:
156: public int hashCode() {
157: return (new Double(theValue)).hashCode();
158: }
159:
160: // Derivative
161: public final Class getNumeratorClass() {
162: return numerator.getClass();
163: }
164:
165: public final Class getDenominatorClass() {
166: return denominator.getClass();
167: }
168:
169: public Measure computeNumerator(Measure denominator) {
170: return multiply((D) denominator);
171: }
172:
173: public Measure getCanonicalDenominator() {
174: return denominator.valueOf(0);
175: }
176:
177: public Measure getCanonicalNumerator() {
178: return numerator.valueOf(0);
179: }
180:
181: public Measure negate() {
182: return scale(-1);
183: }
184:
185: public Measure scale(double scale) {
186: N newNumer = (N) numerator.scale(scale);
187: return newInstance(newNumer, denominator);
188: }
189:
190: /**
191: * Does floor of numerator and denominator.
192: *
193: * May not be what you want
194: * @return floor value
195: */
196: public Measure floor(int unit) {
197: return floor(unit % numerator.getMaxUnit(), unit
198: / denominator.getMaxUnit());
199: }
200:
201: public Measure floor(int numeratorUnit, int denominatorUnit) {
202: return newInstance((N) numerator.floor(numeratorUnit),
203: (D) denominator.floor(denominatorUnit));
204: }
205:
206: /**
207: * Only way to make an instance of the object
208: *
209: * @param numerator to use
210: * @param denominator to use
211: * @return new instance of this derivative or subclass
212: */
213: protected GenericDerivative<N, D> newInstance(N numerator,
214: D denominator) {
215: return new GenericDerivative<N, D>(numerator, denominator);
216: }
217:
218: /**
219: * This is a rate in the common unit of the numerator, by the denominator.
220: *
221: * So for instance if this rate is 10 gallons/hr, valueOf (5) would be 5 liters/hour,
222: * since liters is Volume's common unit.
223: * @param value to use for numerator
224: * @return GenericDerivative instance or subclass
225: */
226: public Measure valueOf(double value) {
227: return newInstance((N) numerator.valueOf(value), denominator);
228: }
229:
230: /**
231: * This is a rate in the specified unit of the numerator, by the denominator.
232: *
233: * So for instance if this rate is 10 gallons/hr, valueOf (5, Volume.GALLONS)
234: * would be 5 gallons/hour.
235: *
236: * @param value to use for numerator
237: * @return GenericDerivative instance or subclass
238: */
239: public Measure valueOf(double value, int unit) {
240: return newInstance((N) numerator.valueOf(value, unit),
241: denominator);
242: }
243:
244: public int getNativeUnit() {
245: return 0;
246: }
247:
248: public double getNativeValue() {
249: return theValue;
250: }
251:
252: public final Duration divide(Rate toRate) {
253: throw new IllegalArgumentException(
254: "Call divideRate instead to divide one Rate by another.");
255: }
256:
257: public final double divideRate(Rate toRate) {
258: if (toRate.getCanonicalNumerator().getClass() != getCanonicalNumerator()
259: .getClass()
260: || toRate.getCanonicalDenominator().getClass() != getCanonicalDenominator()
261: .getClass()) {
262: throw new IllegalArgumentException(
263: "Expecting a GenericDerivative"
264: + ", got a "
265: + toRate.getCanonicalNumerator().getClass()
266: + "/"
267: + toRate.getCanonicalDenominator()
268: .getClass());
269: }
270: return theValue / toRate.getNativeValue();
271: }
272:
273: public Measure min(Measure other) {
274: return (compareTo(other) <= 0 ? this : other);
275: }
276:
277: public Measure max(Measure other) {
278: return (compareTo(other) >= 0 ? this : other);
279: }
280:
281: public Measure apply(UnaryOperator op) {
282: return op.apply(this );
283: }
284:
285: public Measure apply(BinaryOperator op, Measure other) {
286: return op.apply(this , other);
287: }
288:
289: public int compareTo(Object o) {
290: double da = theValue;
291: double db;
292: if (o == null) {
293: db = 0.0;
294: } else {
295: GenericDerivative<N, D> gd = (GenericDerivative<N, D>) o;
296: if (!isSameClass(numerator, gd.numerator)
297: || !isSameClass(denominator, gd.denominator)) {
298: throw new IllegalArgumentException(
299: "Incompatible types:\n " + this + "\" " + o);
300: }
301: db = gd.getNativeValue();
302: }
303: return (da < db ? -1 : da > db ? 1 : 0);
304: }
305:
306: private static final boolean isSameClass(Object a, Object b) {
307: return (a == null ? b == null : b != null
308: && a.getClass() == b.getClass());
309: }
310:
311: // serialization
312: /* public void writeExternal(ObjectOutput out) throws IOException {
313: out.writeDouble(theValue);
314: out.write
315: }
316: public void readExternal(ObjectInput in) throws IOException {
317: theValue = in.readDouble();
318: }*/
319: }
|