001/* A token for QSS integration that contains a double and a derivative.
002
003   Copyright (c) 2014-2018 The Regents of the University of California.
004   All rights reserved.
005   Permission is hereby granted, without written agreement and without
006   license or royalty fees, to use, copy, modify, and distribute this
007   software and its documentation for any purpose, provided that the above
008   copyright notice and the following two paragraphs appear in all copies
009   of this software.
010
011   IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012   FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013   ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014   THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015   SUCH DAMAGE.
016
017   THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020   PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021   CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022   ENHANCEMENTS, OR MODIFICATIONS.
023
024   PT_COPYRIGHT_VERSION_2
025   COPYRIGHTENDKEY
026
027*/
028package ptolemy.data;
029
030import java.util.Arrays;
031
032import ptolemy.actor.util.Time;
033import ptolemy.data.type.BaseType;
034import ptolemy.kernel.util.IllegalActionException;
035
036///////////////////////////////////////////////////////////////////
037//// SmoothToken
038
039/**
040   A double-valued token that contains zero or more derivatives, representing
041   the value of a function of time at a particular time.
042   In mathematical analysis, smoothness has to do with how many derivatives
043   a function possesses. A smooth function is one that has derivatives of
044   all orders everywhere in its domain. An instance of this class represents
045   a sample of a function at a point in time together with some finite number of
046   derivatives of the function at that same point.
047   <p>
048   This token will be treated exactly
049   like a {@link DoubleToken} by any actor or operation that does not
050   specifically support it, and it will be represented in the type systems
051   as a "double." But it can (potentially) carry additional information giving
052   one or more derivatives of the function from which it is a sample and
053   giving the time at which it represents a sample of the signal.
054   This token, therefore, gives a way for actors that either generate or
055   use this derivative information to make that information available to other
056   actors that can use it. Such actors should declare their input ports to
057   be of type double, but when they receive an input token, they should
058   check (using instanceof) whether the token is a SmoothToken, and if so,
059   access these derivatives using the {@link #derivativeValues()} method,
060   or extrapolate the value to a specified time using the {@link #extrapolate(Time)}
061   method.
062   <p>
063   Note that if two SmoothTokens are added or subtracted, then the derivatives also
064   add or subtract. If the times of the two tokens that are added or subtracted are
065   not the same, then the one with the lesser time is extrapolated to the larger time,
066   and the result will be the sum at the later time.
067   If a SmoothToken is added to a DoubleToken, the derivatives of the DoubleToken
068   are assumed to be zero, and similarly for subtraction.
069   <p>
070   If a SmoothToken is multiplied by a SmoothToken, then the product rule of
071   calculus is used to determine the derivatives of the product.
072   The product rule stipulates that
073   <pre>
074      (xy)' = x'y + xy'
075   </pre>
076   Again, if the times of the two tokens are not equal, then the one with the lesser
077   time will be extrapolated to the larger time before being multiplied, and the time
078   of the result will be the larger time.
079   If a SmoothToken is multiplied by a DoubleToken, then the derivatives
080   of the DoubleToken are assumed to be zero.
081   <p>
082   Division works similarly:</p>
083   <pre>
084      (x/y)' = x'/y + x(1/y)' = x'/y - xy'/y^2
085   </pre>
086   <p>where the last equality follows from the reciprocal rule of calculus.
087   The second derivative of a multiplication or division is obtained by
088   applying the above rules to x' and y' rather than to x and y.
089   Higher-order derivatives are similarly obtained.
090   </p><p>
091   You can construct an instance of this token in the Ptolemy expression
092   language using the <code>smoothToken(double, double, {double})</code> function.
093   The first argument specifies the value, and the second argument specifies
094   the time, and the third specifies the derivatives. Also provided in the
095   expression language are one and two argument versions of this function that
096   assume the time is zero. These should be used only during initialization, and
097   only if the start time of the model is actually zero.
098   </p><p>
099   By default, instances of SmoothToken have no more than three derivatives.
100   This can be changed using the {@link #setOrderLimit(int)} method.
101   </p><p>
102   FIXME: Division is not implemented yet.
103   </p>
104
105   @author Thierry S. Nouidui, Michael Wetter, Edward A. Lee
106   @version $Id$
107   @since Ptolemy II 11.0
108   @Pt.ProposedRating Red (mw)
109   @Pt.AcceptedRating Red (mw)
110*/
111public class SmoothToken extends DoubleToken {
112
113    /** Construct a SmoothToken with value 0.0 at time zero and no derivatives.
114     */
115    public SmoothToken() {
116        this(0.0, Time.ZERO, null);
117    }
118
119    /** Construct a SmoothToken with the specified value at time zero and no derivatives.
120     *  @param value The specified value.
121     */
122    public SmoothToken(double value) {
123        this(value, Time.ZERO, null);
124    }
125
126    /** Construct a SmoothToken with the specified value at time zero
127     *  and the specified derivatives.
128     *  This constructor does not copy the derivatives argument, so it is up
129     *  to the caller to ensure that the array passed in does not later get
130     *  modified (tokens are required to be immutable).
131     *  @param value The specified value.
132     *  @param derivatives The specified derivatives.
133     */
134    public SmoothToken(double value, double[] derivatives) {
135        this(value, Time.ZERO, derivatives);
136    }
137
138    /** Construct a SmoothToken with the specified value at the specified
139     *  time, and with the specified derivatives.
140     *  This constructor copies the derivatives argument, so
141     *  the caller is free to modify it (tokens are required to be immutable).
142     *  @param value The specified value.
143     *  @param time The specified time.
144     *  @param derivatives The specified derivatives.
145     */
146    public SmoothToken(double value, Time time, double[] derivatives) {
147        super(value);
148        _time = time;
149        if (_time == null) {
150            _time = Time.ZERO;
151        }
152        if (derivatives != null) {
153            int length = derivatives.length;
154            if (length > _maxOrder) {
155                length = _maxOrder;
156            }
157            _derivatives = new double[length];
158            System.arraycopy(derivatives, 0, _derivatives, 0, length);
159        } else {
160            _derivatives = null;
161        }
162    }
163
164    /** Construct a SmoothToken with the specified value and derivatives, given
165     *  as a single array, at the specified time.
166     *  This constructor copies the data from argument, so the caller is free
167     *  to modify the array after this method returns.
168     *  @param x An array where the first element is the value, and optionally any
169     *   other elements can be present to specify the first, second, etc. derivatives.
170     *  @param time The time at which this token is a sample.
171     */
172    public SmoothToken(double[] x, Time time) {
173        this(x[0], time, null);
174        if (x.length > 1) {
175            final int nDer = (x.length > _maxOrder) ? _maxOrder
176                    : (x.length - 1);
177            _derivatives = new double[nDer];
178            System.arraycopy(x, 1, _derivatives, 0, nDer);
179        }
180    }
181
182    /** Construct a SmoothToken from the specified string, which specifies only
183     *  a value. The resulting token will have no derivatives and will represent
184     *  a sample at time zero.
185     *  @param init The initialization string, which is in a format
186     *  suitable for java.lang.Double.parseDouble(String).
187     *  @exception IllegalActionException If the Token could not
188     *   be created with the given String.
189     */
190    public SmoothToken(String init) throws IllegalActionException {
191        if (init == null || init.equals("nil")) {
192            throw new IllegalActionException(
193                    notSupportedNullNilStringMessage("SmoothToken", init));
194        }
195
196        // It would be nice to call super(init) here, but we can't, so
197        // we copy the code from the parent.
198
199        // FIXME: Parsing the array of derivatives is not yet supported.
200        try {
201            _value = Double.parseDouble(init);
202        } catch (NumberFormatException e) {
203            throw new IllegalActionException(null, e,
204                    "Failed to parse \"" + init + "\" as a number.");
205        }
206        _time = Time.ZERO;
207    }
208
209    ///////////////////////////////////////////////////////////////////
210    ////                         static initializer                ////
211
212    static {
213        // Specify that the QSSToken class is an alternate implementation
214        // of the double type. This allows the expression language to
215        // recognize a return type of QSSToken from a static function
216        // registered in the previous call as a double.
217
218        // Commented out because it broke the build.
219        BaseType.addType(BaseType.DOUBLE, "smoothToken", SmoothToken.class);
220    }
221
222    ///////////////////////////////////////////////////////////////////
223    ////                         public methods                    ////
224
225    /** Given an array of Tokens and a time, align them by
226     *  extrapolating all tokens that are instances of
227     *  SmoothToken to that time, and returning
228     *  an array of tokens with the extrapolated values and derivatives.
229     *  If any of the tokens is not a SmoothToken, it is returned unmodified
230     *  in the result.
231     *  The returned array will have the same size as the argument array, and
232     *  all the tokens will have the same maximum time.
233     *  @param args The tokens to be aligned.
234     *  @param time The Time to which the tokens will be aligned.
235     *  @return An array of aligned tokens.
236     */
237    static public Token[] align(Token[] args, Time time) {
238        Token[] result = new Token[args.length];
239        for (int i = 0; i < args.length; i++) {
240            if (args[i] instanceof SmoothToken) {
241                result[i] = ((SmoothToken) args[i]).extrapolate(time);
242            } else {
243                result[i] = args[i];
244            }
245        }
246        return result;
247    }
248
249    /** Given an array of Tokens, align them by finding the maximum time
250     *  of all the tokens, extrapolating all tokens that are instances of
251     *  SmoothToken to that time, and returning
252     *  an array of tokens with the extrapolated values and derivatives.
253     *  If any of the tokens is not a SmoothToken, it is returned unmodified
254     *  in the result.
255     *  The returned array will have the same size as the argument array, and
256     *  all the tokens will have the same maximum time.
257     *  @param args The tokens to be aligned.
258     *  @return An array of aligned tokens.
259     */
260    static public Token[] align(Token[] args) {
261        // First, find the maximum time.
262        Time latestTime = null;
263        for (int i = 0; i < args.length; i++) {
264            if (args[i] instanceof SmoothToken) {
265                SmoothToken smooth = (SmoothToken) args[i];
266                if (latestTime == null
267                        || latestTime.compareTo(smooth._time) < 0) {
268                    latestTime = smooth._time;
269                }
270            }
271        }
272        // Align the tokens
273        Token[] result = align(args, latestTime);
274        return result;
275    }
276
277    /** Given two SmoothTokens, align them by finding the maximum time
278     *  of the tokens, extrapolating the other token to that time, and returning
279     *  an array of tokens with the extrapolated values and derivatives.
280     *  The returned array will have size 2, and
281     *  all the tokens will have the same maximum time.
282     *  @param arg1 The first SmoothToken to be aligned.
283     *  @param arg2 The second SmoothToken to be aligned.
284     *  @return An array of tokens with the extrapolated values and
285     *  derivatives.
286     */
287    SmoothToken[] align(SmoothToken arg1, SmoothToken arg2) {
288        // First, find the maximum time.
289        Time latestTime = arg1._time;
290        if (latestTime.compareTo(arg2._time) < 0) {
291            latestTime = arg2._time;
292        }
293        SmoothToken[] result = new SmoothToken[2];
294        result[0] = arg1.extrapolate(latestTime);
295        result[1] = arg2.extrapolate(latestTime);
296        return result;
297    }
298
299    /** Return the n-th derivative of the specified token.
300     *  If no n-th derivative has been specified, return 0.0.
301     *  If n is 0 or negative, just return the value.
302     *  @param token The token.
303     *  @param n The order of the desired derivative.
304     *  @return The value of n-th derivatives of this token.
305     */
306    public static final double derivativeValue(DoubleToken token, int n) {
307        if (n <= 0) {
308            return token._value;
309        } else if (!(token instanceof SmoothToken)
310                || ((SmoothToken) token)._derivatives == null
311                || n > ((SmoothToken) token)._derivatives.length) {
312            return 0.0;
313        } else {
314            return ((SmoothToken) token)._derivatives[n - 1];
315        }
316    }
317
318    /** Return the derivatives of the token as a double[], or null if there are
319     *  no derivatives. Since tokens are immutable, the caller of this method must
320     *  copy the returned array if it intends to modify the array.
321     *  @return The value of the derivatives contained in this token.
322     */
323    public double[] derivativeValues() {
324        if (_derivatives == null || _derivatives.length == 0) {
325            return null;
326        }
327        return _derivatives;
328    }
329
330    /** Return true if the argument's class is SmoothToken and it has the
331     *  same value and derivatives as this token.
332     *  Note that this ignores the time of the tokens.
333     *  This is needed to be able to use this in tests.
334     *  @param object An object to compare for equality.
335     *  @return True if the argument is a SmoothToken with the same
336     *   value and derivatives. If either this object or the argument is a nil Token, return
337     *  false.
338     */
339    @Override
340    public boolean equals(Object object) {
341        // The superclass checks class equality, doubleValue equality, and handles nil.
342        if (super.equals(object)) {
343            // Check the times.
344            /* No, don't. See above.
345            if (!_time.equals(((SmoothToken)object)._time)) {
346                return false;
347            }
348            */
349            // Now we just have to check the derivatives.
350            int order = maxOrder(this, (DoubleToken) object);
351            for (int i = 0; i < order; i++) {
352                double d1 = derivativeValue(this, i + 1);
353                double d2 = derivativeValue((DoubleToken) object, i + 1);
354                if (d1 != d2) {
355                    return false;
356                }
357            }
358            // All derivatives are equal.
359            return true;
360        } else {
361            return false;
362        }
363    }
364
365    /** Return a SmoothToken at the specified time whose value and derivatives
366     *  are the result of extrapolating this token to the specified time.
367     *  @param time The time to which to extrapolate this token.
368     *  @return A SmoothToken at the specified time.
369     */
370    public SmoothToken extrapolate(Time time) {
371        // If the time matches, return this token.
372        if (_time == time || (_time != null && _time.equals(time))) {
373            return this;
374        }
375        // If _derivatives == null, simply return the current token.
376        if (_derivatives == null || _derivatives.length == 0) {
377            return new SmoothToken(_value, time, null);
378        } else if (_derivatives.length == 1) {
379            // A common case is QSS2, which has a value and a derivative.
380            // We handle this case special to stay computationally efficient.
381            final double dt = time.subtractToDouble(_time);
382            final double x = _value + dt * _derivatives[0];
383            return new SmoothToken(x, time, _derivatives);
384        } else {
385            // This is the case for tokens with second or higher order derivatives.
386            // Build an array with value and derivatives
387            double[] coef = new double[_derivatives.length + 1];
388            coef[0] = _value;
389            System.arraycopy(_derivatives, 0, coef, 1, _derivatives.length);
390
391            // Create vector with factorial coefficients times dt
392            // raised to the corresponding power.
393            double[] fact = new double[coef.length];
394            fact[0] = 1;
395            final double dt = time.subtractToDouble(_time);
396            for (int i = 1; i < coef.length; i++) {
397                fact[i] = dt * fact[i - 1] / i;
398            }
399
400            // Advance time for all values in coef and store in new array res
401            double[] res = new double[coef.length];
402            for (int i = 0; i < coef.length; i++) {
403                for (int j = 0; j < coef.length - i; j++) {
404                    res[i] += coef[j + i] * fact[j];
405                }
406            }
407            double[] der = new double[_derivatives.length];
408            System.arraycopy(res, 1, der, 0, _derivatives.length);
409
410            return new SmoothToken(res[0], time, der);
411        }
412    }
413
414    /** Get the maximum order of any token (the number of derivatives).
415     *  E.g., if maxOrder = 2, the token will have one value, the first
416     *  and the 2nd derivative.
417     *  By default, tokens will have maxOrder = 3.
418     *  @return the maximum order.
419     *  @see #setOrderLimit(int)
420     */
421    public static int getOrderLimit() {
422        return _maxOrder;
423    }
424
425    /** Return the time for which the values of this smooth token are valid.
426     *  @return The time of this token.
427     */
428    public Time getTime() {
429        return _time;
430    }
431
432    /** Return the hash code for the SmoothToken object. If two SmoothToken
433     *  objects have the same double value and their derivatives
434     *  have the same hashCode, then the two SmoothTokens will have
435     *  the same hashcode.
436     *  @return The hash code for this SmoothToken object.
437     */
438    @Override
439    public int hashCode() {
440        // See http://www.technofundo.com/tech/java/equalhash.html
441        int hashCode = super.hashCode();
442        if (_derivatives != null) {
443            hashCode = 31 * hashCode + Arrays.hashCode(_derivatives);
444        }
445        return hashCode;
446    }
447
448    /** Return true if the token is nil, (aka null or missing).
449     *  Nil or missing tokens occur when a data source is sparsely populated.
450     *  @return True if the token is the {@link #NIL} token.
451     */
452    @Override
453    public boolean isNil() {
454        // We use a method here so that we can easily change how
455        // we determine if a token is nil without modify lots of classes.
456        return this == SmoothToken.NIL;
457    }
458
459    /** Return the maximum number of specified derivatives for the two tokens.
460     *  @param arg1 The first token.
461     *  @param arg2 The second token.
462     *  @return The maximum of the number of derivatives specified.
463     */
464    public static final int maxOrder(DoubleToken arg1, DoubleToken arg2) {
465        return Math.max(order(arg1), order(arg2));
466    }
467
468    /** Return a new token that is the negative of this one.
469     *  @return The negative, where all the derivatives are also negated.
470     */
471    public SmoothToken negate() {
472        if (_derivatives == null || _derivatives.length == 0) {
473            return new SmoothToken(-_value, _time, null);
474        }
475        double[] derivatives = new double[_derivatives.length];
476        for (int i = 0; i < _derivatives.length; i++) {
477            derivatives[i] = -_derivatives[i];
478        }
479        return new SmoothToken(-_value, _time, derivatives);
480    }
481
482    /** Return the number of specified derivatives for the token.
483     *  @param token The token.
484     *  @return The number of derivatives specified.
485     */
486    public static final int order(DoubleToken token) {
487        if (!(token instanceof SmoothToken)
488                || ((SmoothToken) token)._derivatives == null) {
489            return 0;
490        } else {
491            return ((SmoothToken) token)._derivatives.length;
492        }
493    }
494
495    /** Set the maximum order of any token (the number of derivatives).
496     *  This is static, so calling it will affect <i>all</i>
497     *  instances of SmoothToken in the same JVM.
498     *  Its effect is not even limited to a single Ptolemy model.
499     *  E.g., if maxOrder = 2, the token will have one value, the first
500     *  and the 2nd derivative.
501     *  By default, tokens will have maxOrder = 3.
502     *  The maxOrder must be non-negative.
503     *  @param maxOrder The maximum order of the token.
504     *  @see #getOrderLimit()
505     */
506    public static void setOrderLimit(int maxOrder) {
507        if (maxOrder < 0) {
508            throw new IllegalArgumentException(
509                    "maxOrder must be non-negative, not " + maxOrder + ".");
510        }
511        _maxOrder = maxOrder;
512    }
513
514    /** Return a SmoothToken with the specified value at time zero and no derivatives.
515     *  This function gets registered by PtParser, after which it becomes
516     *  available in the expression language.
517     *  Note that there is no way in the expression language to construct a
518     *  SmoothToken with a time other than zero. This makes sense because usually
519     *  expressions are evaluated only once when a model is opened.
520     *  @param value The value.
521     *  @return The SmoothToken with the specified value at time zero
522     *  and no derivatives.
523     */
524    public static SmoothToken smoothToken(double value) {
525        return new SmoothToken(value, Time.ZERO, null);
526    }
527
528    /** Return a SmoothToken with the specified value at time zero and derivatives.
529     *  This function gets registered by PtParser, after which it becomes
530     *  available in the expression language.
531     *  Note that there is no way in the expression language to construct a
532     *  SmoothToken with a time other than zero. This makes sense because usually
533     *  expressions are evaluated only once when a model is opened.
534     *  @param value The value.
535     *  @param derivatives An array containing the first derivative,
536     *   the second derivative, etc.
537     *  @return The SmoothToken with the specified value at time zero
538     *  and derivatives.
539     */
540    public static SmoothToken smoothToken(double value, double[] derivatives) {
541        return new SmoothToken(value, Time.ZERO, derivatives);
542    }
543
544    /** Return the value of this token as a string that can be parsed
545     *  by the expression language to recover a token with the same value and derivatives.
546     *  However, the parsed token will not have the same time. It will have time zero.
547     *  If there are no derivatives, then this just returns what the superclass
548     *  returns to represent a double. Otherwise, the returned
549     *  string has the form "smoothToken(value, derivatives)", where
550     *  the value is the value returned by {@link #doubleValue()}, and
551     *  derivatives is an array of doubles.
552     */
553    @Override
554    public String toString() {
555        if (_derivatives == null || _derivatives.length == 0) {
556            return super.toString();
557        }
558        StringBuffer derivatives = new StringBuffer("{");
559        boolean first = true;
560        for (int i = 0; i < Math.min(_derivatives.length, _maxOrder); i++) {
561            if (first) {
562                first = false;
563            } else {
564                derivatives.append(",");
565            }
566            derivatives.append(Double.toString(_derivatives[i]));
567        }
568        derivatives.append("}");
569        return "smoothToken(" + super.toString() + ", " + derivatives.toString()
570                + ")";
571    }
572
573    ///////////////////////////////////////////////////////////////////
574    ////                         public variables                  ////
575
576    /** A token that represents a missing value.
577     *  Null or missing tokens are common in analytical systems
578     *  like R and SAS where they are used to handle sparsely populated data
579     *  sources.  In database parlance, missing tokens are sometimes called
580     *  null tokens.  Since null is a Java keyword, we use the term "nil".
581     *  The toString() method on a nil token returns the string "nil".
582     */
583    public static final SmoothToken NIL = new SmoothToken(Double.NaN);
584
585    ///////////////////////////////////////////////////////////////////
586    ////                         protected methods                 ////
587
588    /** Return a new token whose value is the value of the
589     *  argument Token added to the value of this Token.
590     *  The argument is guaranteed to be either a DoubleToken or
591     *  a SmoothToken by the caller. If the argument is a DoubleToken,
592     *  then its value is simply added to the value of this token, and
593     *  a new SmoothToken is returned with the sum value, time, and the derivatives
594     *  of this token. If the argument is a SmoothToken, then this token and
595     *  the argument are first aligned using
596     *  {@link ptolemy.data.SmoothToken#align(SmoothToken, SmoothToken)},
597     *  and then added.  The returned SmoothToken
598     *  will have the maximum of the number of derivatives of this token and
599     *  the derivatives of the argument, and for derivatives given by both
600     *  tokens, the derivative will be the sum of the two derivatives.
601     *  The time of the returned token will be the maximum of the time of this
602     *  token and the argument.
603     *  @param rightArgument The token to add to this token.
604     *  @return A new SmoothToken containing the result.
605     */
606    @Override
607    protected ScalarToken _add(ScalarToken rightArgument) {
608        if (rightArgument instanceof SmoothToken) {
609            // First align the tokens.
610            SmoothToken[] aligned = align(this, (SmoothToken) rightArgument);
611
612            // Compute the sum of the values.
613            final double sum = aligned[0].doubleValue()
614                    + aligned[1].doubleValue();
615
616            // Compute the derivatives of the result.
617            double[] derivatives = aligned[1].derivativeValues();
618            if (derivatives == null) {
619                // Just use the derivatives of this token.
620                // This should be safe because, by policy, their value is immutable.
621                return new SmoothToken(sum, aligned[0]._time,
622                        aligned[0]._derivatives);
623            } else if (aligned[0]._derivatives == null) {
624                // Just use the derivatives of the second token.
625                // This should be safe because, by policy, their value is immutable.
626                return new SmoothToken(sum, aligned[0]._time, derivatives);
627            }
628            // Both tokens have derivatives.
629            // Create a sum of derivatives.
630            int max = derivatives.length;
631            if (max < aligned[0]._derivatives.length) {
632                max = aligned[0]._derivatives.length;
633            }
634            double[] result = new double[max];
635            for (int i = 0; i < max; i++) {
636                if (i < aligned[0]._derivatives.length
637                        && i < derivatives.length) {
638                    result[i] = aligned[0]._derivatives[i] + derivatives[i];
639                } else if (i < aligned[0]._derivatives.length) {
640                    result[i] = aligned[0]._derivatives[i];
641                } else {
642                    result[i] = derivatives[i];
643                }
644            }
645            return new SmoothToken(sum, aligned[0]._time, result);
646        } else {
647            final double sum = super.doubleValue()
648                    + ((DoubleToken) rightArgument).doubleValue();
649            // Just use the derivatives of this token.
650            // This should be safe because, by policy, their value is immutable.
651            return new SmoothToken(sum, _time, _derivatives);
652        }
653    }
654
655    /** Return a new token whose value is the value of this token
656     *  divided by the value of the argument token. It is assumed that
657     *  the type of the argument is a SmoothToken
658     *  @param divisor The token to divide this token by.
659     *  @return A new SmoothToken containing the result.
660     */
661    @Override
662    protected ScalarToken _divide(ScalarToken divisor) {
663        if (divisor instanceof SmoothToken) {
664            // First align the tokens.
665            SmoothToken[] aligned = align(this, (SmoothToken) divisor);
666            double x = aligned[0].doubleValue();
667            double y = aligned[1].doubleValue();
668            double quotient = x / y;
669
670            // FIXME: Need to implement the rule in the class comment.
671            // FIXME: Should use: (x/y)' = x'/y + x(1/y)' = x'/y - xy'/y^2
672
673            if (_derivatives == null || _derivatives.length == 0) {
674                return new DoubleToken(quotient);
675            } else {
676                double[] der = new double[_derivatives.length];
677                for (int i = 0; i < _derivatives.length; i++) {
678                    der[i] = _derivatives[i] / y;
679                }
680                return new SmoothToken(quotient, aligned[0]._time, der);
681            }
682        } else {
683            if (_derivatives == null || _derivatives.length == 0) {
684                return super._divide(divisor);
685            } else {
686                final double div = ((DoubleToken) divisor).doubleValue();
687                final double quotient = super.doubleValue() / div;
688                double[] der = new double[_derivatives.length];
689                for (int i = 0; i < _derivatives.length; i++) {
690                    der[i] = _derivatives[i] / div;
691                }
692                return new SmoothToken(quotient, _time, der);
693            }
694        }
695    }
696
697    /** Return true if the two arguments are within epsilon of one another.
698     *  @param arg1 First argument.
699     *  @param arg2 Second argument.
700     *  @param epsilon The maximum difference.
701     *  @return true if the two arguments are within epsilon of one another.
702     */
703    protected final boolean _isClose(double arg1, double arg2, double epsilon) {
704        if (arg1 > arg2 + epsilon || arg1 < arg2 - epsilon) {
705            return false;
706        } else {
707            return true;
708        }
709    }
710
711    /** Test that the value of this token is close to the first
712     *  argument, where "close" means that the distance between their
713     *  values is less than or equal to the second argument. It is
714     *  assumed that the type of the first argument is DoubleToken.
715     *  Here, "close" also means that the derivatives have to be close.
716     *  @param rightArgument The token to compare to this token.
717     *  @param epsilon The distance.
718     *  @return A token containing tue if the value of this token is close
719     *   to that of the argument.
720     */
721    @Override
722    protected BooleanToken _isCloseTo(ScalarToken rightArgument,
723            double epsilon) {
724        BooleanToken result = super._isCloseTo(rightArgument, epsilon);
725        if (!result.booleanValue()) {
726            // Value is not close.
727            return result;
728        }
729        // Now we just have to check the derivatives.
730        int order = maxOrder(this, (DoubleToken) rightArgument);
731        for (int i = 0; i < order; i++) {
732            double d1 = derivativeValue(this, i + 1);
733            double d2 = derivativeValue((DoubleToken) rightArgument, i + 1);
734            if (!_isClose(d1, d2, epsilon)) {
735                return BooleanToken.FALSE;
736            }
737        }
738        // All derivatives are close.
739        return BooleanToken.TRUE;
740    }
741
742    /** Test for ordering of the values of this Token and the argument
743     *  Token.  It is assumed that the type of the argument is SmoothToken.
744     *  @param rightArgument The token to compare to this token.
745     *  @exception IllegalActionException If this method is not
746     *  supported by the derived class.
747     *  @return A new Token containing the result.
748     */
749    @Override
750    protected BooleanToken _isLessThan(ScalarToken rightArgument)
751            throws IllegalActionException {
752        if (rightArgument instanceof DoubleToken) {
753            return super._isLessThan(rightArgument);
754        } else {
755            SmoothToken convertedArgument = (SmoothToken) rightArgument;
756            return BooleanToken
757                    .getInstance(_value < convertedArgument.doubleValue());
758        }
759    }
760
761    /** Return a new token whose value is the value of this token
762     *  multiplied by the value of the argument token.  The derivatives
763     *  of the result are calculated using the product rule.
764     *  The argument is assumed to be a DoubleToken.
765     *  It may also be a SmoothToken.
766     *  @param rightArgument The token to multiply this token by.
767     *  @return A new SmoothToken containing the result.
768     */
769    @Override
770    protected ScalarToken _multiply(ScalarToken rightArgument) {
771        if (rightArgument instanceof SmoothToken) {
772            // First align the tokens.
773            SmoothToken[] aligned = align(this, (SmoothToken) rightArgument);
774
775            double x = aligned[0].doubleValue();
776            double y = aligned[1].doubleValue();
777            double product = x * y;
778            double[] derivatives = aligned[1].derivativeValues();
779
780            // Check whether one or both tokens lack derivatives.
781            if (aligned[0]._derivatives == null
782                    || aligned[0]._derivatives.length == 0) {
783                // x lacks derivatives.
784                if (derivatives == null || derivatives.length == 0) {
785                    // Both lack derivatives.
786                    return new SmoothToken(product, aligned[0]._time, null);
787                }
788                // Only x lacks derivatives. Hence, x should scale y's derivatives.
789                double[] result = new double[derivatives.length];
790                for (int i = 0; i < derivatives.length; i++) {
791                    result[i] = derivatives[i] * x;
792                }
793                return new SmoothToken(product, aligned[0]._time, result);
794            }
795            // y derivatives may be null. In this case, y should scale x's derivatives.
796            if (derivatives == null) {
797                double[] result = new double[aligned[0]._derivatives.length];
798                for (int i = 0; i < aligned[0]._derivatives.length; i++) {
799                    result[i] = aligned[0]._derivatives[i] * y;
800                }
801                return new SmoothToken(product, aligned[0]._time, result);
802            } else {
803                // Both have derivatives.
804                // Multiply the tokens as if they were Taylor polynomials.
805
806                // Build arrays whose elements are the coefficients of the polynomials.
807                double[] p1 = new double[aligned[0]._derivatives.length + 1];
808                double[] p2 = new double[derivatives.length + 1];
809                p1[0] = x;
810                p2[0] = y;
811                // FIXME: Consider avoiding this copy by changing the internal representation
812                // so that the the value and derivatives are in one array.
813                // There are a few other places in the code that will be helped.
814                System.arraycopy(_derivatives, 0, p1, 1, _derivatives.length);
815                System.arraycopy(derivatives, 0, p2, 1, derivatives.length);
816                // Multiply the polynomials
817                double[] pro = _multiplyPolynomials(p1, p2);
818                double[] derRes = new double[pro.length - 1];
819                System.arraycopy(pro, 1, derRes, 0, derRes.length);
820                return new SmoothToken(pro[0], aligned[0]._time, derRes);
821            }
822        } else {
823            // Assume the rightArgument derivatives are zero, so the returned result just
824            // has the derivatives of this token scaled by y.
825            double y = ((DoubleToken) rightArgument).doubleValue();
826            double product = doubleValue() * y;
827
828            if (_derivatives == null || _derivatives.length == 0) {
829                return new SmoothToken(product, _time, null);
830            }
831            double[] result = new double[_derivatives.length];
832            for (int i = 0; i < _derivatives.length; i++) {
833                result[i] = _derivatives[i] * y;
834            }
835            return new SmoothToken(product, _time, result);
836        }
837    }
838
839    /** Multiply two polynomials.
840     *  @param p1 First polynomial.
841     *  @param p2 Second polynomial
842     *  @return The product of the polynomials
843     */
844    protected static double[] _multiplyPolynomials(final double[] p1,
845            final double[] p2) {
846
847        double[] res = new double[(p1.length - 1) + (p2.length - 1) + 1];
848        // Set all coefficients to zero.
849        for (int i = 0; i < res.length; i++) {
850            res[i] = 0;
851        }
852        // Multiply the polynomials
853        for (int i1 = 0; i1 < p1.length; i1++) {
854            for (int i2 = 0; i2 < p2.length; i2++) {
855                final int exponent = i1 + i2;
856                if (res[exponent] == 0) {
857                    res[exponent] = p1[i1] * p2[i2];
858                } else {
859                    res[exponent] += p1[i1] * p2[i2];
860                }
861            }
862        }
863        return res;
864    }
865
866    /** Return a new token whose value is the value of the argument token
867     *  subtracted from the value of this token.  It is assumed that
868     *  the type of the argument is a DoubleToken.
869     *  @param rightArgument The token to subtract from this token.
870     *  @return A new SmoothToken containing the result.
871     */
872    @Override
873    protected ScalarToken _subtract(ScalarToken rightArgument) {
874        if (rightArgument instanceof SmoothToken) {
875            // First align the tokens.
876            SmoothToken[] aligned = align(this, (SmoothToken) rightArgument);
877            double x = aligned[0].doubleValue();
878            double y = aligned[1].doubleValue();
879            final double difference = x - y;
880
881            double[] xderivatives = aligned[0].derivativeValues();
882            double[] yderivatives = aligned[1].derivativeValues();
883
884            if (yderivatives == null) {
885                // Just use the xderivatives.
886                // This should be safe because, by policy, their value is immutable.
887                return new SmoothToken(difference, aligned[0]._time,
888                        xderivatives);
889            } else if (xderivatives == null) {
890                // The derivatives should be negated.
891                double[] result = new double[yderivatives.length];
892                for (int i = 0; i < result.length; i++) {
893                    result[i] = -yderivatives[i];
894                }
895                return new SmoothToken(difference, aligned[0]._time, result);
896            }
897            // Create a difference of derivatives.
898            int max = yderivatives.length;
899            if (max < xderivatives.length) {
900                max = xderivatives.length;
901            }
902            double[] result = new double[max];
903            for (int i = 0; i < max; i++) {
904                if (i < xderivatives.length && i < yderivatives.length) {
905                    result[i] = xderivatives[i] - yderivatives[i];
906                } else if (i < xderivatives.length) {
907                    result[i] = xderivatives[i];
908                } else {
909                    result[i] = -yderivatives[i];
910                }
911            }
912            return new SmoothToken(difference, aligned[0]._time, result);
913        } else {
914            final double difference = super.doubleValue()
915                    - ((DoubleToken) rightArgument).doubleValue();
916            // Just use the derivatives of this token.
917            // This should be safe because, by policy, their value is immutable.
918            return new SmoothToken(difference, _time, _derivatives);
919        }
920    }
921
922    ///////////////////////////////////////////////////////////////////
923    ////                         protected variables               ////
924    /* Maximum order of the token.
925     *
926     * A token with _maxOrder=3 will have a value and three derivatives.
927     */
928    static int _maxOrder = 3;
929
930    ///////////////////////////////////////////////////////////////////
931    ////                         private variables                 ////
932
933    /** The derivatives. */
934    private double[] _derivatives;
935
936    /** The time at which this token is a sample of a function. */
937    private Time _time;
938}