001/* A token that contains an array of tokens.
002
003 Copyright (c) 1997-2015 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.LinkedList;
031import java.util.List;
032
033import ptolemy.data.expr.ASTPtRootNode;
034import ptolemy.data.expr.ParseTreeEvaluator;
035import ptolemy.data.expr.PtParser;
036import ptolemy.data.type.ArrayType;
037import ptolemy.data.type.BaseType;
038import ptolemy.data.type.Type;
039import ptolemy.data.type.TypeLattice;
040import ptolemy.graph.CPO;
041import ptolemy.kernel.util.IllegalActionException;
042import ptolemy.kernel.util.InternalErrorException;
043
044///////////////////////////////////////////////////////////////////
045//// ArrayToken
046
047/**
048 A token that contains an array of tokens.  The operations between
049 arrays are defined pointwise, and require that the lengths of the
050 arrays are the same.  The elements of the ArrayToken will be
051 converted to the least upper bound of their input types.  Zero length
052 array tokens are supported, given a prototype element to determine
053 the type of the array.
054
055 @author Yuhong Xiong, Steve Neuendorffer, Contributor: Christopher Brooks
056 @version $Id$
057 @since Ptolemy II 0.4
058 @Pt.ProposedRating Yellow (cxh)
059 @Pt.AcceptedRating Red (cxh) nil token code
060 */
061public class ArrayToken extends AbstractNotConvertibleToken {
062    /** Construct an ArrayToken with the specified token array.
063     *  The type of the resulting array is the least upper bound
064     *  of the types of the elements.
065     *  This class makes a copy of the given array, so
066     *  the passed array may be reused.  Note that this method cannot
067     *  be used to create an empty array token, since the array token
068     *  must have a type.  Instead, use the constructor that takes a
069     *  type argument or use the "emptyArray" function from the expression
070     *  language.
071     *  @param value An (not empty) array of tokens.
072     *  @exception IllegalActionException If the length of the given array is
073     *   zero.
074     */
075    public ArrayToken(Token[] value) throws IllegalActionException {
076        int length = value.length;
077
078        if (length < 1) {
079            throw new IllegalActionException("ArrayToken(Token[]) called with "
080                    + "a an array of length less than 1.  To create an array "
081                    + "of length 0, use the ArrayToken(Token) constructor "
082                    + "or the \"emptyArray(type)\" function in the expression "
083                    + "language. The reason is that elements in ArrayToken "
084                    + "must have a type.");
085        }
086
087        _elementType = value[0].getType();
088
089        for (int i = 0; i < length; i++) {
090            Type valueType = value[i].getType();
091            _elementType = TypeLattice.leastUpperBound(_elementType, valueType);
092        }
093
094        _value = new Token[length];
095
096        for (int i = 0; i < length; i++) {
097            _value[i] = _elementType.convert(value[i]);
098        }
099    }
100
101    /** Construct an ArrayToken with the first <i>length</i>
102     *  elements of the specified token array. If <i>length</i>
103     *  is greater than the length of the specified array, then the
104     *  resulting array token will have exactly the number of elements
105     *  in the specified array.
106     *  The type of the resulting array is the least upper bound
107     *  of the types of the elements.
108     *  This class makes a copy of the given array, so
109     *  the passed array may be reused.  Note that this method cannot
110     *  be used to create an empty array token, since the array token
111     *  must have a type.  Instead, use the constructor that takes a
112     *  type argument or use the "emptyArray" function from the expression
113     *  language.
114     *  @param value An (not empty) array of tokens.
115     *  @param length The number of elements to be used from the
116     *  specified array.
117     *  @exception IllegalActionException If the length of the given array is
118     *   zero.
119     */
120    public ArrayToken(Token[] value, int length) throws IllegalActionException {
121        if (length > value.length) {
122            length = value.length;
123        }
124
125        if (length < 1) {
126            throw new IllegalActionException("ArrayToken(Token[]) called with "
127                    + "a an empty array.  To create an array "
128                    + "of length 0, use the ArrayToken(Token) constructor "
129                    + "or the \"emptyArray(type)\" function in the expression "
130                    + "language. The reason is that elements in ArrayToken "
131                    + "must have a type.");
132        }
133
134        _elementType = value[0].getType();
135
136        for (int i = 0; i < length; i++) {
137            Type valueType = value[i].getType();
138            _elementType = TypeLattice.leastUpperBound(_elementType, valueType);
139        }
140
141        _value = new Token[length];
142
143        for (int i = 0; i < length; i++) {
144            _value[i] = _elementType.convert(value[i]);
145        }
146    }
147
148    /** Construct an ArrayToken from the specified string.
149     *  The format of the string is a list of comma separated
150     *  token values that begins with "{" and ends with "}".
151     *  For example
152     *  <code>
153     *  "{1, 2, 3}"
154     *  </code>
155     *  @param init A string expression of an array.
156     *  @exception IllegalActionException If the string does
157     *   not contain a parsable array.
158     */
159    public ArrayToken(String init) throws IllegalActionException {
160        PtParser parser = new PtParser();
161        ASTPtRootNode tree = parser.generateParseTree(init);
162        ParseTreeEvaluator evaluator = new ParseTreeEvaluator();
163        Token token = evaluator.evaluateParseTree(tree);
164
165        if (token instanceof ArrayToken) {
166            _value = ((ArrayToken) token)._value;
167            _elementType = ((ArrayToken) token)._elementType;
168        } else {
169            throw new IllegalActionException("An array token cannot be"
170                    + " created from the expression '" + init + "'");
171        }
172    }
173
174    /** Construct an empty ArrayToken with the given element type.
175     *  @param elementType A token type.
176     */
177    public ArrayToken(Type elementType) {
178        _value = new Token[0];
179        _elementType = elementType;
180    }
181
182    /** Construct an ArrayToken with the specified element type and
183     *  token array. All the tokens in the array must have the type
184     *  of element type (or a subclass), otherwise an exception will
185     *  be thrown. This class makes a copy of the given array, so
186     *  the passed array may be reused.
187     *  @param elementType The type of the array.
188     *  @param value An array of tokens.
189     *  @exception IllegalActionException If the tokens in the array
190     *   do not have the specified type.
191     */
192    public ArrayToken(Type elementType, Token[] value)
193            throws IllegalActionException {
194        _elementType = elementType;
195        int length = value.length;
196
197        _value = new Token[length];
198
199        for (int i = 0; i < length; i++) {
200            _value[i] = _elementType.convert(value[i]);
201        }
202    }
203
204    ///////////////////////////////////////////////////////////////////
205    ////                         public methods                    ////
206
207    /** Addition can occur between arrays, or between an array and a token
208     *  of some base type (i.e., anything less than or equal to String).
209     *
210     *  Addition is undefined between arrays and tokens of other incomparable
211     *  data types such as Record and Union.
212     *  @param rightArgument The array to be added to this array.
213     *  @return The result of the addition.
214     *  @exception IllegalActionException If addition between this array
215     *  and the provided argument is not supported.
216     */
217    @Override
218    public Token add(Token rightArgument) throws IllegalActionException {
219
220        int typeInfo = TypeLattice.compare(rightArgument, BaseType.STRING);
221
222        // Disallow addition between arrays and anything greater than or
223        // incomparable with String (e.g., Record, Union, etc).
224        if ((typeInfo == CPO.INCOMPARABLE || typeInfo == CPO.HIGHER)
225                && getClass() != rightArgument.getClass()) {
226            throw new IllegalActionException(
227                    notSupportedDifferentClassesMessage("add", this,
228                            rightArgument));
229        }
230        try {
231            return _add(rightArgument);
232        } catch (IllegalActionException ex) {
233            // If the type-specific operation fails, then create a
234            // better error message that has the types of the
235            // arguments that were passed in.
236            throw new IllegalActionException(null, ex,
237                    notSupportedMessage("add", this, rightArgument));
238        }
239    }
240
241    /** If the left-hand argument is a base type token, then convert it
242     *  to an array of size one. Then do an element-wise addition with
243     *  each element of the right-hand argument.
244     *
245     *  This method is only invoked when addition is attempted using a
246     *  base type left-hand argument (e.g., 1 + {1, 2, 3} which will
247     *  yield {2, 3, 4}.
248     *  @param leftArgument The array to add this array to.
249     *  @return The result of the addition.
250     *  @exception IllegalActionException If addition between this array
251     *  and the provided argument is not supported.
252     */
253    @Override
254    public Token addReverse(Token leftArgument) throws IllegalActionException {
255        try {
256            int typeInfo = TypeLattice.compare(leftArgument, BaseType.STRING);
257
258            // Wrap base type argument in array in order to do expansion.
259            if ((typeInfo == CPO.LOWER || typeInfo == CPO.SAME)) {
260                Token[] arr = { leftArgument };
261                return new ArrayToken(arr).add(this);
262            } else if (getClass() == leftArgument.getClass()) {
263                return ((ArrayToken) leftArgument).add(this);
264            } else {
265                throw new IllegalActionException(null,
266                        notSupportedMessage("addReverse", this, leftArgument));
267            }
268        } catch (IllegalActionException ex) {
269            // If the type-specific operation fails, then create a
270            // better error message that has the types of the
271            // arguments that were passed in.
272            throw new IllegalActionException(null, ex,
273                    notSupportedMessage("addReverse", this, leftArgument));
274        }
275    }
276
277    /** Append the given array to the end of this array, and return the
278    *   resulting array. For example, if this array is {1, 2, 3} and the
279    *   given array is {4, 5, 6}, then the result would be {1, 2, 3, 4, 5, 6}.
280    *   If both arrays are empty, then an empty array is returned.
281    *
282    *  @param token The array to be appended to the end of this array.
283    *  @return The result array.
284    *  @exception IllegalActionException If an array token cannot be created.
285    *  @since Ptolemy II 7.1
286    */
287    public ArrayToken append(ArrayToken token) throws IllegalActionException {
288        // FIXME: This should probably create an instance of a subclass the
289        // preserves and refers to the two subarrays.
290        int newLength = length() + token.length();
291        if (newLength > 0) {
292            // NOTE: Do not use System.arraycopy if either of the two
293            // arrays being appended are a subclasses of this class,
294            // in which case values have to be accessed via the getElement() method,
295            // which is overridden in the subclasses.
296            Token[] result = new Token[newLength];
297            if (_depth == 0 && token._depth == 0) {
298                // Safe to use ArrayCopy, which is much more efficient than
299                // the method below (performance measurements appending 50
300                // arrays of length 10,000 yielded a huge performance improvement).
301                System.arraycopy(_value, 0, result, 0, _value.length);
302                System.arraycopy(token._value, 0, result, _value.length,
303                        token._value.length);
304            } else {
305                int headLength = length();
306                int tailLength = token.length();
307                for (int i = 0; i < headLength; i++) {
308                    result[i] = getElement(i);
309                }
310                for (int i = headLength; i < headLength + tailLength; i++) {
311                    result[i] = token.getElement(i - headLength);
312                }
313            }
314            return new ArrayToken(result);
315        } else {
316            return new ArrayToken(getElementType());
317        }
318    }
319
320    /** Append the given arrays.
321     *  @param tokens The list of arrays to be appended together.
322     *  @return The result array.
323     *  @exception IllegalActionException If an array token cannot be created,
324     *   or if all specified arrays are empty.
325     *  @since Ptolemy II 9.0
326     */
327    public static ArrayToken append(ArrayToken[] tokens)
328            throws IllegalActionException {
329        // FIXME: This should probably create an instance of a subclass the
330        // preserves and refers to the subarrays.
331
332        // First, figure out the length of the result array.
333        boolean okToUseArrayCopy = true;
334        int newLength = 0;
335        for (ArrayToken token : tokens) {
336            if (token != null) {
337                newLength += token.length();
338                if (token._depth > 0) {
339                    okToUseArrayCopy = false;
340                }
341            }
342        }
343        if (newLength == 0) {
344            throw new IllegalActionException("Cannot append empty arrays.");
345        }
346        // NOTE: Do not use System.arraycopy if any of the
347        // arrays being appended are a subclasses of this class,
348        // in which case values have to be accessed via the getElement() method,
349        // which is overridden in the subclasses.
350        Token[] result = new Token[newLength];
351        if (okToUseArrayCopy) {
352            // Safe to use ArrayCopy, which is much more efficient than
353            // the method below (performance measurements appending 50
354            // arrays of length 10,000 yielded a huge performance improvement).
355            int i = 0;
356            for (ArrayToken token : tokens) {
357                if (token != null) {
358                    System.arraycopy(token._value, 0, result, i,
359                            token._value.length);
360                    i += token._value.length;
361                }
362            }
363        } else {
364            int i = 0;
365            for (ArrayToken token : tokens) {
366                if (token != null) {
367                    for (int j = 0; j < token.length(); j++) {
368                        result[i++] = token.getElement(j);
369                    }
370                }
371            }
372        }
373        return new ArrayToken(result);
374    }
375
376    /** Convert an ArrayToken to an array of unsigned bytes.
377     *
378     * @param dataArrayToken to be converted to a unsigned byte array.
379     * @return dataBytes the resulting unsigned byte array.
380     * @see #unsignedByteArrayToArrayToken(byte[])
381     */
382    public static byte[] arrayTokenToUnsignedByteArray(
383            ArrayToken dataArrayToken) {
384        byte[] dataBytes = new byte[dataArrayToken.length()];
385
386        for (int j = 0; j < dataArrayToken.length(); j++) {
387            UnsignedByteToken dataToken = (UnsignedByteToken) dataArrayToken
388                    .getElement(j);
389            dataBytes[j] = dataToken.byteValue();
390        }
391
392        return dataBytes;
393    }
394
395    /** Return an array of tokens populated with the contents of this
396     *  array token.  The returned array is a copy so the caller is
397     *  free to modify it.
398     *  @return An array of tokens.
399     */
400    public Token[] arrayValue() {
401        // NOTE: Do not System.arraycopy here if the
402        // array is a subclasses of this class,
403        // so values have to be accessed via the getElement() method,
404        // which is overridden in the subclasses.
405        Token[] result = new Token[length()];
406        if (_depth == 0) {
407            System.arraycopy(_value, 0, result, 0, _value.length);
408        } else {
409            for (int i = 0; i < length(); i++) {
410                result[i] = getElement(i);
411            }
412        }
413        return result;
414    }
415
416    /** Return a Boolean token that identifies whether the given token is an
417     *  element of this array.
418     *
419     *  @param element A token to test whether it is an element of this array.
420     *  @return A true Boolean token if the element is found, or false
421     *   otherwise.
422     */
423    public BooleanToken contains(Token element) {
424        for (int i = 0; i < length(); i++) {
425            if (getElement(i).equals(element)) {
426                return BooleanToken.TRUE;
427            }
428        }
429        return BooleanToken.FALSE;
430    }
431
432    /** Divide this array token by the specified argument.
433     *  If the argument is an array token and it has
434     *  the same length as this array token, and the division is elementwise.
435     *  Otherwise, each element is divided by the argument.
436     *  This overrides the base class to allow division by scalars.
437     *  @param rightArgument The token to divide into this token.
438     *  @return A new token containing the result.
439     *  @exception IllegalActionException If the argument token is
440     *   an array token but does not have the same length as this
441     *   token, or if division is not supported between the elements
442     *   of this array and the argument.
443     */
444    @Override
445    public Token divide(Token rightArgument) throws IllegalActionException {
446        try {
447            return _divide(rightArgument);
448        } catch (IllegalActionException ex) {
449            // If the type-specific operation fails, then create a
450            // better error message that has the types of the
451            // arguments that were passed in.
452            throw new IllegalActionException(null, ex,
453                    notSupportedMessage("divide", this, rightArgument));
454        }
455    }
456
457    /** Divide this array token into the specified argument.
458     *  If the argument is an array token and it has
459     *  the same length as this array token, and the division is elementwise.
460     *  Otherwise, each element is divided into the argument.
461     *  This overrides the base class to allow division into scalars.
462     *  @param rightArgument The token into which to divide this token.
463     *  @return A new token containing the result.
464     *  @exception IllegalActionException If the argument token is
465     *   an array token but does not have the same length as this
466     *   token, or if division is not supported between the elements
467     *   of this array and the argument.
468     */
469    @Override
470    public Token divideReverse(Token rightArgument)
471            throws IllegalActionException {
472        try {
473            return _divideReverse(rightArgument);
474        } catch (IllegalActionException ex) {
475            // If the type-specific operation fails, then create a
476            // better error message that has the types of the
477            // arguments that were passed in.
478            throw new IllegalActionException(null, ex,
479                    notSupportedMessage("divide", this, rightArgument));
480        }
481    }
482
483    /** Add the given token to each element of this array.
484     *  @param token The token to be added to this token.
485     *  @return A new array token.
486     *  @exception IllegalActionException If the argument token is not
487     *  of a type that can be added to an element of this token.
488     */
489    public ArrayToken elementAdd(Token token) throws IllegalActionException {
490        Token[] result = new Token[length()];
491
492        try {
493            for (int i = 0; i < length(); i++) {
494                result[i] = getElement(i).add(token);
495            }
496        } catch (IllegalActionException ex) {
497            // If the type-specific operation fails, then create a
498            // better error message that has the types of the
499            // arguments that were passed in.
500            throw new IllegalActionException(null, ex,
501                    notSupportedMessage("elementAdd", this, token));
502        }
503
504        return new ArrayToken(result);
505    }
506
507    /** Divide each element of this array by the given token.
508     *  @param token The token which which to divide this token
509     *  @return An array token.
510     *  @exception IllegalActionException If the argument token is not
511     *  of a type that can be divided into an element of this token.
512     */
513    public ArrayToken elementDivide(Token token) throws IllegalActionException {
514        Token[] result = new Token[length()];
515
516        try {
517            for (int i = 0; i < length(); i++) {
518                result[i] = getElement(i).divide(token);
519            }
520        } catch (IllegalActionException ex) {
521            // If the type-specific operation fails, then create a
522            // better error message that has the types of the
523            // arguments that were passed in.
524            throw new IllegalActionException(null, ex,
525                    notSupportedMessage("elementDivide", this, token));
526        }
527
528        return new ArrayToken(result);
529    }
530
531    /** Modulo each element of this array by the given token.
532     *  @param token The token with which to modulo this token.
533     *  @return An array token.
534     *  @exception IllegalActionException If the argument token is not
535     *  of a type that can be used with modulo.
536     */
537    public ArrayToken elementModulo(Token token) throws IllegalActionException {
538        Token[] result = new Token[length()];
539
540        try {
541            for (int i = 0; i < length(); i++) {
542                result[i] = getElement(i).modulo(token);
543            }
544        } catch (IllegalActionException ex) {
545            // If the type-specific operation fails, then create a
546            // better error message that has the types of the
547            // arguments that were passed in.
548            throw new IllegalActionException(null, ex,
549                    notSupportedMessage("elementModulo", this, token));
550        }
551
552        return new ArrayToken(result);
553    }
554
555    /** Multiply each element of this array by the given token.
556     *  @param token The token with which to multiply this token.
557     *  @return An array token.
558     *  @exception IllegalActionException If the argument token is
559     *  not of a type that can be multiplied to an element of this token.
560     */
561    public ArrayToken elementMultiply(Token token)
562            throws IllegalActionException {
563        Token[] result = new Token[length()];
564
565        try {
566            for (int i = 0; i < length(); i++) {
567                result[i] = getElement(i).multiply(token);
568            }
569        } catch (IllegalActionException ex) {
570            // If the type-specific operation fails, then create a
571            // better error message that has the types of the
572            // arguments that were passed in.
573            throw new IllegalActionException(null, ex,
574                    notSupportedMessage("elementMultiply", this, token));
575        }
576
577        return new ArrayToken(result);
578    }
579
580    /** Return the (exact) return type of the elementMultiply function
581     *  above.  This returns a new array type whose element type is
582     *  the least upper bound of the element type of this token and
583     *  the given type.
584     *  @param type1 The type of the base of the corresponding function.
585     *  @param type2 The type of the argument of the corresponding function.
586     *  @return The type of the value returned from the corresponding
587     *  function.
588     *  @exception IllegalActionException Not thrown in this base class.
589     */
590    public static Type elementMultiplyReturnType(Type type1, Type type2)
591            throws IllegalActionException {
592        if (type1 instanceof ArrayType) {
593            return new ArrayType(TypeLattice.leastUpperBound(
594                    ((ArrayType) type1).getElementType(), type2));
595        } else {
596            return new ArrayType(BaseType.UNKNOWN);
597        }
598    }
599
600    /** Subtract the given token from each element of this array.
601     *  @param token The token to subtract from this token.
602     *  @return An array token.
603     *  @exception IllegalActionException If the argument token is not
604     *  of a type that can be subtracted from an element of this token.
605     */
606    public ArrayToken elementSubtract(Token token)
607            throws IllegalActionException {
608        Token[] result = new Token[length()];
609
610        try {
611            for (int i = 0; i < length(); i++) {
612                result[i] = getElement(i).subtract(token);
613            }
614        } catch (IllegalActionException ex) {
615            // If the type-specific operation fails, then create a
616            // better error message that has the types of the
617            // arguments that were passed in.
618            throw new IllegalActionException(null, ex,
619                    notSupportedMessage("elementSubtract", this, token));
620        }
621
622        return new ArrayToken(result);
623    }
624
625    /** Return true if the class of the argument is ArrayToken and of
626     *  the same length and the elements are equal to that of this
627     *  token.  Equality of the contained elements is tested by their
628     *  equals() method.
629     *  @param object the object to compare with.
630     *  @return True if the argument is an array token of the same length
631     *   and the elements are equal to that of this token.
632     */
633    @Override
634    public boolean equals(Object object) {
635        if (object == null) {
636            return false;
637        }
638        // This test allows instances of a subclass.
639        if (!(object instanceof ArrayToken)) {
640            return false;
641        }
642
643        if (this.isNil() || ((ArrayToken) object).isNil()) {
644            return false;
645        }
646
647        ArrayToken arrayArgument = (ArrayToken) object;
648        int length = arrayArgument.length();
649
650        if (length() != length) {
651            return false;
652        }
653
654        for (int i = 0; i < length(); i++) {
655            if (!getElement(i).equals(arrayArgument.getElement(i))
656                    || getElement(i).isNil()) {
657                return false;
658            }
659        }
660
661        return true;
662    }
663
664    /** Extract a non-contiguous subarray either by giving a boolean array
665     *  of the same length of this array describing which elements to
666     *  include and which to include, or by giving an an array of an
667     *  arbitrary length giving the indices of elements from this array
668     *  to include in the subarray.  An example of the first form is
669     *  {"red","green","blue"}.extract({true,false,true}), which evaluates
670     *  to {"red", "blue"}.  An example of the second form is
671     *  {"red","green","blue"}.extract({2,0,1,1}), which evaluates to
672     *  {"blue", "red", "green", "green"}.
673     *  @param selection An ArrayToken describing the selection of elements
674     *   with which to form the subarray: either an array of integer
675     *   indices, or an array of boolean inclusion/exclusion choices.
676     *  @return An ArrayToken containing the extracted subarray.
677     *  @exception IllegalActionException If the argument type is invalid
678     *   or the result cannot be constructed.
679     *  @exception ArrayIndexOutOfBoundsException  If the argument is an array
680     *   of integers, and one or more of those integers is not a valid
681     *   index into this array.
682     *  @since Ptolemy II 4.1
683     */
684    public ArrayToken extract(ArrayToken selection)
685            throws IllegalActionException {
686        List result = new LinkedList();
687
688        if (selection.getElementType().equals(BaseType.BOOLEAN)) {
689            if (selection.length() != length()) {
690                throw new IllegalActionException(
691                        "When the argument is an array of booleans, it must have "
692                                + "the same length as this array.");
693            }
694
695            for (int i = 0; i < selection.length(); i++) {
696                if (selection.getElement(i).equals(BooleanToken.TRUE)) {
697                    result.add(getElement(i));
698                }
699            }
700        } else if (selection.getElementType().equals(BaseType.INT)) {
701            for (int i = 0; i < selection.length(); i++) {
702                // We could check for out-of-bounds indicies and ignore them,
703                // if we wanted to.
704                int index = ((IntToken) selection.getElement(i)).intValue();
705                result.add(getElement(index));
706            }
707        } else {
708            throw new IllegalActionException(
709                    "The argument must be {boolean} or {int}.");
710        }
711
712        if (result.size() > 0) {
713            Token[] resultArray = new Token[result.size()];
714            resultArray = (Token[]) result.toArray(resultArray);
715            return new ArrayToken(resultArray);
716        } else {
717            return new ArrayToken(getElementType());
718        }
719    }
720
721    /** Return the element at the specified index.
722     *  @param index The index of the desired element.
723     *  @return The token contained in this array token at the
724     *  specified index.
725     *  @exception ArrayIndexOutOfBoundsException If the specified index is
726     *   outside the range of the token array.
727     */
728    public Token getElement(int index) {
729        return _value[index];
730    }
731
732    /** Return the type contained in this ArrayToken.
733     *  @return A Type.
734     */
735    public Type getElementType() {
736        return _elementType;
737    }
738
739    /** Return the type of this ArrayToken.
740     *  @return An ArrayType.
741     */
742    @Override
743    public Type getType() {
744        return new ArrayType(getElementType(), length());
745    }
746
747    /** Return a hash code value for this token. This method returns
748     *  the hash code of the first element, unless the array is empty,
749     *  in which case it returns the hashCode of the element type, unless
750     *  there is no element type, in which case it returns the superclass hash code.
751     *  @return A hash code value for this token.
752     */
753    @Override
754    public int hashCode() {
755        if (length() > 0) {
756            return getElement(0).hashCode();
757        } else if (getElementType() != null) {
758            return getElementType().hashCode();
759        } else {
760            return super.hashCode();
761        }
762    }
763
764    /** Test that the value of this token is close to the first argument,
765     *  where "close" means that the distance between them is less than
766     *  or equal to the second argument.  This method only makes sense
767     *  for arrays where where the distance between elements is reasonably
768     *  represented as a double. This class overrides the superclass to not
769     *  insist that the two array tokens be instances of the same class,
770     *  but rather that they just both be array tokens, and then defers to the
771     *  _isCloseTo() method.
772     *  @param token The token to test closeness of this token with.
773     *  @param epsilon  The value that we use to determine whether two
774     *   tokens are close.
775     *  @return A boolean token that contains the value true if the
776     *   value of this token is close to that of the argument token.
777     *  @exception IllegalActionException If the argument token and
778     *   this token are implemented in different classes.
779     */
780    @Override
781    public BooleanToken isCloseTo(Token token, double epsilon)
782            throws IllegalActionException {
783        if (!(token instanceof ArrayToken)) {
784            throw new IllegalActionException(
785                    notSupportedDifferentClassesMessage("isCloseTo", this,
786                            token));
787        }
788
789        try {
790            return _isCloseTo(token, epsilon);
791        } catch (IllegalActionException ex) {
792            // If the type-specific operation fails, then create a
793            // better error message that has the types of the
794            // arguments that were passed in.
795            throw new IllegalActionException(null, ex,
796                    notSupportedMessage("isCloseTo", this, token));
797        }
798    }
799
800    /** Return true if the token is nil, (aka null or missing).
801     *  Nil or missing tokens occur when a data source is sparsely populated.
802     *  @return True if the token is the {@link #NIL} token.
803     */
804    @Override
805    public boolean isNil() {
806        // We use a method here so that we can easily change how
807        // we determine if a token is nil without modify lots of classes.
808        // Can't use equals() here, or we'll go into an infinite loop.
809        return this == ArrayToken.NIL;
810    }
811
812    /** Return the length of the contained token array.
813     *  @return The length of the contained token array.
814     */
815    public int length() {
816        return _value.length;
817    }
818
819    /** Return a new token whose value is the value of this token
820     *  modulo the value of the argument token.
821     *  This overrides the base class to allow modulo by scalars.
822     *  @param rightArgument The token to divide into this token.
823     *  @return A new token containing the result.
824     *  @exception IllegalActionException If the argument token and
825     *  this token are implemented in different classes, or the
826     *  operation does not make sense for the given types.
827     */
828    @Override
829    public Token modulo(Token rightArgument) throws IllegalActionException {
830        try {
831            return _modulo(rightArgument);
832        } catch (IllegalActionException ex) {
833            // If the type-specific operation fails, then create a
834            // better error message that has the types of the
835            // arguments that were passed in.
836            throw new IllegalActionException(null, ex,
837                    notSupportedMessage("modulo", this, rightArgument));
838        }
839    }
840
841    /** Return a new token whose value is the value of the argument
842     *  modulo the value of this token.
843     *  This overrides the base class to allow modulo by scalars.
844     *  @param rightArgument The token to divide into this token.
845     *  @return A new token containing the result.
846     *  @exception IllegalActionException If the argument token and
847     *  this token are implemented in different classes, or the
848     *  operation does not make sense for the given types.
849     */
850    @Override
851    public Token moduloReverse(Token rightArgument)
852            throws IllegalActionException {
853        try {
854            return _moduloReverse(rightArgument);
855        } catch (IllegalActionException ex) {
856            // If the type-specific operation fails, then create a
857            // better error message that has the types of the
858            // arguments that were passed in.
859            throw new IllegalActionException(null, ex,
860                    notSupportedMessage("modulo", this, rightArgument));
861        }
862    }
863
864    /** Multiply this array token by the specified argument.
865     *  If the argument is an array token and it has
866     *  the same length as this array token, and the multiplication is elementwise.
867     *  Otherwise, each element is multiplied by the argument.
868     *  This overrides the base class to allow multiplication by scalars.
869     *  @param rightArgument The token to multiply by this token.
870     *  @return A new token containing the result.
871     *  @exception IllegalActionException If the argument token is
872     *   an array token but does not have the same length as this
873     *   token, or if multiplication is not supported between the elements
874     *   of this array and the argument.
875     */
876    @Override
877    public Token multiply(Token rightArgument) throws IllegalActionException {
878        try {
879            return _multiply(rightArgument);
880        } catch (IllegalActionException ex) {
881            // If the type-specific operation fails, then create a
882            // better error message that has the types of the
883            // arguments that were passed in.
884            throw new IllegalActionException(null, ex,
885                    notSupportedMessage("multiply", this, rightArgument));
886        }
887    }
888
889    /** Multiply this array token by the specified argument.
890     *  If the argument is an array token and it has
891     *  the same length as this array token, and the multiplication is elementwise.
892     *  Otherwise, each element is multiplied by the argument.
893     *  This overrides the base class to allow multiplication by scalars.
894     *  @param leftArgument The token to multiply by this token.
895     *  @return A new token containing the result.
896     *  @exception IllegalActionException If the argument token is
897     *   an array token but does not have the same length as this
898     *   token, or if multiplication is not supported between the elements
899     *   of this array and the argument.
900     */
901    @Override
902    public Token multiplyReverse(Token leftArgument)
903            throws IllegalActionException {
904        try {
905            return _multiply(leftArgument);
906        } catch (IllegalActionException ex) {
907            // If the type-specific operation fails, then create a
908            // better error message that has the types of the
909            // arguments that were passed in.
910            throw new IllegalActionException(null, ex,
911                    notSupportedMessage("multiplyReverse", this, leftArgument));
912        }
913    }
914
915    /** Return a new ArrayToken representing the multiplicative
916     *  identity.  The returned token contains an array of the same
917     *  size as the array contained by this token, and each element of
918     *  the array in the returned token is the multiplicative identity
919     *  of the corresponding element of this token.
920     *  @return An ArrayToken.
921     *  @exception IllegalActionException If multiplicative identity is not
922     *   supported by the element token.
923     */
924    @Override
925    public Token one() throws IllegalActionException {
926        Token[] oneValueArray = new Token[length()];
927
928        for (int i = 0; i < length(); i++) {
929            oneValueArray[i] = getElement(i).one();
930        }
931
932        return new ArrayToken(oneValueArray);
933    }
934
935    /** Return a new ArrayToken whose elements are in reverse order of this
936     *  ArrayToken.
937     *  @return An ArrayToken
938     *  @exception IllegalActionException If thrown while creating the new
939     *  ArrayToken.
940     */
941    public ArrayToken reverse() throws IllegalActionException {
942        Token[] result = new Token[length()];
943        for (int i = 0; i < length(); i++) {
944            result[i] = getElement(length() - i - 1);
945        }
946        return new ArrayToken(result);
947    }
948
949    /** Return the contiguous subarray starting at the specified index to the
950     *  end of this array. If the specified index is out of range,
951     *  then return an empty array with the same type as this array.
952     *  @param index The index of the beginning of the subarray.
953     *  @return The extracted subarray.
954     *  @exception IllegalActionException If the index argument is
955     *   less than zero.
956     *  @since Ptolemy II 7.1
957     */
958    public ArrayToken subarray(int index) throws IllegalActionException {
959        return subarray(index, length() - index);
960    }
961
962    /** Return the contiguous subarray starting at the specified index and
963     *  of the specified length. If the specified index is out of range,
964     *  or if the specified length extends beyond the end of the array,
965     *  then return an empty array with the same type as this array.
966     *  @param index The index of the beginning of the subarray.
967     *  @param count The length of the subarray.
968     *  @return The extracted subarray.
969     *  @exception IllegalActionException If the index argument is
970     *   less than zero.
971     *  @since Ptolemy II 4.1
972     */
973    public ArrayToken subarray(int index, int count)
974            throws IllegalActionException {
975        if (index < 0) {
976            throw new IllegalActionException(
977                    "index argument of subarray() must be non-negative.");
978        }
979
980        // NOTE: Do not use System.arraycopy here if the
981        // array is a subclass of this class,
982        // so values have to be accessed via the getElement() method,
983        // which is overridden in the subclasses.
984
985        if (count > 0 && index < length() && index >= 0) {
986            if (count + index > length()) {
987                count = length() - index;
988            }
989
990            Token[] result = new Token[count];
991            if (_depth == 0) {
992                System.arraycopy(_value, index, result, 0, count);
993            } else {
994                for (int i = 0; i < count; i++) {
995                    result[i] = getElement(index + i);
996                }
997            }
998            return new ArrayToken(result);
999        } else {
1000            return new ArrayToken(getElementType());
1001        }
1002    }
1003
1004    /** Subtract from this array token the specified argument.
1005     *  If the argument is an array token and it has
1006     *  the same length as this array token, and the subtraction is elementwise.
1007     *  Otherwise, subtract the argument from each element.
1008     *  This overrides the base class to allow subtraction by scalars.
1009     *  @param rightArgument The token to subtract from this token.
1010     *  @return A new token containing the result.
1011     *  @exception IllegalActionException If the argument token is
1012     *   an array token but does not have the same length as this
1013     *   token or length 1, or if division is not supported between the elements
1014     *   of this array and the argument.
1015     */
1016    @Override
1017    public Token subtract(Token rightArgument) throws IllegalActionException {
1018        try {
1019            return _subtract(rightArgument);
1020        } catch (IllegalActionException ex) {
1021            // If the type-specific operation fails, then create a
1022            // better error message that has the types of the
1023            // arguments that were passed in.
1024            throw new IllegalActionException(null, ex,
1025                    notSupportedMessage("subtract", this, rightArgument));
1026        }
1027    }
1028
1029    /** Subtract this array token from the specified argument.
1030     *  If the argument is an array token and it has
1031     *  the same length as this array token, and the subtraction is elementwise.
1032     *  Otherwise, each element is subtracted from the argument.
1033     *  This overrides the base class to allow subtraction from scalars.
1034     *  @param rightArgument The token from which to subtract this token.
1035     *  @return A new token containing the result.
1036     *  @exception IllegalActionException If the argument token is
1037     *   an array token but does not have the same length as this
1038     *   token or length 1, or if division is not supported between the elements
1039     *   of this array and the argument.
1040     */
1041    @Override
1042    public Token subtractReverse(Token rightArgument)
1043            throws IllegalActionException {
1044        try {
1045            return _subtractReverse(rightArgument);
1046        } catch (IllegalActionException ex) {
1047            // If the type-specific operation fails, then create a
1048            // better error message that has the types of the
1049            // arguments that were passed in.
1050            throw new IllegalActionException(null, ex,
1051                    notSupportedMessage("divide", this, rightArgument));
1052        }
1053    }
1054
1055    /** Return the value of this token as a string that can be parsed
1056     *  by the expression language to recover a token with the same value.
1057     *  @return A string beginning with "{" that contains expressions
1058     *  for every element in the array separated by commas, ending with "}".
1059     */
1060    @Override
1061    public String toString() {
1062        StringBuffer buffer = new StringBuffer("{");
1063
1064        for (int i = 0; i < length(); i++) {
1065            buffer.append(getElement(i).toString());
1066
1067            if (i < length() - 1) {
1068                buffer.append(", ");
1069            }
1070        }
1071
1072        buffer.append("}");
1073        return buffer.toString();
1074    }
1075
1076    /** Take an array of unsigned bytes and convert it to an ArrayToken.
1077     *
1078     * @param dataBytes data to be converted to an ArrayToken.
1079     * @return dataArrayToken the resulting ArrayToken.
1080     * @exception IllegalActionException If ArrayToken can not be created.
1081     * @see #arrayTokenToUnsignedByteArray(ArrayToken)
1082     */
1083    public static ArrayToken unsignedByteArrayToArrayToken(byte[] dataBytes)
1084            throws IllegalActionException {
1085        int bytesAvailable = dataBytes.length;
1086        Token[] dataArrayToken = new Token[bytesAvailable];
1087
1088        for (int j = 0; j < bytesAvailable; j++) {
1089            dataArrayToken[j] = new UnsignedByteToken(dataBytes[j]);
1090        }
1091
1092        return new ArrayToken(dataArrayToken);
1093    }
1094
1095    /** Return a new array with all elements equal to those of this
1096     *  array except the one at position <i>index</i>, which has value
1097     *  given by <i>value</i>. If the index is out of range, then return
1098     *  this array token unchanged. The element type of the new array is the
1099     *  least upper bound of the element type of this array and the specified
1100     *  value.
1101     *  @param index The index of the element to be updated.
1102     *  @param value The value of the element to be updated.
1103     *  @return A new array.
1104     *  @exception IllegalActionException Should not be thrown in this base class.
1105     */
1106    public ArrayToken update(int index, Token value)
1107            throws IllegalActionException {
1108        if (index < 0 || index >= length()) {
1109            return this;
1110        }
1111        return new UpdatedArrayToken(this, index, value);
1112    }
1113
1114    /** Returns a new ArrayToken representing the additive identity.
1115     *  The returned token contains an array of the same size as the
1116     *  array contained by this token, and each element of the array
1117     *  in the returned token is the additive identity of the
1118     *  corresponding element of this token.
1119     *  @return An ArrayToken.
1120     *  @exception IllegalActionException If additive identity is not
1121     *  supported by an element token.
1122     */
1123    @Override
1124    public Token zero() throws IllegalActionException {
1125        if (length() == 0) {
1126            return this;
1127        }
1128
1129        Token[] zeroValueArray = new Token[length()];
1130
1131        for (int i = 0; i < length(); i++) {
1132            zeroValueArray[i] = getElement(i).zero();
1133        }
1134
1135        return new ArrayToken(zeroValueArray);
1136    }
1137
1138    ///////////////////////////////////////////////////////////////////
1139    ////                         public variables                  ////
1140
1141    /** A token that represents a missing value.
1142     *  Null or missing tokens are common in analytical systems
1143     *  like R and SAS where they are used to handle sparsely populated data
1144     *  sources.  In database parlance, missing tokens are sometimes called
1145     *  null tokens.  Since null is a Java keyword, we use the term "nil".
1146     */
1147    public static final ArrayToken NIL = new ArrayToken(BaseType.NIL);
1148
1149    ///////////////////////////////////////////////////////////////////
1150    ////                         protected methods                 ////
1151
1152    /** Return a new token whose value is the value of the argument
1153     *  token added to the value of this token.  It is assumed that
1154     *  this class is the class of the argument.
1155     *  @param rightArgument The token whose value we add to the value
1156     *  of this token.
1157     *  @return A new array token containing the result.
1158     *  @exception IllegalActionException If the argument is an
1159     *  ArrayToken of different length, or calling the add method of
1160     *  an element token throws it.
1161     */
1162    @Override
1163    protected Token _add(Token rightArgument) throws IllegalActionException {
1164        Token[] result = null;
1165
1166        if (rightArgument instanceof ArrayToken) {
1167            // Right argument is an array.
1168            ArrayToken rightArray = (ArrayToken) rightArgument;
1169            // If array's lengths match, then do element-wise addition.
1170            if (rightArray.length() == length()) {
1171                result = new Token[length()];
1172                for (int i = 0; i < length(); i++) {
1173                    result[i] = getElement(i).add(rightArray.getElement(i));
1174                }
1175            } else {
1176                if (rightArray.length() == 1) {
1177                    // If the left array has only one element, then expand it
1178                    // and do element-wise addition.
1179                    result = new Token[length()];
1180                    for (int i = 0; i < length(); i++) {
1181                        result[i] = getElement(i).add(rightArray.getElement(0));
1182                    }
1183                } else if (length() == 1) {
1184                    // If the right array has only one element, then expand it
1185                    // and do element-wise addition.
1186                    result = new Token[rightArray.length()];
1187                    for (int i = 0; i < rightArray.length(); i++) {
1188                        result[i] = getElement(0).add(rightArray.getElement(i));
1189                    }
1190                } else {
1191                    // Use this method to get a consistent error message
1192                    // defined in one place.
1193                    _checkArgumentLength(rightArgument);
1194                    // Note that we might not be setting result here.
1195                }
1196
1197            }
1198        } else {
1199            // Right argument is not an array.
1200            // Add right argument to each element in the array.
1201            result = new Token[length()];
1202            for (int i = 0; i < length(); i++) {
1203                result[i] = getElement(i).add(rightArgument);
1204            }
1205        }
1206        if (result == null) {
1207            // FindBugs wants us to check to see if result is null.
1208            throw new InternalErrorException("result was null?");
1209        }
1210        return new ArrayToken(result);
1211    }
1212
1213    /** Return a new token whose value is the value of this token
1214     *  divided by the value of the argument token.  If the argument
1215     *  is an array, then the division is done
1216     *  elementwise. Otherwise, this method assumes that each
1217     *  element can be divided by the argument and performs the
1218     *  division.
1219     *  @param rightArgument The token to divide this token by.
1220     *  @return A new token containing the result.
1221     *  @exception IllegalActionException If the argument is an
1222     *   ArrayToken of different length, or calling the divide method
1223     *   of the element token throws it.
1224     */
1225    @Override
1226    protected Token _divide(Token rightArgument) throws IllegalActionException {
1227        Token[] result = new Token[length()];
1228        if (rightArgument instanceof ArrayToken) {
1229            ArrayToken rightArray = (ArrayToken) rightArgument;
1230            if (rightArray.length() == length()) {
1231                for (int i = 0; i < length(); i++) {
1232                    result[i] = getElement(i).divide(rightArray.getElement(i));
1233                }
1234            } else {
1235                // Maybe one argument or the other is an array
1236                // of length one, converted automatically from
1237                // a scalar.
1238                if (rightArray.length() == 1) {
1239                    Token scalar = rightArray.getElement(0);
1240                    for (int i = 0; i < length(); i++) {
1241                        result[i] = getElement(i).divide(scalar);
1242                    }
1243                } else if (length() == 1) {
1244                    result = new Token[rightArray.length()];
1245                    Token scalar = getElement(0);
1246                    for (int i = 0; i < rightArray.length(); i++) {
1247                        result[i] = scalar.divide(rightArray.getElement(i));
1248                    }
1249                } else {
1250                    // Use this method to get a consistent error message
1251                    // defined in one place.
1252                    _checkArgumentLength(rightArgument);
1253                }
1254            }
1255        } else {
1256            for (int i = 0; i < length(); i++) {
1257                result[i] = getElement(i).divide(rightArgument);
1258            }
1259        }
1260        return new ArrayToken(result);
1261    }
1262
1263    /** Return a new token whose value is the value of this token
1264     *  divided into the value of the argument token.  If the argument
1265     *  is an array, then the division is done
1266     *  elementwise. Otherwise, this method assumes that the argument
1267     *  can be divided by each element of this array and performs the
1268     *  division.
1269     *  @param rightArgument The token into which to divide this token.
1270     *  @return A new token containing the result.
1271     *  @exception IllegalActionException If the argument is an
1272     *   ArrayToken of different length, or calling the divide method
1273     *   of the element token throws it.
1274     */
1275    protected Token _divideReverse(Token rightArgument)
1276            throws IllegalActionException {
1277        if (rightArgument instanceof ArrayToken) {
1278            return ((ArrayToken) rightArgument).divide(this);
1279        } else {
1280            Token[] result = new Token[length()];
1281            for (int i = 0; i < length(); i++) {
1282                result[i] = rightArgument.divide(getElement(i));
1283            }
1284            return new ArrayToken(result);
1285        }
1286    }
1287
1288    /** Test whether the value of this token is close to the first argument,
1289     *  where "close" means that the distance between them is less than
1290     *  or equal to the second argument.  This method only makes sense
1291     *  for tokens where the distance between them is reasonably
1292     *  represented as a double. It is assumed that the argument is
1293     *         an ArrayToken, and the isCloseTo() method of the array elements
1294     *         is used.
1295     *  @param token The token to compare to this token.
1296     *  @param epsilon The value that we use to determine whether two
1297     *   tokens are close.
1298     *  @exception IllegalActionException If the elements do not support
1299     *   this comparison.
1300     *  @return A true-valued token if the first argument is close
1301     *  to this token.
1302     */
1303    @Override
1304    protected BooleanToken _isCloseTo(Token token, double epsilon)
1305            throws IllegalActionException {
1306        ArrayToken rightArray = (ArrayToken) token;
1307
1308        if (length() != rightArray.length()) {
1309            return BooleanToken.FALSE;
1310        }
1311
1312        for (int i = 0; i < length(); i++) {
1313            // Here is where isCloseTo() differs from isEqualTo().
1314            // Note that we return false the first time we hit an
1315            // element token that is not close to our current element token.
1316            BooleanToken result = getElement(i)
1317                    .isCloseTo(rightArray.getElement(i), epsilon);
1318
1319            if (result.booleanValue() == false) {
1320                return BooleanToken.FALSE;
1321            }
1322        }
1323
1324        return BooleanToken.TRUE;
1325    }
1326
1327    /** Return a true-valued token if the argument is equal to this one.
1328     *  The isEqualTo() method of the element tokens is used to make the
1329     *         comparison.  It is assumed that the argument is an ArrayToken.
1330     *  @param token The token to compare to this token.
1331     *  @exception IllegalActionException If the element types do not
1332     *   support this comparison.
1333     *  @return A true-valued token if the argument is equal.
1334     */
1335    @Override
1336    protected BooleanToken _isEqualTo(Token token)
1337            throws IllegalActionException {
1338        if (isNil() || token.isNil()) {
1339            return BooleanToken.FALSE;
1340        }
1341
1342        _checkArgumentLength(token);
1343
1344        ArrayToken rightArray = (ArrayToken) token;
1345
1346        for (int i = 0; i < length(); i++) {
1347            BooleanToken result = getElement(i)
1348                    .isEqualTo(rightArray.getElement(i));
1349
1350            if (result.booleanValue() == false) {
1351                return BooleanToken.FALSE;
1352            }
1353        }
1354
1355        return BooleanToken.TRUE;
1356    }
1357
1358    /** Return a new token whose value is the value of this token
1359     *  modulo the value of the argument token.  It is assumed that
1360     *  this class is the class of the argument.
1361     *  @param rightArgument The token to modulo this token by.
1362     *  @return A new token containing the result.
1363     *  @exception IllegalActionException If the argument is an
1364     *  ArrayToken of different length, or calling the modulo method
1365     *  of the element token throws it.
1366     */
1367    @Override
1368    protected Token _modulo(Token rightArgument) throws IllegalActionException {
1369        Token[] result = new Token[length()];
1370        if (rightArgument instanceof ArrayToken) {
1371            ArrayToken rightArray = (ArrayToken) rightArgument;
1372            if (rightArray.length() == length()) {
1373                for (int i = 0; i < length(); i++) {
1374                    result[i] = getElement(i).modulo(rightArray.getElement(i));
1375                }
1376            } else {
1377                // Maybe one argument or the other is an array
1378                // of length one, converted automatically from
1379                // a scalar.
1380                if (rightArray.length() == 1) {
1381                    Token scalar = rightArray.getElement(0);
1382                    for (int i = 0; i < length(); i++) {
1383                        result[i] = getElement(i).modulo(scalar);
1384                    }
1385                } else if (length() == 1) {
1386                    result = new Token[rightArray.length()];
1387                    Token scalar = getElement(0);
1388                    for (int i = 0; i < rightArray.length(); i++) {
1389                        result[i] = scalar.modulo(rightArray.getElement(i));
1390                    }
1391                } else {
1392                    // Use this method to get a consistent error message
1393                    // defined in one place.
1394                    _checkArgumentLength(rightArgument);
1395                }
1396            }
1397        } else {
1398            for (int i = 0; i < length(); i++) {
1399                result[i] = getElement(i).modulo(rightArgument);
1400            }
1401        }
1402        return new ArrayToken(result);
1403    }
1404
1405    /** Return a new token whose value is the value of this token
1406     *  modulo the value of the argument token.  If the argument
1407     *  is an array, then the modulo is done
1408     *  elementwise. Otherwise, this method assumes that the argument
1409     *  can be moduloed by each element of this array and performs the
1410     *  modulo.
1411     *  @param rightArgument The token into which to modulo this token.
1412     *  @return A new token containing the result.
1413     *  @exception IllegalActionException If the argument is an
1414     *   ArrayToken of different length, or calling the modulo method
1415     *   of the element token throws it.
1416     */
1417    protected Token _moduloReverse(Token rightArgument)
1418            throws IllegalActionException {
1419        if (rightArgument instanceof ArrayToken) {
1420            return ((ArrayToken) rightArgument).modulo(this);
1421        } else {
1422            Token[] result = new Token[length()];
1423            for (int i = 0; i < length(); i++) {
1424                result[i] = rightArgument.modulo(getElement(i));
1425            }
1426            return new ArrayToken(result);
1427        }
1428    }
1429
1430    /** Return a new token whose value is the value of this token
1431     *  multiplied by the value of the argument token.  If the argument
1432     *  is an array token, then it is required to have the same length
1433     *  as this array token, and the multiplication is performed
1434     *  elementwise. Otherwise, each element of this array is multiplied
1435     *  by the argument.
1436     *  @param rightArgument The token to multiply this token by.
1437     *  @return A new token containing the result.
1438     *  @exception IllegalActionException If the argument is an
1439     *  ArrayToken of different length, or calling the multiply method
1440     *  of the element token throws it.
1441     */
1442    @Override
1443    protected Token _multiply(Token rightArgument)
1444            throws IllegalActionException {
1445        Token[] result = new Token[length()];
1446        if (rightArgument instanceof ArrayToken) {
1447            ArrayToken rightArray = (ArrayToken) rightArgument;
1448            if (rightArray.length() == length()) {
1449                for (int i = 0; i < length(); i++) {
1450                    result[i] = getElement(i)
1451                            .multiply(rightArray.getElement(i));
1452                }
1453            } else {
1454                // Maybe one argument or the other is an array
1455                // of length one, converted automatically from
1456                // a scalar.
1457                if (rightArray.length() == 1) {
1458                    Token scalar = rightArray.getElement(0);
1459                    for (int i = 0; i < length(); i++) {
1460                        result[i] = getElement(i).multiply(scalar);
1461                    }
1462                } else if (length() == 1) {
1463                    result = new Token[rightArray.length()];
1464                    Token scalar = getElement(0);
1465                    for (int i = 0; i < rightArray.length(); i++) {
1466                        result[i] = rightArray.getElement(i).multiply(scalar);
1467                    }
1468                } else {
1469                    // Use this method to get a consistent error message
1470                    // defined in one place.
1471                    _checkArgumentLength(rightArgument);
1472                }
1473            }
1474        } else {
1475            for (int i = 0; i < length(); i++) {
1476                result[i] = getElement(i).multiply(rightArgument);
1477            }
1478        }
1479        return new ArrayToken(result);
1480    }
1481
1482    /** Return a new token whose value is the value of the argument
1483     *  token subtracted from the value of this token.  It is assumed
1484     *  that this class is the class of the argument.
1485     *  @param rightArgument The token to subtract to this token.
1486     *  @return A new token containing the result.
1487     *  @exception IllegalActionException If the argument is an
1488     *  ArrayToken of different length, or calling the subtract method
1489     *  of the element token throws it.
1490     */
1491    @Override
1492    protected Token _subtract(Token rightArgument)
1493            throws IllegalActionException {
1494        Token[] result = new Token[length()];
1495        if (rightArgument instanceof ArrayToken) {
1496            ArrayToken rightArray = (ArrayToken) rightArgument;
1497            if (rightArray.length() == length()) {
1498                for (int i = 0; i < length(); i++) {
1499                    result[i] = getElement(i)
1500                            .subtract(rightArray.getElement(i));
1501                }
1502            } else {
1503                // Maybe one argument or the other is an array
1504                // of length one, converted automatically from
1505                // a scalar.
1506                if (rightArray.length() == 1) {
1507                    Token scalar = rightArray.getElement(0);
1508                    for (int i = 0; i < length(); i++) {
1509                        result[i] = getElement(i).subtract(scalar);
1510                    }
1511                } else if (length() == 1) {
1512                    result = new Token[rightArray.length()];
1513                    Token scalar = getElement(0);
1514                    for (int i = 0; i < rightArray.length(); i++) {
1515                        result[i] = scalar.subtract(rightArray.getElement(i));
1516                    }
1517                } else {
1518                    // Use this method to get a consistent error message
1519                    // defined in one place.
1520                    _checkArgumentLength(rightArgument);
1521                }
1522            }
1523        } else {
1524            for (int i = 0; i < length(); i++) {
1525                result[i] = getElement(i).subtract(rightArgument);
1526            }
1527        }
1528        return new ArrayToken(result);
1529    }
1530
1531    /** Return a new token whose value is the value of this token
1532     *  subtracted from the value of the argument token.  If the argument
1533     *  is an array with the same length as this one, then the division is done
1534     *  elementwise. Otherwise, this method assumes that the argument
1535     *  can be subtracted from each element of this array and performs the
1536     *  subtraction.
1537     *  @param rightArgument The token from which to subtract this token.
1538     *  @return A new token containing the result.
1539     *  @exception IllegalActionException If the argument is an
1540     *   ArrayToken of different length (and not length 1), or calling the subtract method
1541     *   of the element token throws it.
1542     */
1543    protected Token _subtractReverse(Token rightArgument)
1544            throws IllegalActionException {
1545        if (rightArgument instanceof ArrayToken) {
1546            return ((ArrayToken) rightArgument).subtract(this);
1547        } else {
1548            Token[] result = new Token[length()];
1549            for (int i = 0; i < length(); i++) {
1550                result[i] = rightArgument.subtract(getElement(i));
1551            }
1552            return new ArrayToken(result);
1553        }
1554    }
1555
1556    ///////////////////////////////////////////////////////////////////
1557    ////                         protected variables               ////
1558
1559    /** The depth of the hierarchy of array tokens used to represent
1560     *  this array. If this array is an instance of this base class,
1561     *  then the depth is 0. Subclasses, however, represent the array
1562     *  in terms of instances of ArrayToken, and in that case, the
1563     *  value of this variable will be the longest path in the hierarchy
1564     *  to the an instance of this ArrayToken class.
1565     */
1566    protected int _depth = 0;
1567
1568    /** The type of this array. */
1569    protected Type _elementType;
1570
1571    ///////////////////////////////////////////////////////////////////
1572    ////                         private methods                   ////
1573    // Throw an exception if the argument is not an ArrayToken of the
1574    // same length.
1575    private void _checkArgumentLength(Token token)
1576            throws IllegalActionException {
1577        int length = ((ArrayToken) token).length();
1578
1579        if (length() != length) {
1580            throw new IllegalActionException("The length of the argument ("
1581                    + length + ") is not the same as the length of this token ("
1582                    + length() + ").");
1583        }
1584    }
1585
1586    ///////////////////////////////////////////////////////////////////
1587    ////                         private variables                 ////
1588
1589    /** The array of values of this array token. */
1590    private Token[] _value;
1591}