source: branches/dev-5819/Compiler/ModelicaFlatTree/src/jastadd/Arrays.jrag @ 13800

Last change on this file since 13800 was 13800, checked in by randersson, 6 weeks ago

#5819 Merged trunk into branch

File size: 143.9 KB
Line 
1/*
2    Copyright (C) 2009 Modelon AB
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, version 3 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17import java.util.Collection;
18import java.util.HashSet;
19import java.util.Map;
20import java.util.ArrayList;
21import java.util.Arrays;
22import java.util.Collections;
23import java.util.Iterator;
24import java.util.NoSuchElementException;
25
26import org.jmodelica.util.collections.ListUtil;
27import org.jmodelica.util.collections.IntIterator;
28
29aspect Arrays {
30
31        /**
32         * Check if an expression is inside array subscripts.
33         */
34        inh boolean FExp.inArraySubscripts();
35        eq FArraySubscripts.getChild().inArraySubscripts() = true;
36        eq FAbstractEquation.getChild().inArraySubscripts() = false;
37        eq Root.getChild().inArraySubscripts() = false;
38
39    /**
40     * Check if an access is an array access.
41     *
42     * @return True if the access has array subscripts, otherwise false.
43     */
44    syn boolean SrcAccess.isArrayAccess() = false;
45    eq SrcArrayAccess.isArrayAccess()     = true;
46
47        /**
48         * Return an Index with these array subscripts.
49         *
50         * This version is not cached, to allow indices to be re-evaluated at each use
51         * during function evaluation.
52         *
53         * @throws ConstantEvaluationException  if the subscripts can't be evaluated to
54         *                                      constant Integer values.
55         */
56        public Index FArraySubscripts.createIndex() {
57                return createIndex(defaultVariableEvaluator());
58        }
59
60    /**
61     * Return an Index with these array subscripts.
62     *
63     * This version is not cached, to allow indices to be re-evaluated at each use
64     * during function evaluation.
65     *
66     * @throws ConstantEvaluationException  if the subscripts can't be evaluated to
67     *                                      constant Integer values.
68     */
69    public Index FArraySubscripts.createIndex(VariableEvaluator evaluator) {
70        if (numSubscript() == 0) {
71            return Index.NULL;
72        }
73        int[] i = new int[numSubscript()];
74        int j = 0;
75        for (Subscript s : subscripts()) 
76            i[j++] = s.value(evaluator);
77        return new Index(i);
78    }
79
80    public interface Subscript {
81        public int ndims();
82        public Size size();
83        public FType type();
84        public int value();
85        public TypePrefixVariability variability();
86        public int[] myIndices();
87        public boolean isCircular();
88        public boolean isColon();
89        public String prettyPrint(String indent);
90        public void prettyPrint(Printer p, CodeStream str, String indent);
91        public void prettyPrint_XML(CodeStream str, String indent);
92        public boolean calculateExpandableConnectorSize(MutableSize s, int i, int len);
93        public FSubscript deferredCopy();
94        public void addDeclarationSize(MutableSize s);
95    }
96    public class IntegerSubscript implements Subscript {
97        private int value;
98        public IntegerSubscript(int value) {
99            this.value = value;
100        }
101        public int value() {
102            return value;
103        }
104    }
105    FSubscript implements Subscript;
106
107    private int[] FArrayLitSubscripts.subscripts = new int[0];
108
109    syn Subscript FArraySubscripts.subscript(int i);
110    eq FArrayExpSubscripts.subscript(int i) = getFSubscript(i);
111    eq FArrayLitSubscripts.subscript(int i) = new IntegerSubscript(subscripts[i]);
112
113    public abstract int FArraySubscripts.numSubscript();
114    public int FArrayLitSubscripts.numSubscript() {
115        return subscripts.length;
116    }
117    public int FArrayExpSubscripts.numSubscript() {
118        return getNumFSubscript();
119    }
120
121    public abstract Iterable<? extends Subscript> FArraySubscripts.subscripts();
122    public Iterable<Subscript> FArrayLitSubscripts.subscripts() {
123        java.util.List<Subscript> list = new ArrayList<>(subscripts.length);
124        for (int i : subscripts) {
125            list.add(new IntegerSubscript(i));
126        }
127        return list;
128    }
129    public Iterable<? extends Subscript> FArrayExpSubscripts.subscripts() {
130        return getFSubscripts();
131    }
132
133    public abstract FArrayExpSubscripts FArraySubscripts.copyAsFArrayExpSubscripts();
134    public FArrayExpSubscripts FArrayExpSubscripts.copyAsFArrayExpSubscripts() {
135        return treeCopy();
136    }
137    public FArrayExpSubscripts FArrayLitSubscripts.copyAsFArrayExpSubscripts() {
138        FSubscript[] list = new FSubscript[subscripts.length];
139        for (int i = 0; i < list.length; i++) {
140            list[i] = new FIntegerSubscript(subscripts[i]);
141        }
142        return new FArrayExpSubscripts(new List(list));
143    }
144
145        /**
146         * Get the dimensions to use in dimension conversion.
147         */
148        syn lazy int[] FDimensionConvert.dimensionsToKeep();
149        eq FScalarExp.dimensionsToKeep() = new int[] {};
150        eq FVectorExp.dimensionsToKeep() {
151                Size s = getFExp().size();
152                int i = getFExp().ndims();
153                for (i = (i > 0) ? i - 1 : 0; i > 0 && s.get(i) == 1; i--);
154                return new int[] { i };
155        }
156        eq FMatrixExp.dimensionsToKeep() = new int[] { 0, 1 };
157
158        /**
159         * Get array dimensions.
160         *
161         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
162         * an error in computation of the array dimensions.
163         *
164         * @return Array dimension.
165         */     
166        syn int FAbstractEquation.ndims() = -1;
167        eq FEquation.ndims() {
168                if (getLeft().ndims() == getRight().ndims()) {
169                        return getLeft().ndims();
170                }
171                return -1;
172        }
173
174        /**
175         * Get array dimensions.
176         *
177         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
178         * an error in computation of the array dimensions.
179         *
180         * @return Array dimension.
181         */     
182        syn int FArraySubscripts.ndims() { 
183                return numSubscript();
184        }
185
186        // Array dimensions
187        /**
188         * Get array dimensions of array subscripts when used in an identifier.
189         *
190         * Here it is not sufficient to check the number of subscripts; the
191         * identifier x[1] has the dimension 0, not 1.
192         *
193         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
194         * an error in computation of the array dimensions.
195         *
196         * @return Array dimension.
197         */     
198        syn int FArraySubscripts.accessNdims();
199        eq FArrayLitSubscripts.accessNdims() = 0; 
200        syn lazy int FArrayExpSubscripts.accessNdims() {
201                int nd = 0;
202                for (FSubscript fs : getFSubscripts()) {
203                        nd += fs.ndims();
204                }
205                return nd;
206        }
207       
208        /**
209         * Get array dimensions.
210         *
211         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
212         * an error in computation of the array dimensions.
213         *
214         * @return Array dimension.
215         */     
216        syn int FSubscript.ndims();
217        eq FExpSubscript.ndims()     = getFExp().ndims();
218        eq FColonSubscript.ndims()   = 1;
219        eq FIntegerSubscript.ndims() = 0;
220        public int IntegerSubscript.ndims() { return 0; }
221       
222        /**
223         * Get array dimensions.
224         *
225         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
226         * an error in computation of the array dimensions.
227         *
228         * @return Array dimension.
229         */     
230        syn int FExp.ndims() = 0;
231        syn lazy int FAbstractArrayExp.ndims() = super.ndims();
232        eq FRangeExp.ndims() = 1;
233        eq FLinspace.ndims() = 1;
234        eq FArray.ndims() {
235                if (isIterArray())
236                        return getFExp(0).ndims();
237                if (getNumFExp()==0)  //Empty array
238                        return 1;
239                // We assume that the FArray is set up correctly and that
240                // all branches are equal.
241                return getFExp(0).ndims() + 1;
242        }
243        eq FAbstractCat.ndims() {
244                int ndims = 2;
245                for (FExp e : getFExps())
246                        if (e.ndims() > ndims)
247                                ndims = e.ndims();
248                return ndims;
249        }
250        eq FCatExp.ndims()         = getFExp(0).ndims();
251        eq FReductionExp.ndims()   = getFExp().isIterExp() ? iterExp().ndims() : 0;
252    eq FSubscriptedExp.ndims() = getFExp().ndims() - getFArraySubscripts().ndims() + getFArraySubscripts().accessNdims();
253        eq FIterExp.ndims() {
254                int exp = getFExp().ndims();
255                return (exp >= 0) ? exp + localNdims() : -1;
256        }
257       
258        /**
259         * The number of dimensions of the iteration indices of this iteration expression.
260         */
261        syn int FIterExp.localNdims() = getNumForIndex();
262       
263        eq FSymmetric.ndims()    = 2;
264        eq FCross.ndims()        = 1;
265        eq FSkew.ndims()         = 2;
266        eq FOuterProduct.ndims() = 2;
267    eq FAbstractDiagonal.ndims() = 2;
268       
269        eq FScalarExp.ndims() = 0;
270        eq FVectorExp.ndims() = 1;
271        eq FMatrixExp.ndims() = 2;
272       
273        eq FUnaryBuiltIn.ndims()              = getFExp().ndims();
274        eq FEventGenExp.ndims()               = getX().ndims();
275        eq FMathematicalFunctionCall.ndims()  = getFExp().ndims();
276       
277        eq FHomotopyExp.ndims()   = vectorizedNdims();
278        eq FSemiLinearExp.ndims() = size().ndims();
279
280    eq FDelayExp.ndims()       = vectorizedNdims();
281    eq FSpatialDistExp.ndims() = vectorizedNdims();
282   
283    eq FReinit.ndims()         = vectorizedNdims();
284    eq FAssert.ndims()         = vectorizedNdims();
285
286        eq FSizeExp.ndims() = hasDim() ? 0 : 1;
287        eq FNdimsExp.ndims() = 0;
288       
289        eq FArrayDimAsArgsExp.ndims()     = getNumFExp();
290        eq FFillExp.ndims()               = getNumFExp() + getFillExp().ndims();
291        eq FFunctionCall.ndims()          = hasOutputs() ? expOutput().ndims() : -1;
292        eq FVectorFunctionCall.ndims()    = size().ndims();
293        eq InstFunctionCall.ndims()       = hasOutputs() ? expOutput().ndims() : -1;
294    eq InstPartialFunctionCall.ndims() = hasOutputs() ? 0 : -1;
295        eq InstVectorFunctionCall.ndims() = getDims();
296
297    /**
298     * Get array dimensions of function argument.
299     */
300    syn int InstFunctionArgument.ndims() = -1;
301    eq InstDefaultArgument.ndims()       = getFExp().ndims();
302    eq InstGivenArgument.ndims()         = getFExp().ndims();
303
304    eq FDeferExp.ndims() = getFExp().ndims();
305
306    eq FBinExp.ndims()   = overloadNdims();
307    eq FUnaryExp.ndims() = overloadNdims();
308
309    syn int FExp.overloadNdims() {
310        if (shouldUseOverloadedOperator()) {
311            InstClassDecl oper = overloadedOperator(true);
312            if (oper != null && !oper.myOutputs().isEmpty())
313                return oper.myOutputs().get(0).ndims();
314        }
315        return ndimsBase();
316    }
317
318    syn int FExp.ndimsBase()   = -1;
319    eq FBinExp.ndimsBase()     = getLeft().ndims();
320    eq FUnaryExp.ndimsBase()   = getFExp().ndims();
321    eq FArtmBinExp.ndimsBase() = Math.max(getLeft().ndims(), getRight().ndims());
322    eq FDivExp.ndimsBase()     = getLeft().ndims();
323    eq FPowExp.ndimsBase()     = getLeft().ndims();
324    eq FMulExp.ndims() {
325        int left = getLeft().ndims();
326        int right = getRight().ndims();
327        if (isElementWise())
328            return Math.max(left, right);
329        if (left > 2 || right > 2)
330            return -1;
331        return left + right - 2;
332    }
333
334        eq FIfExp.ndims() = getThenExp().ndims();
335       
336        eq FSmoothExp.ndims() = getFExp().ndims();
337       
338        eq FVectUnaryBuiltIn.ndims() = getFExp().ndims();
339       
340        /**
341         * Check if multiplication is equivalent with an element-wise multiplication.
342         *
343         * True if any operand is scalar.
344         */
345        syn boolean FMulExp.isElementWise() = (getLeft().ndims() * getRight().ndims() == 0);
346
347    eq FExInStream.ndims() = expDefiningSize().ndims();
348
349    syn FExp FExInStream.expDefiningSize() = (numVars() > 0) ? streamExp(0) : getDefault();
350
351        /**
352         * Get array dimensions.
353         *
354         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
355         * an error in computation of the array dimensions.
356         *
357         * @return Array dimension.
358         */     
359        syn int CommonAccess.ndims();
360    eq CommonAccessExp.ndims() = getAccess().ndims();
361   
362        eq FAccess.ndims() {
363                // Notice here the use of accessNdims. Also, if the access has
364                // no subscripts, it may still have dimension > 0 if its declaration
365                // is an array declaration.
366                // If the FAccess is marked as scalarized, then dimension must
367                // be 0 and using myFV() might cause a NullPointerException.
368                // This is because if scalarization is in progress,
369                // then this node will be hanging without a proper AST.
370                int n = 0;
371                if (!isScalarized())
372                        for (FArraySubscripts fas : allFArraySubscripts())
373                                n += fas.accessNdims();
374                return n;
375        }
376               
377        eq InstAccess.ndims()  = 0;
378        eq InstScalarAccess.ndims() = myInstComponentDecl().ndims();
379        eq InstArrayAccess.ndims()  = getFArraySubscripts().accessNdims();
380    eq InstDot.ndims() {
381        int n = 0;
382        for (InstAccess ia : getInstAccesss()) {
383            n = n + ia.ndims();
384        }
385        return n;
386    }
387    eq InstGlobalAccess.ndims() = getInstAccess().ndims();
388
389    /**
390     * Get array dimensions up to this part for a part of a dotted access. For
391     * an access that is not part of a dotted access, this is equivalent to ndims().
392     *
393     * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
394     * an error in computation of the array dimensions.
395     */
396    syn int InstAccess.combinedNdims() = collectCombinedNdims() + ndims();
397
398    inh int InstAccess.collectCombinedNdims();
399    eq BaseNode.getChild()          .collectCombinedNdims() = 0;
400    eq InstDot .getInstAccess(int i).collectCombinedNdims() {
401        int n = 0;
402        for (int j = 0; j < i; j++) {
403            n += getInstAccess(j).ndims();
404        }
405        return n;
406    }
407
408    /**
409     * Get the expanded FArraySubscripts of each part of this access.
410     */
411    eq InstAccess      .allFArraySubscripts() = Arrays.<FArraySubscripts>asList(new FArrayLitSubscripts());
412    eq InstArrayAccess .allFArraySubscripts() = Arrays.asList(getFArraySubscripts());
413    eq InstScalarAccess.allFArraySubscripts() = Arrays.asList(getExpandedSubscripts());
414    eq InstDot         .allFArraySubscripts() = allFArraySubscriptsTo(getNumInstAccess());
415    eq InstGlobalAccess.allFArraySubscripts() = getInstAccess().allFArraySubscripts();
416
417    /**
418     * Get the expanded FArraySubscripts of each part up to this for a part of a dotted access.
419     * For an access that is not part of a dotted access, this is equivalent to
420     * {@link InstAccess#qualifiedAllFArraySubscripts()}.
421     */
422    syn java.util.List<FArraySubscripts> InstAccess.combinedFArraySubscripts() = 
423        ListUtil.concatenate(collectCombinedFArraySubscripts(), 
424                             allFArraySubscripts());
425
426    inh java.util.List<FArraySubscripts> InstAccess.collectCombinedFArraySubscripts();
427    eq BaseNode.getChild()          .collectCombinedFArraySubscripts() = Collections.emptyList();
428    eq InstDot .getInstAccess(int i).collectCombinedFArraySubscripts() = allFArraySubscriptsTo(i);
429
430    private java.util.List<FArraySubscripts> InstDot.allFArraySubscriptsTo(int n) {
431        java.util.List<FArraySubscripts>[] lists = new java.util.List[n];
432        for (int i = 0; i < n; i++) {
433            lists[i] = getInstAccess(i).allFArraySubscripts();
434        }
435        return ListUtil.concatenate(lists);
436    }
437
438        /**
439         * Get the expanded FArraySubscripts of each part of this access.
440         */
441        syn java.util.List<FArraySubscripts> CommonAccess.allFArraySubscripts();
442        syn lazy java.util.List<FArraySubscripts> FAccess.allFArraySubscripts() {
443                ArrayList<FArraySubscripts> res = createFArraySubscriptsList();
444        if (!hasFArraySubscripts() && myFV().isArray()) {
445            res.add(getExpandedSubscripts());
446        }
447                return res;
448        }
449       
450        /**
451         * Create a list with an FArraySubscripts for each part of this access, empty for parts that has none.
452         */
453    public ArrayList<FArraySubscripts> FAccess.createFArraySubscriptsList() {
454        return new ArrayList<FArraySubscripts>();
455    }
456
457    public ArrayList<FArraySubscripts> FAccessFull.createFArraySubscriptsList() {
458        ArrayList<FArraySubscripts> res = new ArrayList<FArraySubscripts>();
459        for (FAccessPart accessPart : getFAccessParts()) {
460            if (accessPart.hasFArraySubscripts()) {
461                res.add(accessPart.getFArraySubscripts());
462            }
463        }
464        return res;
465    }
466
467        /**
468         * Get the expanded array subscripts of this access.
469         *
470         * An access without subscripts returns subscripts that span the entire component.
471         * Any colon subscripts are expanded into constant vector expressions.
472         */
473        syn lazy FArraySubscripts InstScalarAccess.getExpandedSubscripts() = myInstComponentDecl().expandedSubscripts();
474       
475        /**
476         * Get the expanded array subscripts of this access.
477         *
478         * @return  an FArraySubscripts that spans the entire FV this access points to.
479         */
480    syn lazy FArraySubscripts FAccess.getExpandedSubscripts() {
481                Size s = myFV().size();
482                if (s.isUnknown() && myFV().inRecord()) {
483            s = calcMySize(numParts());
484                }
485                return s.createExpandedFArraySubscripts();
486        }
487       
488        /**
489         * Create an FArraySubscripts that spans all array cells of this component.
490         *
491         * If this is a scalar component, an empty FArraySubscripts is returned.
492         */
493        public FArraySubscripts InstComponentDecl.expandedSubscripts() {
494                return size().createExpandedFArraySubscripts();
495        }
496       
497        /**
498         * Get array dimensions.
499         *
500         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
501         * an error in computation of the array dimensions.
502         *
503         * @return Array dimension.
504         */     
505        syn int InstAssignable.ndims() = hasFArraySubscripts() ? getFArraySubscripts().ndims() : 0;
506       
507        /**
508         * Get array dimensions.
509         *
510         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
511         * an error in computation of the array dimensions.
512         *
513         * @return Array dimension.
514         */     
515        syn int InstNode.ndims() = 0;
516       
517        eq InstComponentDecl.ndims()      = hasFArraySubscripts() ? getFArraySubscripts().ndims() : 0;
518        eq InstArrayComponentDecl.ndims() = retrieveArrayCompNdims();
519
520    /**
521     * The number of array dimensions declared locally on this component, i.e. not from the type.
522     */
523    syn int InstComponentDecl.localNdims() = 
524        hasLocalFArraySubscripts() ? getLocalFArraySubscripts().ndims() : 0;
525
526    inh int InstArrayComponentDecl.retrieveArrayCompNdims();
527    eq InstNode.getChild().retrieveArrayCompNdims()              = ndims() - 1;
528    eq InstRecordConstructor.getChild().retrieveArrayCompNdims() = 0;
529
530        syn int FAbstractVariable.ndims() = -1;
531       
532        eq FVariable.ndims()         = isScalarized()? 0 : getFAccess().declarationNDims();
533    eq FFunctionVariable.ndims() = getType().ndims();
534
535    syn int CommonForIndex.ndims() = 1;
536
537        /**
538         * Get array dimensions.
539         *
540         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
541         * an error in computation of the array dimensions.
542         *
543         * @return Array dimension.
544         */     
545        syn int FAccess.declarationNDims() = 0;
546        eq FAccessFull.declarationNDims() {
547                // Only look at the array subscripts for the last FAccessPart,
548                // all other array subscripts has been expanded in the instantiation.
549                FAccessPart last = getFAccessPart(getNumFAccessPart() - 1);
550                if (last.hasFArraySubscripts()) {
551                        return last.getFArraySubscripts().ndims(); 
552                } else {
553                        return 0;
554                }
555        }
556
557        /**
558         * Get array dimensions of an identifier when used in an identifier.
559         *
560         * Here it is not sufficient to check the number of subscripts; the
561         * identifier x[1] has the dimension 0, not 1.
562         *
563         * A value > 0 indicates an array, 0 indicates a scalar and -1 indicates
564         * an error in computation of the array dimensions.
565         *
566         * @return Array dimension.
567         */             
568        syn int FAccess.accessNdims() = 0;
569        eq FAccessFull.accessNdims() {
570        int res = 0;
571        for (FAccessPart accessPart : getFAccessParts()) {
572            res = res + accessPart.accessNdims();
573        }
574        return res;
575    }
576   
577    syn int FAccessPart.accessNdims() = 0;
578    eq FAccessPartArray.accessNdims() = getFArraySubscripts().accessNdims();
579
580       
581        // Array sizes
582       
583        /**
584         * Get the array sizes.
585         */
586        syn lazy Size FAbstractEquation.size() = Size.SCALAR;
587        eq FEquation.size() {
588                Size left = getLeft().size();
589                Size right = getRight().size();
590                return left.equals(right) ? left : Size.SCALAR;
591        }
592
593        syn Size FAbstractEquation.totalSize() = size().expand(parentTotalSize());
594
595    inh Size FAbstractEquation.parentTotalSize();
596    eq InstForClauseE.getChild().parentTotalSize() {
597        Size s = parentTotalSize();
598        for (InstForIndex i : getInstForIndexs()) {
599            s = i.size().expand(s);
600        }
601        return s;
602    }
603    eq InstRoot.getChild().parentTotalSize() = Size.SCALAR;
604    eq FlatRoot.getChild().parentTotalSize() = Size.SCALAR;
605
606        syn FArraySubscripts FAbstractEquation.expandedSubscripts() {
607        List<FSubscript> list = parentExpandedSubscripts();
608                Size size = size();
609                for (int i = 0; i < size.ndims(); i++) {
610                        list.add(size.createExpandedFSubscript(i));
611                }
612                return FArraySubscripts.createFArraySubscripts(list);
613        }
614
615    inh List<FSubscript> FAbstractEquation.parentExpandedSubscripts();
616    eq InstForClauseE.getChild().parentExpandedSubscripts() {
617        List<FSubscript> list = parentExpandedSubscripts();
618        for (InstForIndex i : getInstForIndexs()) {
619            list.add(i.createFSubscript());
620        }
621        return list;
622    }
623    eq InstRoot.getChild().parentExpandedSubscripts() = new List<FSubscript>();
624    eq FlatRoot.getChild().parentExpandedSubscripts() = new List<FSubscript>();
625
626    public FSubscript InstForIndex.createFSubscript() {
627        return getFExp().flatten(null).createFSubscript();
628    }
629    @Override
630    public FSubscript InstForIndexNoExp.createFSubscript() {
631        return hasFExp() ? super.createFSubscript() : new FColonSubscript();
632    }
633
634        /**
635         * Get the array sizes.
636         */
637        syn Size FArraySubscripts.declarationSize() = declarationSize(subscripts());
638       
639        /**
640         * Get the array size for a collection of FSubscripts.
641         */
642        public static Size FArraySubscripts.declarationSize(Iterable<? extends Subscript> subscripts) {
643                int ndims = 0;
644                for (Subscript s : subscripts)
645                        ndims++;
646                if (ndims == 0)
647                        return Size.SCALAR;
648                MutableSize size = new MutableSize(ndims);
649                for (Subscript subscript : subscripts)
650                        subscript.addDeclarationSize(size);
651                return size;
652        }
653       
654        /**
655         * Add the size of the dimension denoted by this subscript when used
656         *        in a declaration to the given Size.
657         */
658        public abstract void FSubscript.addDeclarationSize(MutableSize s);
659       
660        public void FExpSubscript.addDeclarationSize(MutableSize s) {
661                FExp e = getFExp();
662                if (e.ndims() == 0)
663                        s.append(e);
664                else
665                        s.append(e.size(), 0);
666        }
667       
668        public void FColonSubscript.addDeclarationSize(MutableSize s) {
669                FExp e = new FColonSizeExp(surroundingVariableDecl(), myDim());
670                e.setParent(this);
671                s.append(e);
672        }
673       
674        public void FIntegerSubscript.addDeclarationSize(MutableSize s) {
675                s.append(getValue());
676        }
677   
678    public void IntegerSubscript.addDeclarationSize(MutableSize s) {
679        s.append(value);
680    }
681       
682        /**
683         * The variable declaration that this subscript is a part of the size of, if any.
684         */
685        inh CommonVariableDecl FColonSubscript.surroundingVariableDecl();
686        eq FVariable.getFAccess().surroundingVariableDecl()                   = this;
687        eq InstComponentDecl.getFArraySubscripts().surroundingVariableDecl() = this;
688        eq FExp.getChild().surroundingVariableDecl()                         = null;
689        eq Root.getChild().surroundingVariableDecl()                         = null;
690       
691        /**
692         * The dimension this subscript is used for.
693         */
694        inh int FSubscript.myDim();
695        eq FArrayExpSubscripts.getFSubscript(int i).myDim() = i;
696
697        /**
698         * Get the array sizes when the array subscripts are used in an
699         * access. See also documentation of accessNdims().
700         */
701        syn Size FArraySubscripts.accessSize();
702        eq FArrayLitSubscripts.accessSize() = Size.SCALAR;
703        syn lazy Size FArrayExpSubscripts.accessSize() {
704                if (accessNdims() == 0)
705                        return Size.SCALAR;
706                MutableSize s = new MutableSize(accessNdims());
707                for (FSubscript fs : getFSubscripts()) 
708                        if (fs.ndims() == 1)
709                                s.append(fs.size());
710                return s;
711        }
712       
713        /**
714         * Get the array sizes.
715         */
716        syn Size FExp.size() = Size.SCALAR;
717        syn lazy Size FAbstractArrayExp.size() = super.size();
718
719    eq FBinExp.size()   = overloadSize();
720    eq FUnaryExp.size() = overloadSize();
721
722    syn Size FExp.overloadSize() {
723        if (shouldUseOverloadedOperator()) {
724            InstClassDecl oper = overloadedOperator(true);
725            if (oper != null && !oper.myOutputs().isEmpty())
726                return oper.myOutputs().get(0).size();
727        }
728        return sizeBase();
729    }
730
731    syn Size FExp.sizeBase()  = null;
732    eq FBinExp.sizeBase()     = getLeft().size();
733    eq FUnaryExp.sizeBase()   = getFExp().size();
734    eq FArtmBinExp.sizeBase() = getLeft().isArray() ? getLeft().size() : getRight().size();
735
736    eq FDivExp.sizeBase() = getLeft().size();
737    eq FPowExp.sizeBase() = getLeft().size();
738
739    eq FMulExp.sizeBase() {
740        if (!getLeft().isArray())
741            return getRight().size();
742        if (!getRight().isArray())
743            return getLeft().size();
744        if (!isArray())
745            return Size.SCALAR;
746        MutableSize s = new MutableSize(ndims());
747        if (getLeft().ndims() == 2)
748            s.append(getLeft().size(), 0);
749        if (getRight().ndims() == 2)
750            s.append(getRight().size(), 1);
751        return s;
752    }
753
754    syn boolean FRangeExp.hasStep() = getNumFExp() > 2;
755
756    eq FRangeExp.size() {
757        MutableSize s = new MutableSize(1);
758        FExp start = getFExp(0);
759        FExp stop = getFExp(hasStep() ? 2 : 1);
760        start = start.makeRangeSizeExp();
761        stop = stop.makeRangeSizeExp();
762        FExp exp = stop;
763        if (hasStep() || !start.isIntegerLiteral(1)) {
764            exp = new FSubExp(stop, start);
765            if (hasStep())
766                exp = new FDivExp(exp, getFExp(1).treeCopy());
767            exp = new FAddExp(new FIntegerFuncExp(exp), new FIntegerLitExp(1));
768        } else if (promoteTypeForFExpList(getFExps()).isReal()) {
769            exp = new FIntegerFuncExp(exp);
770        }
771        if (!(exp instanceof FSizeExp)) {
772            exp = new FMaxExp(exp, new Opt(new FIntegerLitExp(0)));
773        }
774        s.append(dynamicFExp(exp));
775        return s;
776    }
777
778    /**
779     * Create a new expression suitable for use in an expression calculating the
780     *        array size of a range expression.
781     */
782    public FExp FExp.makeRangeSizeExp() {
783        return type().wrapRangeSizeExp(fullCopy());
784    }
785
786        /**
787         * Wrap the given expression so it is suitable for use in an expression
788         *        calculating the array size of a range expression.
789         */
790        public FExp FType.wrapRangeSizeExp(FExp exp) {
791                return exp;
792        }
793       
794        public FExp FEnumType.wrapRangeSizeExp(FExp exp) {
795                return new FEnumIntegerExp(exp);
796        }
797       
798        public FExp FBooleanType.wrapRangeSizeExp(FExp exp) {
799                return new FIfExp(exp, new FIntegerLitExp(2), new FIntegerLitExp(1));
800        }
801
802    syn boolean FExp.isIntegerLiteral()         = false;
803    eq FIntegerLitExp.isIntegerLiteral()        = true;
804
805    syn boolean FExp.isIntegerLiteral(int v)    = false;
806    eq FIntegerLitExp.isIntegerLiteral(int v)   = getValue() == v;
807 
808    syn boolean FExp.isRealLiteral()            = false;
809    eq FRealLitExp.isRealLiteral()              = true;
810
811    syn boolean FExp.isRealLiteral(double v)    = false;
812    eq FRealLitExp.isRealLiteral(double v)      = getValue() == v;
813   
814    syn boolean FExp.isZeroLiteral()  = isIntegerLiteral(0);
815    eq FRealLitExp.isZeroLiteral()    = isRealLiteral(0.0);
816
817    eq FArray.isZeroLiteral() {
818        for (FExp e : getFExps()) {
819            if (!e.isZeroLiteral()) {
820                return false;
821            }
822        }
823        return true;
824    }
825
826        eq FLinspace.size() {
827                MutableSize s = new MutableSize(ndims());
828                s.append(getN());
829                return s;
830        }
831       
832        eq FArray.size() {
833            if (getFExp(0) == null)
834                return new Size(0);
835                if (isIterArray())
836                        return getFExp(0).size();
837                return getFExp(0).size().expand(getNumFExp());
838        }
839       
840        syn int FAbstractCat.dimension();
841        eq FCatExp.dimension()    = getDim().ceval().intValue() - 1;
842        eq FMatrix.dimension()    = 0;
843        eq FMatrixRow.dimension() = 1;
844       
845        syn int FSizeExp.dimension() = getDim().ceval().intValue() - 1;
846       
847        eq FAbstractCat.size() {
848                try {
849                        int dim = dimension();
850                        MutableSize ms = getFExp(0).size().promote(ndims()).mutableClone();
851                        for (int i = 1; i < getNumFExp(); i++)
852                                ms.add(dim, getFExp(i).size().promote(ndims()), dim);
853                        return ms;
854                } catch (ConstantEvaluationException e) {
855                        return Size.SCALAR;
856                }
857        }
858       
859        eq FReductionExp.size() = getFExp().isIterExp() ? iterExp().size() : Size.SCALAR;
860       
861        eq FIterExp.size() {
862                if (ndims() <= 0)
863                        return Size.SCALAR;
864                MutableSize s = new MutableSize(ndims());
865                s.append(localSize());
866                s.append(getFExp().size());
867                return s;
868        }
869
870    /**
871     * The size of the iteration indices of this iteration expression.
872     */
873    syn lazy Size FIterExp.localSize() {
874        MutableSize s = new MutableSize(localNdims());
875        for (CommonForIndex fi : getForIndexList()) {
876            if (fi.expIsVector()) {
877                s.append(fi.size());
878            }
879        }
880        return s;
881    }
882
883    /**
884     * Check if the expression of this index is a vector (and thus usable).
885     */
886    syn boolean CommonForIndex.expIsVector() = getFExp().ndims() == 1;
887    eq InstForIndexNoExp.expIsVector()       = true;
888
889        /**
890         * Check if this expression is inside an iteration expression.
891         */
892        inh boolean FExp.inIterExp();
893        eq FIterExp.getFExp().inIterExp()  = true;
894        eq FClass.getChild().inIterExp()   = false;
895        eq InstNode.getChild().inIterExp() = false;
896       
897        /**
898         * Return a size that represents the given size with sizes of surrounding iteration expressions appended.
899         */
900        inh Size FExp.expandSizeForIterExp(Size s);
901        eq FIterExp.getFExp().expandSizeForIterExp(Size s)  = expandSizeForIterExp(s.expand(localSize()));
902        eq FClass.getChild().expandSizeForIterExp(Size s)   = s;
903        eq InstNode.getChild().expandSizeForIterExp(Size s) = s;
904       
905        eq FSubscriptedExp.size() = getFArraySubscripts().accessSize();
906    eq FComponentExp.size()   = type().size();
907       
908        eq FTranspose.size() {
909                Size size = getFExp().size();
910                if (size.ndims() < 2)
911                        return size;
912                MutableSize s = new MutableSize(size.ndims());
913                s.append(size, 1);
914                s.append(size, 0);
915                for (int i = 2; i < s.ndims(); i++)
916                        s.append(size, i);
917                return s;
918        }
919       
920        eq FCross.size()     = new Size(3);
921        eq FSkew.size()      = new Size(3, 3);
922
923    eq FOuterProduct.size() {
924        MutableSize s = new MutableSize(2);
925        s.append(getX().size(), 0);
926        s.append(getY().size(), 0);
927        return s;
928    }
929
930        eq FIdentity.size() {
931                MutableSize s = new MutableSize(2);
932                s.append(getFExp());
933                s.append(getFExp());
934                return s;
935        }
936       
937        eq FDiagonal.size() {
938                MutableSize s = new MutableSize(2);
939                Size s2 = getFExp().size();
940                if (s2 != Size.SCALAR) { 
941                        s.append(s2, 0);
942                        s.append(s2, 0);
943                }
944                return s;
945        }
946       
947        eq FDimensionConvert.size() {
948                if (getFExp().isArray() && isArray()) {
949                        MutableSize s = new MutableSize(ndims());
950                        Size s2 = getFExp().size(); 
951                        for (int d : dimensionsToKeep()) {
952                                if (d < s2.ndims())
953                                        s.append(s2, d);
954                                else
955                                        s.append(1);
956                        }
957                        return s;
958                } else {
959                        return sizeForScalarArg();
960                }
961        }
962        eq FScalarExp.size()        = Size.SCALAR;
963       
964    eq FVectorExp.size() {
965        Size s = getFExp().size();
966        if (s.ndims() > 0 && s.isUnknown()) {
967            FExp e = null;
968            for (int i = 0; i < s.ndims(); i++) {
969                FExp e1 = s.createFExp(i);
970                if (e == null) {
971                    e = e1;
972                } else {
973                    e = new FMulExp(e,e1);
974                }
975            }
976            dynamicFExp(e);
977            MutableSize ss = new MutableSize(1);
978            ss.set(0, e);
979            return ss;
980        }
981        return super.size();
982    }
983       
984        syn Size FDimensionConvert.sizeForScalarArg();
985        eq FScalarExp.sizeForScalarArg() = Size.SCALAR;
986        eq FVectorExp.sizeForScalarArg() = new Size(1);
987        eq FMatrixExp.sizeForScalarArg() = new Size(1, 1);
988       
989        eq FSizeExp.size()  = hasDim() ? Size.SCALAR : new Size(getFExp().ndims());
990        eq FNdimsExp.size() = Size.SCALAR;
991       
992        eq FSmoothExp.size() = getFExp().size();
993       
994        eq FUnaryBuiltIn.size()             = getFExp().size();
995        eq FVectUnaryBuiltIn.size()         = getFExp().size().contractRight(ndims());
996       
997        eq FEventGenExp.size()              = getX().size();
998        eq FMathematicalFunctionCall.size() = getFExp().size();
999        eq FHomotopyExp.size()              = vectorizedSize();
1000        eq FSemiLinearExp.size()            = vectorizedSize();
1001
1002    eq FDelayExp.size()                 = vectorizedSize();
1003    eq FSpatialDistExp.size()           = vectorizedSize();
1004   
1005    eq FReinit.size()                   = vectorizedSize();
1006    eq FAssert.size()                   = vectorizedSize();
1007   
1008    eq FStringExp.size()                = getValue().size();
1009
1010    eq FExInStream.size()               = expDefiningSize().size();
1011
1012    syn Size FBuiltInFunctionCall.vectorizedSize() {
1013        for (FExp e : myArgs())
1014            if (e.isArray())
1015                return e.size();
1016        return Size.SCALAR;
1017    }
1018    eq FSpatialDistExp.vectorizedSize() {
1019        return getIn0().size();
1020    }
1021   
1022    syn int FBuiltInFunctionCall.vectorizedNdims() {
1023        for (FExp e : myArgs())
1024            if (e.isArray())
1025                return e.ndims();
1026        return 0;
1027    }
1028    eq FSpatialDistExp.vectorizedNdims() {
1029        return getIn0().ndims();
1030    }
1031
1032    /**
1033     * An iterable over the arguments of the builtin.
1034     *
1035     * Default implementation is simply an alias for childFExps().
1036     */
1037    syn Iterable<FExp> FBuiltInFunctionCall.myArgs() = childFExps();
1038    eq FDelayExp.myArgs() = hasMax()
1039            ? Arrays.asList(getFExp(), getDelay(), getMax())
1040            : Arrays.asList(getFExp(), getDelay());
1041    eq FSpatialDistExp.myArgs() = Arrays.asList(getIn0(), getIn1(), getX(),
1042            getPositiveVelocity(), getInitialPoints(), getInitialValues());
1043
1044        eq FArrayDimAsArgsExp.size() {
1045                if (!isArray())
1046                        return Size.SCALAR;
1047                MutableSize s = new MutableSize(ndims());
1048                for (FExp fe : getFExps()) 
1049                        s.append(fe);
1050                appendSpecificLengths(s);
1051                return s;
1052        }
1053       
1054        protected void FArrayDimAsArgsExp.appendSpecificLengths(MutableSize s) {}
1055        protected void FFillExp.appendSpecificLengths(MutableSize s) {
1056                s.append(getFillExp().size());
1057        }
1058       
1059        inh Size FFunctionCallLeft.size();
1060        eq FFunctionCallEquation.getLeft(int i).size() = getCall().sizeOfOutput(i);
1061        eq FFunctionCallStmt.getLeft(int i).size()     = getCall().sizeOfOutput(i);
1062       
1063        eq FFunctionCall.size()    = hasOutputs() ? sizeOfOutput(0) : Size.SCALAR;
1064        eq InstFunctionCall.size() = hasOutputs() ? sizeOfOutput(0) : Size.SCALAR;
1065    eq InstPartialFunctionCall.size() = Size.SCALAR;
1066
1067    eq FIfExp.size() {
1068        if (ndims() > 0) {
1069            MutableSize res = new MutableSize(ndims());
1070            for (FExp exp : getSizeExps()) {
1071                res.append(exp);
1072            }
1073            return res;
1074        } else {
1075            return getThenExp().size();
1076        }
1077    }
1078
1079    syn nta List<FExp> FIfExp.getSizeExps() {
1080        List<FExp> res = new List<>();
1081        for (int i = 0; i < ndims(); i++) {
1082            res.add(new FIfExp(getIfExp().treeCopy(), getThenExp().size().createFExp(i), getElseExp().size().createFExp(i)));
1083        }
1084        return res;
1085    }
1086
1087    eq InstIfExp.size() {
1088        if (isParameterIf()) {
1089            try {
1090                return cevalSelectExp().size();
1091            } catch (ConstantEvaluationException e) {
1092            }
1093        }
1094        return getThenExp().size();
1095    }
1096
1097        /**
1098         * Get the array sizes.
1099         */
1100        syn Size CommonAccess.size();
1101        eq FAccess.size() {
1102                if (ndims() == 0)
1103                        return Size.SCALAR;
1104               
1105                MutableSize size = new MutableSize(ndims());
1106                for (FArraySubscripts fas : allFArraySubscripts())
1107                        for (Subscript sub : fas.subscripts()) 
1108                                if (sub.ndims() >= 1)
1109                                        size.append(sub.size());
1110                return size;
1111        }
1112        eq CommonAccessExp.size() = getAccess().size();
1113       
1114    /**
1115     * Get the array sizes.
1116     */
1117    eq InstAccess.size() = Size.SCALAR;
1118    eq InstGlobalAccess.size() = getInstAccess().size();
1119    eq InstScalarAccess.size() = getExpandedSubscripts().accessSize();
1120    eq InstArrayAccess.size()  = getFArraySubscripts().accessSize();
1121    eq InstDot.size() {
1122        if (isArray()) {
1123            MutableSize s = new MutableSize(ndims());
1124            for (InstAccess ia : getInstAccesss()) {
1125                s.append(ia.size());
1126            }
1127            return s;
1128        } else {
1129            return Size.SCALAR;
1130        }
1131    }
1132
1133    /**
1134     * Get the size of all parts of an InstDot up to this part.
1135     */
1136    inh Size InstAccess.partSize();
1137    eq BaseNode.getChild().partSize() = null;
1138    eq InstDot.getInstAccess(int i).partSize() {
1139        int ndims = 0;
1140        for (int j = 0; j <= i; j++) {
1141            ndims += getInstAccess(j).ndims();
1142        }
1143        if (ndims == 0) {
1144            return Size.SCALAR;
1145        } else {
1146            MutableSize s = new MutableSize(ndims);
1147            for (int j = 0; j <= i; j++) {
1148                s.append(getInstAccess(j).size());
1149            }
1150            return s;
1151        }
1152    }
1153
1154    /**
1155     * Get the array sizes.
1156     */
1157    syn Size InstNode.size()               = FArraySubscripts.declarationSize(myFSubscripts()); 
1158    syn lazy Size InstComponentDecl.size() = declaredSize();
1159    eq InstAssignable.size() {
1160        Size s = super.size();
1161        if (s.isUnknown() && hasBindingFExp() && 
1162                (!inRecordDecl() || !isModifiable()) && 
1163                (!isInput() || !inFunction()) &&
1164                !getBindingFExp().isCircular()) {
1165            s = s.createKnown(getBindingFExp());
1166        }
1167        return s;
1168    }
1169   
1170    /**
1171     * Get the array sizes as declared. May be unknown.
1172     */
1173    syn Size InstComponentDecl.declaredSize() = 
1174        hasFArraySubscripts() ? getFArraySubscripts().declarationSize() : defaultSize();
1175    syn Size InstComponentDecl.declaredSizeCalc() =
1176            hasFArraySubscripts() ? getFArraySubscripts().declarationSize() : defaultSizeCalc();
1177
1178    /**
1179     * Find the declared size for a component that does not have any array subscripts in the declaration.
1180     * For all components except the NTA of InstComponentRedeclare, this is simply scalar.
1181     */
1182    inh Size InstComponentDecl.defaultSize();
1183    eq InstComponentRedeclare.getInstComponentDecl().defaultSize() = myInstReplacingComponent().declaredSize();
1184    eq ASTNode.getChild().defaultSize()                            = Size.SCALAR;
1185
1186    /**
1187     * Find the declared calculated size for a component that does not have any array subscripts in the declaration.
1188     * For all components except the NTA of InstComponentRedeclare, this is simply scalar.
1189     */
1190    inh Size InstComponentDecl.defaultSizeCalc();
1191    eq InstComponentRedeclare.getInstComponentDecl().defaultSizeCalc() = myInstReplacingComponent().declaredSizeCalc();
1192    eq ASTNode.getChild().defaultSizeCalc()                            = Size.SCALAR;
1193   
1194        /**
1195         * Get the array sizes.
1196         */     
1197        syn lazy Size FAbstractVariable.size() = Size.SCALAR;
1198        eq FVariable.size()      = isScalarized()? Size.SCALAR: getFAccess().declarationSize();
1199    eq FFunctionVariable.size() = type().size();
1200
1201    /**
1202     * Get the array size of the loop index expression.
1203     */ 
1204    syn Size CommonForIndex.size() = getFExp().size();
1205    eq InstForIndexNoExp.size()    = hasFExp() ? getFExp().size() : new Size(-1);
1206
1207        /**
1208         * Get the array sizes.
1209         */
1210        syn Size FAccess.declarationSize() = Size.SCALAR;
1211        syn lazy Size FAccessFull.declarationSize() {
1212                FAccessPart last = getFAccessPart(getNumFAccessPart()-1);
1213                if (last.hasFArraySubscripts()) {
1214                        return last.getFArraySubscripts().declarationSize(); 
1215                } else {
1216                        return Size.SCALAR;
1217                }
1218        }
1219       
1220        /**
1221         * check if an expression is an array expression.
1222         *
1223         * @return True if array dimension > 0 else false
1224         */
1225        syn boolean FExp.isArray() = ndims()>0;
1226
1227    /**
1228     * Check if an expression is an array expression.
1229     */
1230    syn boolean CommonAccess.isArray() = ndims() > 0;
1231
1232        /**
1233         * check if an access is an array expression.
1234         *
1235         * @return True if array dimension > 0 else false
1236         */
1237        syn boolean InstAccess.isArray() = ndims()>0;
1238
1239        /**
1240         * check if a variable is an array expression.
1241         *
1242         * @return True if array dimension > 0 else false
1243         */
1244        syn boolean FAbstractVariable.isArray() = ndims()>0;
1245       
1246        /**
1247         * check if an instance node is an array expression.
1248         *
1249         * @return True if array dimension > 0 else false
1250         */
1251        syn boolean InstNode.isArray() = ndims()>0;
1252
1253    public abstract String CommonForIndex.name();
1254
1255        /**
1256         * Expand for all values of for indices given in <code>indices</code>.
1257         *
1258         * This is used to get the set of values for array indices while error checking
1259         * and to expand summation reduction expressions.
1260         *
1261         * Size of new Array will be (n + m), where n = indices.size() and m = ndims(). 
1262         */
1263    public ArrayExp Array.createExpanded(Iterable<? extends CommonForIndex> forIndices);
1264
1265    public ArrayExp ArrayExp.createExpanded(Iterable<? extends CommonForIndex> forIndices) {
1266                return createExpanded(this, forIndices);
1267        }
1268
1269    public static ArrayExp ArrayExp.createExpanded(Array exp, Iterable<? extends CommonForIndex> forIndices) {
1270                Indices newIndices = Indices.create(forIndices);
1271                ArrayExp arr = new ArrayExp(Indices.create(expandedSize(exp, newIndices.size())));
1272                Map<String,FExp> indexMap = new HashMap<String,FExp>();
1273                for (Index i : newIndices) {
1274                        newIndices.fillIndexMap(indexMap, i, forIndices);
1275                        for (CommonForIndex fi : forIndices)
1276                                indexMap.put(fi.uniqueIterExpName(), fi.evaluationValue().buildLiteral());
1277            fillSubset(arr, i, indexMap, exp);
1278                }
1279        for (CommonForIndex fi : forIndices) {
1280            fi.clearEvaluationValue();
1281        }
1282                return arr;
1283    }
1284
1285        protected static Size ArrayExp.expandedSize(Array exp, Size size) {
1286                return exp.size().expand(size);
1287        }
1288
1289    protected static void ArrayExp.fillSubset(ArrayExp arr, Index i, Map<String,FExp> indexMap, Array exp) {
1290                for (Index i2 : exp.indices()) {
1291            arr.set(i.expand(i2), createSubsetExp(exp.get(i2), indexMap));
1292                }
1293        }
1294
1295    protected static FExp ArrayExp.createSubsetExp(FExp e, Map<String,FExp> indexMap) {
1296        return e.dynamicFExp(e.fullCopy()).replaceIndices(indexMap);
1297    }
1298
1299    public ArrayExp FExp.createExpanded(Iterable<? extends CommonForIndex> forIndices) {
1300        return ArrayExp.createExpanded(this, forIndices);
1301    }
1302
1303        /**
1304         * Replaces all uses of indices in <code>indexMap</code> with the respective expressions.
1305         *
1306         * May alter the tree below this.
1307         */
1308        protected ASTNode ASTNode.replaceIndices(Map<String,FExp> indexMap) {
1309                ASTNode res = replaceFromIndexMap(indexMap);
1310                if (this == res) {
1311                        for (int i = 0, n = getNumChild(); i < n; i++) {
1312                                ASTNode sub = getChild(i);
1313                                ASTNode repl = sub.replaceIndices(indexMap);
1314                                if (repl != sub)
1315                                        setChild(repl, i);
1316                        }
1317                }
1318                return res;
1319        }
1320       
1321        protected FExp FExp.replaceIndices(Map<String,FExp> indexMap) {
1322                return (FExp) super.replaceIndices(indexMap);
1323        }
1324       
1325        /**
1326         * If this node is a use of an index in <code>indexMap</code>, return the
1327         *        respective expression, otherwise return <code>this</code>.
1328         */
1329        protected ASTNode ASTNode.replaceFromIndexMap(Map<String,FExp> indexMap) {
1330                return this;
1331        }
1332   
1333        protected ASTNode CommonAccessExp.replaceFromIndexMap(Map<String,FExp> indexMap) {
1334                FExp res = indexMap.get(name());
1335                return (res == null) ? this : res;
1336        }
1337       
1338        /**
1339         * Find the closest ancestor that is an FExpSubscript, if any.
1340         */
1341        inh FExpSubscript CommonAccess.surroundingFExpSubscript();
1342        inh FExpSubscript FExpSubscript.surroundingFExpSubscript();
1343        eq FExpSubscript.getChild().surroundingFExpSubscript() = this;
1344        eq Root.getChild().surroundingFExpSubscript()          = null;
1345       
1346        /**
1347         * Find the all ancestors that are FExpSubscripts, if any.
1348         */
1349        syn ArrayList<FExpSubscript> CommonAccess.allSurroundingFExpSubscripts() {
1350                ArrayList<FExpSubscript> list = new ArrayList<FExpSubscript>();
1351                FExpSubscript cur = surroundingFExpSubscript();
1352                while (cur != null) {
1353                        list.add(cur);
1354                        cur = cur.surroundingFExpSubscript();
1355                }
1356                return list;
1357        }
1358
1359    /**
1360     * Computes a generic array expansion of the expression.
1361     *
1362     * @return An Array with scalar expressions if this is an array expression,
1363     *          <code>this</code> otherwise.
1364     */
1365    syn Array FExp.getArray() = this;
1366
1367    eq FAbstractArrayExp.getArray() {
1368        if (isArray()) {
1369            if (canBuildArrayFromChild()) {
1370                return childToBuildArray().getArray();
1371            } else {
1372                return getArrayExp();
1373            }
1374        } else {
1375            return this;
1376        }
1377    }
1378
1379    eq FDeferExp.getArray() = getFExp().getArray();
1380
1381    /*
1382     * canBuildArrayFromChild() and childToBuildArray() are designed so an expression can get its Array
1383     * directly from a child, rather than building a new ArrayExp nta which would be a copy.
1384     */
1385   
1386    syn boolean FAbstractArrayExp.canBuildArrayFromChild() = false;
1387    eq FArray .canBuildArrayFromChild() = isIterArray();
1388    eq FPowExp.canBuildArrayFromChild() = isArray() && getRight().ceval().intValue() == 1;
1389    eq FIfExp .canBuildArrayFromChild() = isArray() && !getThenExp().size().equivalent(getElseExp().size(), inFunction());
1390
1391    syn FExp FAbstractArrayExp.childToBuildArray() { throw new UnsupportedOperationException(); }
1392    eq FArray .childToBuildArray() = getFExp(0);
1393    eq FPowExp.childToBuildArray() = getLeft();
1394    eq FIfExp .childToBuildArray() = cevalSelectExp();
1395
1396    /**
1397     * Computes a generic array expansion of the expression. If this expression is not an array the result is undefined.
1398     * Normally {@link #getArray()} should be called instead.
1399     *
1400     * This is used mainly to scalarize array expressions. Should be overridden for all
1401     * expression types possible, since default implementation clones the original expression
1402     * for each cell.
1403     *
1404     * @return An ArrayExp with scalar expressions if this is an array expression,
1405     *          <code>null</code> otherwise.
1406     */
1407    syn lazy ArrayExp FAbstractArrayExp.getArrayExp() {
1408        if (useTempVar())
1409            return createTempArray();
1410       
1411        ArrayExp res = new ArrayExp(indices());
1412        for (Index i : res.indices())
1413            res.set(i, new FSubscriptedExp(unboundCopy(), i.createFArraySubscripts()));
1414        return res;
1415    }
1416   
1417    /**
1418     * Computes a generic array expansion of the temporary replacing this expression.
1419     */
1420    syn ArrayExp FExp.createTempArray() {
1421        ArrayExp res = new ArrayExp(indices());
1422        for (Index i : res.indices()) {
1423            res.set(i, tempExp(i));
1424        }
1425        return res;
1426    }
1427       
1428        eq FBinExp.getArrayExp() {
1429                /* Standard implementation covers many binary operators.
1430                 * Apply operator element-wise, if one operand is scalar, use it with
1431                 * all elements in other operand. Used for operators that does not
1432                 * allow a scalar and an array as well, since that is caught by the
1433                 * error check.
1434                 */
1435                Array left  = getLeft().getArray();
1436                Array right = getRight().getArray();
1437                ArrayExp res   = new ArrayExp(indices());
1438                for (Index i : res.indices())
1439                        res.set(i, createNode(left.get(i).fullCopy(), right.get(i).fullCopy()));
1440                return res;
1441        }
1442       
1443        eq FUnaryExp.getArrayExp() {
1444                Array src = getFExp().getArray();
1445                ArrayExp res = new ArrayExp(indices());
1446                for (Index i : res.indices())
1447                        res.set(i, createNode(src.get(i).fullCopy()));
1448                return res;
1449        }
1450       
1451        eq FMulExp.getArrayExp() {
1452                if (isElementWise())
1453                        return super.getArrayExp();
1454        if (useTempVar())
1455            return createTempArray();
1456               
1457                ArrayExp res = new ArrayExp(indices());
1458                for (Index i : res.indices()) 
1459                        res.set(i, composeMulScalarCellExp(i));
1460                return res;
1461        }
1462       
1463        protected FExp FMulExp.composeMulScalarCellExp(Index i) {
1464                return vectorMultiplication(getLeft().getArray().leftMulIterator(i), 
1465                                            getRight().getArray().rightMulIterator(i), type());
1466        }
1467       
1468        protected static FExp FExp.vectorMultiplication(Iterator<FExp> left, Iterator<FExp> right, FType type) {
1469                if (!left.hasNext())
1470                        return type.zeroLiteral();
1471                FExp cur = new FMulExp( left.next().fullCopy(), right.next().fullCopy());
1472                while (left.hasNext()) 
1473                        cur = new FAddExp(cur, new FMulExp( left.next().fullCopy(), right.next().fullCopy()));
1474                return cur;
1475        }
1476
1477    eq FPowExp.getArrayExp() {
1478        int e = getRight().ceval().intValue();
1479        if (e < 1) {
1480            return new FIdentity(new FIntegerLitExp(size().get(0))).getArrayExp();
1481        }
1482        if (e == 1) {
1483            /* Handled in getArray() */
1484            throw new UnsupportedOperationException();
1485        }
1486        Array base = getLeft().getArray();
1487        ArrayExp res = null;
1488        FType type = type();
1489        for (; e > 1; e--) {
1490            ArrayExp cur = new ArrayExp(indices());
1491            for (Index i : cur.indices()) {
1492                Iterator<FExp> left = (res == null ? base : res).leftMulIterator(i);
1493                Iterator<FExp> right = base.rightMulIterator(i);
1494                cur.set(i, vectorMultiplication(left, right, type));
1495            }
1496            res = cur;
1497        }
1498        return res;
1499    }
1500
1501        eq FTranspose.getArrayExp() {
1502                Array inner = getFExp().getArray();
1503                ArrayExp res = new ArrayExp(indices());
1504                int[] ind = new int[ndims()];
1505                Index ti = new Index(ind);
1506                for (Index i : res.indices()) {
1507                        ind[0] = i.get(1);
1508                        ind[1] = i.get(0);
1509                        for (int j = 2; j < ind.length; j++)
1510                                ind[j] = i.get(j);
1511                        res.set(i, inner.get(ti));
1512                }
1513                return res;
1514        }
1515       
1516        eq FSymmetric.getArrayExp() {
1517                Array inner = getFExp().getArray();
1518                ArrayExp res = new ArrayExp(indices());
1519                int[] ind = new int[ndims()];
1520                Index ti = new Index(ind);
1521                for (Index i : res.indices()) {
1522                        ind[0] = i.get(0);
1523                        ind[1] = i.get(1);
1524                        if (ind[0] > ind[1]) {
1525                                int temp = ind[0];
1526                                ind[0] = ind[1];
1527                                ind[1] = temp;
1528                        }
1529                        res.set(i, inner.get(ti));
1530                }
1531                return res;
1532        }
1533       
1534        eq FCross.getArrayExp() {
1535                ArrayExp res = new ArrayExp(indices());
1536                Array x = getX().getArray();
1537                Array y = getY().getArray();
1538                for (Index i : res.indices()) {
1539                        int j = i.first() % 3 + 1;
1540                        int k = j % 3 + 1;
1541                        FExp m1 = new FMulExp(x.get(j).fullCopy(), y.get(k).fullCopy());
1542                        FExp m2 = new FMulExp(x.get(k).fullCopy(), y.get(j).fullCopy());
1543                        res.set(i, new FSubExp(m1, m2));
1544                }
1545                return res;
1546        }
1547       
1548        eq FSkew.getArrayExp() {
1549                ArrayExp res = new ArrayExp(indices());
1550                Array inner = getFExp().getArray();
1551                Index j = new Index(new int[1]);
1552                for (Index i : res.indices()) {
1553                        /* Result is:
1554                         * [    0, -x[3],  x[2];
1555                         *   x[3],     0, -x[1];
1556                         *  -x[2],  x[1],     0 ]
1557                         */
1558                        FExp cell = null;
1559                        j.set(0, 6 - i.get(0) - i.get(1));
1560                        switch ((i.get(0) - i.get(1) + 2) % 3) {
1561                        case 0:
1562                                cell = inner.get(j);
1563                                break;
1564                        case 1:
1565                                cell = new FNegExp(inner.get(j).fullCopy());
1566                                break;
1567                        case 2:
1568                                cell = new FIntegerLitExp(0);
1569                                break;
1570                        }
1571                        res.set(i, cell);
1572                }
1573                return res;
1574        }
1575       
1576        eq FOuterProduct.getArrayExp() {
1577                ArrayExp res = new ArrayExp(indices());
1578                Array x = getX().getArray();
1579                Array y = getY().getArray();
1580                for (Index i : res.indices()) 
1581                        res.set(i, new FMulExp(x.get(i.first()).fullCopy(), y.get(i.last()).fullCopy()));
1582                return res;
1583        }
1584       
1585        eq FIdentity.getArrayExp() {
1586                ArrayExp arr = new ArrayExp(indices());
1587                for (Index i : arr.indices())
1588                        arr.set(i, new FIntegerLitExp((i.get(0) == i.get(1)) ? 1 : 0));
1589                return arr;
1590        }
1591       
1592        eq FDiagonal.getArrayExp() {
1593                ArrayExp arr = new ArrayExp(indices());
1594                Array inner = getFExp().getArray();
1595                for (Index i : arr.indices())
1596                        arr.set(i, (i.get(0) == i.get(1)) ? inner.get(i.subIndex(1)) : new FIntegerLitExp(0));
1597                return arr;
1598        }
1599       
1600        eq FDimensionConvert.getArrayExp() {
1601        if (useTempVar())
1602            return createTempArray();
1603                Indices ind = indices();
1604                ArrayExp arr = new ArrayExp(ind);
1605                if (getFExp().isArray()) {
1606                        Array x = getFExp().getArray();
1607                        for (Index i : ind)
1608                                arr.set(i, x.get(ind.translate(i)));
1609                } else {
1610                        Index i = ind.iterator().next();
1611                        arr.set(i, getFExp());
1612                }
1613                return arr;
1614        }
1615       
1616        eq FSizeExp.getArrayExp() {
1617                if (hasDim()) 
1618                        return super.getArrayExp();
1619               
1620                ArrayExp arr = new ArrayExp(indices());
1621                Size size = getFExp().size();
1622                for (Index i : arr.indices())
1623                        arr.set(i, size.createFExp(i.first() - 1));
1624                return arr;
1625        }
1626       
1627        eq FArray.getArrayExp() {
1628                ArrayExp arr = new ArrayExp(indices());
1629                for (Index i : arr.indices())
1630                        fillArray(arr, i, 0);
1631                return arr;
1632        }
1633       
1634        eq FAbstractCat.getArrayExp() {
1635                ArrayExp arr = new ArrayExp(indices());
1636                int dim = dimension();
1637                int adj = 0;
1638                for (FExp exp : getFExps()) {
1639                        Array expArr = exp.getArray();
1640                        for (Index i : expArr.indices()) 
1641                                arr.set(i.adjusted(dim, adj, ndims()), expArr.get(i));
1642                        adj += (exp.ndims() > dim) ? exp.size().get(dim) : 1;
1643                }
1644                return arr;
1645        }
1646       
1647        eq FReductionExp.getArrayExp() {
1648                FIterExp exp = (FIterExp) getFExp();
1649                ArrayExp arr = new ArrayExp(indices());
1650                for (Index i : arr.indices())
1651                        arr.set(i, createNode(exp.extract(i)));
1652                return arr;
1653        }       
1654       
1655        public FExp FIterExp.extract(Index i) {
1656                FExp exp = getFExp().getArray().get(i).fullCopy();
1657                List fil = (List) getForIndexList().fullCopy();
1658                return new FIterExp(exp, fil);
1659        }
1660
1661    eq FIterExp.getArrayExp() = getFExp().getArray().createExpanded(getForIndexList());
1662
1663    eq FSubscriptedExp.getArrayExp() {
1664        if (!getFExp().variability().knownParameterOrLess() && !getFArraySubscripts().variability().knownParameterOrLess()) {
1665            FArraySubscripts fas = getFArraySubscripts();
1666            ArrayExp arr = new ArrayExp(indices());
1667            for (Index i : indices()) {
1668                arr.set(i, new FSubscriptedExp(getFExp().treeCopy(), fas.specifyAll(i)));
1669            }
1670            return arr;
1671        }
1672       
1673        NonConsecutiveIndices expIs = NonConsecutiveIndices.expIndices(getFExp().size(), getFArraySubscripts());
1674        NonConsecutiveIndices fasIs = NonConsecutiveIndices.fasIndices(getFArraySubscripts());
1675        ArrayExp arr = new ArrayExp(indices());
1676        Iterator<Index> it = arr.indices().iterator();
1677       
1678        Array old = getFExp().getArray();
1679        for (Index i : expIs) {
1680            FExp e = old.subArrayFExp(i, expIs);
1681            for (Index j : fasIs) {
1682                FExp e2 = e;
1683                FArraySubscripts fas = getFArraySubscripts().specify(j);
1684                if (fas.ndims() > 0) {
1685                    e2 = new FSubscriptedExp(e, fas);
1686                }
1687                arr.set(it.next(), e2);
1688            }
1689        }
1690       
1691        return arr;
1692    }
1693   
1694    /**
1695     * Filter out known subscripts and copy to a new FArraySubscripts.
1696     * Unknown non-scalar subscripts will be specified
1697     * by the corresponding position in index.
1698     */
1699    syn FArraySubscripts FArraySubscripts.specify(Index index) = treeCopy();
1700    eq FArrayExpSubscripts.specify(Index index) {
1701        List<FSubscript> list = new List<FSubscript>();
1702        int j = 0;
1703        for (FSubscript fs : getFSubscripts()) {
1704            if (!fs.variability().indexParameterOrLess()) {
1705                if (fs.ndims() > 0) {
1706                    fs = fs.specify(index.get(j));
1707                } else {
1708                    fs = fs.treeCopy();
1709                }
1710                j++;
1711                list.add(fs);
1712            }
1713        }
1714        return FArraySubscripts.createFArraySubscripts(list);
1715    }
1716   
1717    syn FArraySubscripts FArraySubscripts.specifyAll(Index index) = treeCopy();
1718    eq FArrayExpSubscripts.specifyAll(Index index) {
1719        List<FSubscript> list = new List<FSubscript>();
1720        int j = 0;
1721        for (FSubscript fs : getFSubscripts()) {
1722            if (fs.ndims() > 0) {
1723                fs = fs.specify(index.get(j++));
1724            } else {
1725                fs = fs.treeCopy();
1726            }
1727            list.add(fs);
1728        }
1729        return FArraySubscripts.createFArraySubscripts(list);
1730    }
1731
1732        eq FSmoothExp.getArrayExp() {
1733                ArrayExp arr = new ArrayExp(indices());
1734                Array inner = getFExp().getArray();
1735                for (Index i : arr.indices())
1736                        arr.set(i, new FSmoothExp(getOrder().fullCopy(), inner.get(i)));
1737                return arr;
1738        }
1739       
1740        eq FVectUnaryBuiltIn.getArrayExp() {
1741                // TODO: This only supports scalar -> scalar functions, see #528
1742                ArrayExp arr = new ArrayExp(indices());
1743                Array inner = getFExp().getArray();
1744                for (Index i : arr.indices())
1745                        arr.set(i, createNode(inner.get(i)));
1746                return arr;
1747        }
1748       
1749        eq FUnaryBuiltIn.getArrayExp() {
1750                ArrayExp arr = new ArrayExp(indices());
1751                Array inner = getFExp().getArray();
1752                for (Index i : arr.indices())
1753                        arr.set(i, createNode(inner.get(i)));
1754                return arr;
1755        }
1756       
1757        eq FEventGenExp.getArrayExp() {
1758                ArrayExp arr = new ArrayExp(indices());
1759                Array inner = getX().getArray();
1760                for (Index i : arr.indices())
1761                        arr.set(i, createNode(inner.get(i)));
1762                return arr;
1763        }
1764       
1765        eq FBinEventGenExp.getArrayExp() {
1766                ArrayExp arr = new ArrayExp(indices());
1767                Array inner1 = getX().getArray();
1768                Array inner2 = getY().getArray();
1769                for (Index i : arr.indices())
1770                        arr.set(i, createNode(inner1.get(i), inner2.get(i)));
1771                return arr;
1772        }
1773       
1774        eq FMathematicalFunctionCall.getArrayExp() {
1775                ArrayExp arr = new ArrayExp(indices());
1776                Array inner = getFExp().getArray();
1777                for (Index i : arr.indices())
1778                        arr.set(i, createNode(inner.get(i)));
1779                return arr;
1780        }
1781       
1782        eq FAtan2Exp.getArrayExp() {
1783                ArrayExp arr = new ArrayExp(indices());
1784                Array inner1 = getFExp().getArray();
1785                Array inner2 = getY().getArray();
1786                for (Index i : arr.indices())
1787                        arr.set(i, createNode(inner1.get(i), inner2.get(i)));
1788                return arr;
1789        }
1790       
1791        eq FHomotopyExp.getArrayExp() {
1792                ArrayExp arr = new ArrayExp(indices());
1793                Array inner1 = getActual().getArray();
1794                Array inner2 = getSimplified().getArray();
1795                for (Index i : arr.indices())
1796                        arr.set(i, createNode(inner1.get(i), inner2.get(i)));
1797                return arr;
1798        }
1799       
1800        eq FSemiLinearExp.getArrayExp() {
1801                ArrayExp arr = new ArrayExp(indices());
1802                Array inner1 = getX().getArray();
1803                Array inner2 = getPosSlope().getArray();
1804                Array inner3 = getNegSlope().getArray();
1805                for (Index i : arr.indices())
1806                        arr.set(i, createNode(inner1.get(i), inner2.get(i), inner3.get(i)));
1807                return arr;
1808        }
1809
1810    eq FVectorFunctionCall.getArrayExp() {
1811        ArrayExp arr = new ArrayExp(indices());
1812        boolean[] vec = getVectorized();
1813        int j;
1814        for (Index i : arr.indices()) {
1815            List<FExp> args = new List<FExp>();
1816            j = 0;
1817            for (FExp arg : getArgs()) 
1818                args.add(vec[j++] ? arg.getArray().subArrayFExp(i) : arg);
1819            arr.set(i, new FFunctionCall(getName().fullCopy(), args, getFType().scalarType()));
1820        }
1821        return arr;
1822    }
1823
1824    eq FReinit.getArrayExp() {
1825        ArrayExp arr = new ArrayExp(indices());
1826        Array inner1 = getVar().getArray();
1827        Array inner2 = getFExp().getArray();
1828        for (Index i : arr.indices())
1829            arr.set(i, new FReinit(inner1.get(i), inner2.get(i)));
1830        return arr;
1831    }
1832   
1833    eq FAssert.getArrayExp() {
1834        ArrayExp arr = new ArrayExp(indices());
1835        Array inner1 = getTest().getArray();
1836        Array inner2 = getMsg().getArray();
1837        Array inner3 = null;
1838        if (hasLevel()) {
1839            inner3 = getLevel().getArray();
1840        }
1841        for (Index i : arr.indices()) {
1842            arr.set(i, new FAssert(inner1.get(i), inner2.get(i), hasLevel() ? new Opt<FExp>(inner3.get(i)) : new Opt<FExp>()));
1843        }
1844        return arr;
1845    }
1846
1847    eq FDelayExp.getArrayExp() {
1848        ArrayExp arr = new ArrayExp(indices());
1849        for (Index i : arr.indices()) {
1850            arr.set(i, createNode(getFExp().getArray().get(i), getDelay().getArray().get(i), 
1851                    hasMax() ? new Opt(getMax().getArray().get(i)) : new Opt()));
1852        }
1853        return arr;
1854    }
1855   
1856    eq FSpatialDistExp.getArrayExp() {
1857        ArrayExp arr = new ArrayExp(indices());
1858        boolean vecPoints = getInitialPoints().ndims() > 1;
1859        boolean vecValues = getInitialValues().ndims() > 1;
1860        FExp points = getInitialPoints();
1861        FExp values = getInitialValues();
1862        for (Index i : arr.indices()) {
1863            if (vecPoints) {
1864                points = getInitialPoints().getArray().subArrayFExp(i);
1865            }
1866            if (vecValues) {
1867                values = getInitialValues().getArray().subArrayFExp(i);
1868            }
1869            arr.set(i, new FSpatialDistExp(getIn0().getArray().subArrayFExp(i), getIn1().getArray().subArrayFExp(i), getX().fullCopy(),
1870                    getPositiveVelocity().fullCopy(), points, values));
1871        }
1872        return arr;
1873    }
1874
1875    eq FExInStream.getArrayExp() {
1876        ArrayExp arr = new ArrayExp(indices());
1877        for (Index i : arr.indices()) {
1878            FExInStream cell = new FExInStream(getDefault().getArray().get(i).treeCopy(), getEps().treeCopy(), new List<FExp>());
1879            for (FExp e : getVars()) {
1880                Index j = (e.ndims() < i.ndims()) ? i.partIndex(0, e.ndims()) : i;
1881                cell.addVarNoTransform(e.getArray().get(j).treeCopy());
1882            }
1883            arr.set(i, cell);
1884        }
1885        return arr;
1886    }
1887
1888        /**
1889         * Add a copy of this expression to arr at position i.
1890         */
1891        public void FExp.fillArray(ArrayExp arr, Index i, int level) {
1892                if (isArray())
1893            arr.set(i, getArray().get(i.subIndex(level)).copySymbolic());
1894                else
1895            arr.set(i, copySymbolic());
1896        }
1897       
1898        /**
1899         * Add a copy of the expression at position i to arr.
1900         *
1901         * @param arr    the Array to add the expression to.
1902         * @param i      the index to add at, denotes position in both Array and FArray.
1903         * @param level  the level this FArray is at in a structure of nestled FArrays.
1904         */
1905        public void FArray.fillArray(ArrayExp arr, Index i, int level) {
1906            if (isIterArray())
1907                super.fillArray(arr, i, level);
1908            else
1909                getFExp(i.get(level) - 1).fillArray(arr, i, level + 1);
1910        }
1911
1912    eq InstFunctionCall.getArrayExp() {
1913        if (variability().knownParameterOrLess()) {
1914            try {
1915                ArrayExp arr = new ArrayExp(indices());
1916                CValue val = cevalArray(Index.NULL);
1917                if (val.isArray()) {
1918                    CValueArray carr = val.array();
1919                    for (Index i : arr.indices()) {
1920                        arr.set(i, carr.getCell(i).buildInstLiteral());
1921                    }
1922                    return arr;
1923                }
1924            } catch (ConstantEvaluationException r) {
1925                // Constant evaluation may fail even if variability is known parameter or less.
1926                // If so we want to do the same thing we would do if variability was higher.
1927            }
1928        }
1929        return super.getArrayExp();
1930    }
1931
1932    eq FFunctionCall.getArrayExp() {
1933        FClass fc = myFClass();
1934        if (!isComposite() || fc == null) {
1935            return super.getArrayExp();
1936        }
1937       
1938        if (isArray() && variability().knownParameterOrLess() && inKeptBExp()) {
1939            ArrayExp arr = new ArrayExp(indices());
1940            CValueArray carr = (CValueArray) cevalArray(Index.NULL);
1941            for (Index i : arr.indices()) {
1942                arr.set(i, carr.getCell(i).buildLiteral());
1943            }
1944            return arr;
1945        }
1946       
1947        if (isFunctionCallArg()) {
1948            return super.getArrayExp();
1949        }
1950       
1951        return createTempArray();
1952    }
1953
1954        /**
1955         * A name that is not a valid Modelica identifier, and is unique among the iteraton indices
1956         * of nestled iteration expressions.
1957         */
1958        syn lazy String CommonForIndex.uniqueIterExpName() = name() + '|' + iterExpDepth();
1959       
1960        /**
1961         * The number of nestled iteration expressions surrounding this index or iteration expression.
1962         */
1963        inh int CommonForIndex.iterExpDepth();
1964        inh int FIterExp.iterExpDepth();
1965        eq FIterExp.getFExp().iterExpDepth()  = iterExpDepth() + 1;
1966        eq FClass.getChild().iterExpDepth()   = 0;
1967        eq InstNode.getChild().iterExpDepth() = 0;
1968
1969    eq FIfExp.getArrayExp() {
1970        ArrayExp arr = new ArrayExp(indices());
1971        Array thenArr = getThenExp().getArray();
1972        Array elseArr = getElseExp().getArray();
1973        for (Index i : arr.indices()) {
1974            FExp ifExp = getIfExp().fullCopy();
1975            arr.set(i, createNode(ifExp, thenArr.get(i), elseArr.get(i)));
1976        }
1977        return arr;
1978    }
1979
1980        eq CommonAccessExp.getArrayExp() {
1981                /*
1982                 * Based on an array access, say x, corresponding to the declaration
1983                 * Real x[2], the array {x[1],x[2]} is generated.
1984                 */
1985                ArrayExp array = new ArrayExp(indices());
1986                for (Index i : array.indices()) 
1987                        array.set(i, createSpecifiedNode(i, false));
1988                return array;
1989        }
1990       
1991
1992    public abstract FExp CommonAccessExp.createSpecifiedNode(Index i, boolean scalarize);
1993    public FExp InstAccessExp.createSpecifiedNode(Index i, boolean scalarize) {
1994        return createNode(getInstAccess().specify(i, scalarize));
1995    }
1996    public FExp FAccessExp.createSpecifiedNode(Index i, boolean scalarize) {
1997        return createNode(getFAccess().specify(i, scalarize));
1998    }
1999
2000        /**
2001         * Returns a scalar CommonAccess, as specified by an index.
2002         *
2003         * The use is marked scalarized if this use is.
2004         *
2005         * @param i  the Index specifying what array subscripts to use
2006         */
2007        public abstract CommonAccess CommonAccess.specify(Index i);
2008       
2009        /**
2010         * Returns a scalar CommonAccess, as specified by an index.
2011         *
2012         * @param i          the Index specifying what array subscripts to use
2013         * @param scalarize  <code>true</code> if the use should be marked as scalarized
2014         */
2015        public abstract CommonAccess CommonAccess.specify(Index i, boolean scalarize);
2016       
2017        /**
2018         * Creates a new FAccess with the FArraySubscripts taken from the given Index.
2019         *
2020         * The FAccess is marked scalarized if this use is.
2021         *
2022         * @param i  the Index specifying what array subscripts to use
2023         */
2024        public FAccess FAccess.specify(Index i) {
2025                return specify(i, isScalarized());
2026        }
2027       
2028        /**
2029         * Creates a new FAccess with the FArraySubscripts taken from the given Index.
2030         *
2031         * @param i          the Index specifying what array subscripts to use
2032         * @param scalarize  <code>true</code> if the FAccess should be marked as scalarized
2033         */
2034        public FAccess FAccess.specify(Index i, boolean scalarize) {
2035                FAccess access = copyAndAddFas(i.createFArraySubscripts());
2036                access.scalarized = scalarize;
2037                return access;
2038        }
2039       
2040        public FAccess FAccessFull.specify(Index i, boolean scalarize) {
2041                FAccessFull res = new FAccessFull();
2042                int[] dim = new int[1];
2043                int np = getNumFAccessPart();
2044                for (int j = 0; j < np; j++) {
2045                        FAccessPart part = getFAccessPart(j);
2046                        int n = part.numFSubscripts();
2047                        if (n == 0 && j == np - 1)
2048                                n = i.ndims() - dim[0];
2049                        FArraySubscripts newfas = null;
2050                        if (n > 0) {
2051                if (part.hasFArraySubscripts()) {
2052                    newfas = part.getFArraySubscripts().createSpecified(i, dim);
2053                } else {
2054                    List<FSubscript> newSubscripts = new List<>();
2055                    for (int k = 0; k < n; k++) {
2056                        newSubscripts.add(new FIntegerSubscript(i.get(dim[0]++)));
2057                    }
2058                    newfas = FArraySubscripts.createFArraySubscripts(newSubscripts);
2059                                }
2060                // If this is last part, append the rest of i to newfas
2061                while (j == np - 1 && dim[0] < i.ndims())
2062                    newfas.addFSubscript(i.get(dim[0]++));
2063                        }
2064                        FAccessPart newpart = (newfas == null) ? 
2065                                        new FAccessPart(part.getName()) : 
2066                                        new FAccessPartArray(part.getName(), newfas);
2067                        res.addFAccessPart(newpart);
2068                }
2069                res.scalarized = scalarize;
2070                return res;
2071        }
2072       
2073    public FArraySubscripts FArraySubscripts.createSpecified(Index i, int[] dim) {
2074        return treeCopy();
2075    }
2076   
2077    public FArraySubscripts FArrayExpSubscripts.createSpecified(Index i, int[] dim) {
2078        if (ndims() == 0) {
2079            return super.createSpecified(i, dim);
2080        }
2081       
2082        List<FSubscript> subscripts = new List<>();
2083        for (FSubscript fs : getFSubscripts()) {
2084            subscripts.add(fs.createSpecified(i, dim));
2085        }
2086        return FArraySubscripts.createFArraySubscripts(subscripts);
2087    }
2088
2089        /**
2090         * Creates a new FSubscript that specifies this array subscript to a single index.
2091         *
2092         * - For scalar subscripts, a copy is returned.
2093         * - For colon subscripts, the given index is used as the new subscript.
2094         * - For other vector subscripts, the given index is used as the index of a
2095         *   cell in the vector, and that cell is used as the new subscript.
2096         *   In this case, dim will be incremented.
2097         *
2098         * @param i    the Index specifying what array subscripts to use
2099         * @param dim  the dimension in <code>i</code> to use,
2100         *             wrapped in an array so that it can be changed by the method
2101         */
2102        public FSubscript FSubscript.createSpecified(Index i, int[] dim) {
2103                return fullCopy();
2104        }
2105       
2106        public FSubscript FColonSubscript.createSpecified(Index i, int[] dim) {
2107                return new FIntegerSubscript(i.get(dim[0]++));
2108        }
2109       
2110        public FSubscript FExpSubscript.createSpecified(Index i, int[] dim) {
2111                if (ndims() == 0)
2112                        return fullCopy();
2113               
2114                int index = i.get(dim[0]++) - 1;
2115                return getFExp().getArray().getFExp(index).createFSubscript();
2116        }
2117       
2118        /**
2119         * Gets the number of FSubscripts in the FArraySubscripts of this FAccessPart, if any.
2120         */
2121        syn int FAccessPart.numFSubscripts() = 
2122                hasFArraySubscripts() ? getFArraySubscripts().numSubscript() : 0;
2123       
2124        /**
2125         * Creates a new InstAccess with the FArraySubscripts taken from the given Index.
2126         *
2127         * @param i  the Index specifying what array subscripts to use
2128         */
2129        public InstAccess InstAccess.specify(Index i) {
2130                return specifyEach(i, new int[1]);
2131        }
2132
2133    /* Returns a scalar InstAccess, as specified by an index.
2134     *
2135     * @param i          the Index specifying what array subscripts to use
2136     * @param scalarize  ignored (needed by superclass implementation)
2137     */
2138    public InstAccess InstAccess.specify(Index i, boolean scalarize) {
2139        return specify(i);
2140    }
2141
2142        /**
2143         * Create a copy with the FArraySubscripts of each part set to match the Index.
2144         *
2145         * @param i    the Index specifying what array subscripts to use
2146         * @param dim  the next dimension in <code>i</code> to use,
2147         *             wrapped in an array so that it can be changed by the method
2148         */
2149        protected InstAccess InstAccess.specifyEach(Index i, int[] dim) {
2150                return treeCopy();
2151        }
2152
2153        protected InstDot InstDot.specifyEach(Index i, int[] dim) {
2154                List<InstAccess> l = new List<InstAccess>();
2155                for (InstAccess ia : getInstAccesss())
2156                        l.add(ia.specifyEach(i, dim));
2157                return new InstDot(l);
2158        }
2159
2160        protected InstGlobalAccess InstGlobalAccess.specifyEach(Index i, int[] dim) {
2161                return new InstGlobalAccess(getInstAccess().specifyEach(i, dim));
2162        }
2163       
2164        protected InstNamedAccess InstScalarAccess.specifyEach(Index i, int[] dim) { //TODO:Necessary?
2165                FArraySubscripts oldfas = allFArraySubscripts().get(0);
2166                int n = oldfas.ndims();
2167                if (n > 0) {
2168                        return getArrayCopy(oldfas.createSpecified(i, dim));
2169                } else {
2170                        return treeCopy();
2171                }
2172        }
2173
2174    /**
2175     * Get a specific cell of this array component decl.
2176     *
2177     * Only valid if this is an array and <code>i</code> refers to an element of it.
2178     */
2179    syn InstComponentDecl InstComponentDecl.specify(Index i) = specifyHelper(i, 0);
2180
2181    syn InstComponentDecl InstComponentDecl.specifyHelper(Index i, int d) = 
2182        (d >= i.ndims() || !isArray()) 
2183            ? this 
2184            : getInstComponentDecl(i.get(d) - 1).specifyHelper(i, d + 1);
2185    eq InstPrimitive.specifyHelper(Index i, int d) = this;
2186
2187        syn InstArrayAccess InstScalarAccess.getArrayCopy(FArraySubscripts fas);
2188        eq InstParseAccess.getArrayCopy(FArraySubscripts fas) = new InstParseArrayAccess(getID(), fas);
2189        eq InstAmbiguousAccess.getArrayCopy(FArraySubscripts fas) = new InstAmbiguousArrayAccess(getID(), fas);
2190        eq InstComponentAccess.getArrayCopy(FArraySubscripts fas) = new InstComponentArrayAccess(getID(), fas);
2191
2192        protected InstNamedAccess InstArrayAccess.specifyEach(Index i, int[] dim) {
2193                InstArrayAccess res = treeCopy();
2194                FArraySubscripts oldfas = allFArraySubscripts().get(0);
2195                int n = oldfas.ndims();
2196                if (n > 0) {
2197                        res.setFArraySubscripts(oldfas.createSpecified(i, dim));
2198                }
2199                return res;
2200        }
2201
2202        eq FRangeExp.getArrayExp() {
2203                //log.debug("FRangeExp.getArray(): size = " + size().get(0));
2204                ArrayExp array = new ArrayExp(indices());
2205                if (type().isReal()) {
2206                        double i1 = getFExp(0).ceval().realValue();
2207                        double i2 = 1.0;
2208                        if (hasStep()) 
2209                                i2 = getFExp(1).ceval().realValue();
2210                        for (Index i : array.indices()) { 
2211                                array.set(i, new FRealLitExp(i1));
2212                                i1 += i2;
2213                        }
2214                } else {
2215                        int i1 = getFExp(0).ceval().intValue();
2216                        int i2 = 1;
2217                        if (hasStep()) 
2218                                i2 = getFExp(1).ceval().intValue();
2219                        for (Index i : array.indices()) { 
2220                                array.set(i, type().createLiteral(i1));
2221                                i1 += i2;
2222                        }
2223                }
2224               
2225                return array;
2226        }
2227       
2228        eq FLinspace.getArrayExp() {
2229                int n = size().get(0);
2230                FExp len = new FSubExp(getStopExp().fullCopy(), getStartExp().fullCopy());
2231                FExp step = new FDivExp(len, new FIntegerLitExp(n - 1));
2232                ArrayExp array = new ArrayExp(indices());
2233                for (Index i : array.indices()) {
2234                        FExp part = new FMulExp(new FIntegerLitExp(i.first() - 1), step.unboundCopy());
2235                        array.set(i, new FAddExp(getStartExp().fullCopy(), part));
2236                }
2237                return array;
2238        }
2239       
2240        eq FArrayDimAsArgsExp.getArrayExp() = new ArrayExp(indices()).fill(fillExp());
2241       
2242        /**
2243         * Get the expression the array is filled with.
2244         *
2245         * E.g. a literal 1 in the case of <code>ones()</code>.
2246         * Will only create new nodes if necessary.
2247         */
2248        syn FExp FArrayDimAsArgsExp.fillExp();
2249        eq FZeros.fillExp()   = new FIntegerLitExp(0);
2250        eq FOnes.fillExp()    = new FIntegerLitExp(1);
2251        eq FFillExp.fillExp() = getFillExp();
2252       
2253        /**
2254         * Get the set of all array indices of an array access.
2255         *
2256         * @return An Indices object containing all indices in each array dimension.
2257         */
2258        syn Indices FExp.indices()                   = Indices.create(size());
2259        syn lazy Indices FAbstractArrayExp.indices() = super.indices();
2260        eq CommonAccessExp.indices()                 = getAccess().indices();
2261        eq FDimensionConvert.indices() {
2262                int n = getFExp().ndims();
2263                if (n == 0) {
2264                        return Indices.create(size());
2265                } else {
2266                        int extra = Math.max(ndims() - n, 0);
2267            int[] keep = dimensionsToKeep();
2268            if (keep.length + extra == 0)
2269                return Indices.create(Size.SCALAR);
2270            return NonConsecutiveIndices.create(getFExp().size(), keep, extra);
2271                }
2272        }
2273       
2274        /**
2275         * Get the set of all array indices of an array access.
2276         *
2277         * @return An Indices object containing all indices in each array dimension.
2278         */
2279        syn lazy Indices FArraySubscripts.indices() = Indices.createFromFas(this);
2280       
2281        /**
2282         * Get the set of all array indices of an array access.
2283         *
2284         * @return An Indices object containing all indices in each array dimension.
2285         */
2286        syn Indices FSubscript.indices() = Indices.create(size());
2287       
2288        /**
2289         * Get the set of all array indices of an array access.
2290         *
2291         * @return An Indices object containing all indices in each array dimension.
2292         */
2293        syn lazy Indices FType.indices() = Indices.create(size());
2294       
2295        /**
2296         * Get the set of all array indices of an array access.
2297         *
2298         * @return An Indices object containing all indices in each array dimension.
2299         */
2300        syn Indices FExpSubscript.indices() = getFExp().indices();
2301
2302        /**
2303         * Get the set of all array indices of an array access.
2304         *
2305         * @return An Indices object containing all indices in each array dimension.
2306         */
2307        syn Indices CommonAccess.indices() = Indices.createFromFas(allFArraySubscripts());
2308
2309        /**
2310         * Get the set of all array indices of an instance array access.
2311         *
2312         * @return An Indices object containing all indices in each array dimension.
2313         */
2314        syn Indices InstAccess.indices() = Indices.createFromFas(allFArraySubscripts());
2315
2316    /**
2317     * Get the set of array indices up to this part for a part of a dotted access. For
2318     * an access that is not part of a dotted access, this is equivalent to indices().
2319     */
2320    syn Indices InstAccess.combinedIndices() = Indices.createFromFas(combinedFArraySubscripts());
2321
2322        /**
2323         * Get the set of all array indices of an instance primitive component.
2324         *
2325         * @return An Indices object containing all indices in each array dimension.
2326         */
2327        syn lazy Indices InstAssignable.indices() = Indices.create(size());
2328
2329        /**
2330         * Get the set of all array indices of an FVariable.
2331         *
2332         * @return An Indices object containing all indices in each array dimension.
2333         */
2334    syn lazy Indices FAbstractVariable.indices() = Indices.create(size());
2335
2336        /**
2337         * Get the set of all array indices of an InstComponentDecl.
2338         *
2339         * @return An Indices object containing all indices in each array dimension.
2340         */
2341        syn lazy Indices InstComponentDecl.indices() = Indices.create(size());
2342       
2343        /**
2344         * Get the set of all array indices of an array access.
2345         *
2346         * @return An Indices object containing all indices in each array dimension.
2347         */
2348        syn Indices FEquation.indices() = getLeft().indices();
2349       
2350        /**
2351         * Get the set of all indices this array subscript spans.
2352         *
2353         * @return an int array containing the indices spanned
2354         */
2355        syn int[] FSubscript.myIndices();
2356       
2357        eq FColonSubscript.myIndices() {
2358                int n = size().get(0);
2359                if (n < 0)
2360                        return new int[0];
2361                int[] ind = new int[n];
2362                for (int i = 0; i < n; i++)
2363                        ind[i] = i + 1;
2364                return ind;
2365        }
2366       
2367        eq FExpSubscript.myIndices()     = getFExp().myIndices();
2368        eq FIntegerSubscript.myIndices() = new int[] { getValue() };
2369   
2370    public int[] IntegerSubscript.myIndices() {
2371        return new int[] {value()}; 
2372    }
2373
2374    syn int[] FExp.myIndices() {
2375        try {
2376            int n = 0;
2377            if (ndims() == 0) {
2378                n = 1;
2379            } else if (ndims() == 1) {
2380                n = size().get(0);
2381            }
2382            if (n > 0) {
2383                CValue arrVal = ceval();
2384                if (!arrVal.isUnknown()) {
2385                    int[] indices = new int[n];
2386                    int j = 0;
2387                    for (CValue val : arrVal) {
2388                        if (!val.hasIntValue()) {
2389                            return new int[0];
2390                        }
2391                        indices[j++] = val.intValue();
2392                    }
2393                    return indices;
2394                }
2395            }
2396        } catch (ConstantEvaluationException e) {
2397        }
2398        return new int[0];
2399    }
2400
2401    /**
2402     * Get the set of all values this for index spans.
2403     *
2404     * @return an int array containing the values spanned
2405     */
2406    syn int[] CommonForIndex.myIndices() = getFExp().myIndices();
2407    eq InstForIndexNoExp.myIndices()     = hasFExp() ? getFExp().myIndices() : new int[0];
2408
2409        /**
2410         * Try to infer type of an expression from its surrounding Array.
2411         *
2412         * An FExp that is the direct child of an Array always has the same type as the Array, except scalar.
2413         *
2414         * @return  if this expression is in an Array, the inferred type, otherwise type()
2415         */
2416        syn FType FExp.inferType() = inArray() ? inferredType() : type();
2417       
2418        /**
2419         * Check if this expression is the direct child of an Array.
2420         */
2421        inh boolean FExp.inArray();
2422        inh boolean List.inArray();
2423        eq List.getChild().inArray()    = inArray();
2424        eq Array.getChild().inArray()   = true;
2425        eq ASTNode.getChild().inArray() = false;
2426       
2427        /**
2428         * Helper attribute to {@link FExp#inferType()}.
2429         */
2430        inh FType FExp.inferredType();
2431        inh FType List.inferredType();
2432        eq List.getChild().inferredType()    = inferredType();
2433        eq Array.getChild().inferredType()   = type().scalarType();
2434        eq ASTNode.getChild().inferredType() = null;
2435
2436        /**
2437         * The type of the expression this ArrayExp belongs to.
2438         */
2439        inh FType ArrayExp.type();
2440        eq FAbstractArrayExp.getArrayExp().type()             = type();
2441
2442}
2443
2444aspect ArrayHelpers {
2445       
2446        /**
2447         * An array size. Can be multi-dimensional.
2448         */
2449        public class Size {
2450               
2451                /**
2452                 * Used for unknown lengths.
2453                 */
2454                public static final int UNKNOWN = -1;
2455               
2456                /**
2457                 * Used to represent the size of scalar expressions.
2458                 */
2459                public static final Size SCALAR = new Size();
2460               
2461                protected int[] size;
2462               
2463                /**
2464                 * Private constructor that creates a scalar size.
2465                 */
2466                private Size() {
2467                        size = new int[0];
2468                }
2469
2470        /**
2471         * Constructs a Size with the given lengths.
2472         */
2473        public Size(int... size) {
2474            if (size.length == 0)
2475                throw new IllegalArgumentException(
2476                        "Can't create 0-dimensional Size object, use Size.SCALAR instead.");
2477            this.size = size;
2478        }
2479
2480                /**
2481                 * Get the number of dimensions.
2482                 */
2483                public int ndims() {
2484                        return size.length;
2485                }
2486               
2487                /**
2488                 * Get length in the <code>i</code>th dimension.
2489                 */
2490                public int get(int i) {
2491                        return has(i) ? size[i] : UNKNOWN;
2492                }
2493               
2494                /**
2495                 * Get length in the last dimension.
2496                 */
2497                public int last() {
2498                        return get(size.length - 1);
2499                }
2500               
2501                /**
2502                 * Check if this size has an <code>i</code>th dimension.
2503                 */
2504                public boolean has(int i) {
2505                        return i >= 0 && i < size.length;
2506                }
2507
2508        /**
2509         * Returns the number of elements spanned by this Size.
2510         *
2511         * Only valid if all dimensions are known or currently evaluable.
2512         */
2513        public int numElements() {
2514            return numElements(0);
2515        }
2516
2517        /**
2518         * Returns the number of elements spanned by all but the <code>n</code> outermost
2519         * dimensions of this Size.
2520         *
2521         * Only valid if all used dimensions are known or currently evaluable.
2522         */
2523        public int numElements(int n) {
2524            int res = 1;
2525            for (int i = n; i < size.length && res > 0; i++)
2526                res *= get(i);
2527            return res < 0 ? 0 : res;
2528        }
2529
2530        /**
2531         * True if any dimension is verified to be zero
2532         */
2533        public boolean isZero() {
2534            return !isUnknown() && numElements() == 0;
2535        }
2536               
2537                /**
2538                 * Create a new FArraySubscripts object with ranges spanning this size.
2539                 */
2540                public FArraySubscripts rangeFArraySubscripts() {
2541                        FArrayExpSubscripts fas = new FArrayExpSubscripts();
2542                        for (int i = 0; i < size.length; i++)
2543                                fas.addFSubscript(rangeFSubscript(i));
2544                        return fas;
2545                }
2546
2547        /**
2548         * Create a new FSubscript for dimension <code>i</code>.
2549         */
2550        public FSubscript rangeFSubscript(int i) {
2551            return size[i] == UNKNOWN ? new FColonSubscript() : new FExpSubscript(new FRangeExp(1, size[i]));
2552        }
2553
2554                /**
2555                 * Check if any lengths are unknown.
2556                 */
2557                public boolean isUnknown() {
2558                        for (int s : size)
2559                                if (s == UNKNOWN)
2560                                        return true;
2561                        return false;
2562                }
2563                public boolean isUnknownNoEval() {
2564                    return isUnknown();
2565                }
2566       
2567        /**
2568         * Check if length in dimension d is unknown.
2569         */
2570        public boolean isUnknown(int d) {
2571            return !has(d) || size[d] == UNKNOWN;
2572        }
2573       
2574                /**
2575                 * Check if all lengths have a value (fix length or expression).
2576                 */
2577                public boolean isComplete() {
2578                        for (int i = 0; i < size.length; i++)
2579                                if (!hasValue(i))
2580                                        return false;
2581                        return true;
2582                }
2583               
2584                /**
2585                 * Check is the length in any dimension equals 0.
2586                 */
2587                public boolean isEmpty() {
2588                        for (int i = 0; i < size.length; i++)
2589                                if (read(i) == 0)
2590                                        return true;
2591                        return false;
2592                }
2593               
2594                /**
2595                 * Check if a given index fits within this size.
2596                 *
2597                 * Unknown lengths are assumed to be long enough.
2598                 */
2599                public boolean isOKIndex(Index i) {
2600                        int[] ind = i.index();
2601                        if (size.length != ind.length)
2602                                return false;
2603                        for (int j = 0; j < size.length; j++) {
2604                                int a = ind[j];
2605                                int b = get(j);
2606                                if (a < 1 || (a > b && b != UNKNOWN))
2607                                        return false;
2608                        }
2609                        return true;
2610                }
2611               
2612                /**
2613                 * Check if the lengths in the given dimension has a value (fix length or integer).
2614                 */
2615                protected boolean hasValue(int dim) {
2616                        return size[dim] != UNKNOWN;
2617                }
2618               
2619                /**
2620                 * Create a copy of this size.
2621                 */
2622                protected Size clone() {
2623                        return (size.length == 0) ? SCALAR : new Size(size.clone());
2624                }
2625               
2626                /**
2627                 * Create a copy of this size as a MutableSize.
2628                 */
2629                public MutableSize mutableClone() {
2630                        MutableSize ms = new MutableSize(size.length);
2631                        System.arraycopy(size, 0, ms.size, 0, size.length);
2632                        return ms;
2633                }
2634               
2635                /**
2636                 * Create a copy of this with <code>dim</code> dimensions, if necessary
2637                 *        adding dimensions of length 1 to the right side, or removing dimensions
2638                 *        from the left side.
2639                 */
2640                public Size promote(int dim) {
2641                        if (dim == size.length) 
2642                                return this;
2643                        if (dim == 0)
2644                                return SCALAR;
2645                        Size ns = new Size(new int[dim]);
2646                        int old = dim < size.length ? dim : size.length;
2647                        System.arraycopy(size, size.length - old, ns.size, 0, old);
2648                        Arrays.fill(ns.size, old, dim, 1);
2649                        return ns;
2650                }
2651               
2652                /**
2653                 * If this size contains any dimensions that are represented with expressions, then creates
2654                 * and attempts to evaluate a copy of this size. Otherwise, return this.
2655                 */
2656                public Size evaluated() {
2657                    return this;
2658                }
2659               
2660                /**
2661                 * Return a Size that has the same lengths as this size where they are known,
2662                 *        and any that are unknown copied from the size of <code>exp</code>.
2663                 *
2664                 * If the size of <code>exp</code> has more dimensions, the last part is assumed to match this size.
2665                 */
2666                public Size createKnown(FExp exp) {
2667                        Size known;
2668                        if (!exp.size().isUnknown() || this instanceof MutableSize) { 
2669                                known = clone();
2670                        } else {
2671                                known = new MutableSize(size.length);
2672                                System.arraycopy(size, 0, known.size, 0, size.length);
2673                        }
2674                        known.fillUnknownFrom(exp);
2675                        return known;
2676                }
2677               
2678                /**
2679                 * Return a Size that have the same lengths as this size where they are known,
2680                 * and any that are unknown in this size but known in <code>s</code> is copied from there.
2681                 */
2682                public Size createKnown(Size s) {
2683                        Size known = clone();
2684                        for (int i = 0; i < size.length; i++)
2685                                if (known.size[i] == UNKNOWN && s.size[i] != UNKNOWN)
2686                                        known.set(i, s.size[i]);
2687                        return known;
2688                }
2689               
2690                /**
2691                 * Sets length <code>i</code> to <code>s</code>.
2692                 */
2693                protected void set(int i, int s) {
2694                        size[i] = s;
2695                }
2696               
2697                /**
2698                 * For each unknown length, copy the equivalent length from size of <code>exp</code>.
2699                 *
2700                 * If the size of <code>exp</code> have more dimensions than this, the last part is ignored.
2701                 */
2702                protected void fillUnknownFrom(FExp exp) {
2703                        Size other = exp.size();
2704                        if (other.size.length >= size.length)
2705                                for (int i = 0; i < size.length; i++) 
2706                                        if (!hasValue(i))
2707                                                copyFrom(i, exp, i);
2708                }
2709               
2710                /**
2711                 * Copy value of dimension <code>d2</code> in <code>other</code> to dimension
2712                 *        <code>d1</code> in <code>this</code>.
2713                 */
2714                protected void copyFrom(int d1, FExp exp, int d2) {
2715                        size[d1] = exp.size().size[d2];
2716                }
2717               
2718                /**
2719                 * Check if another object is equal to this one.
2720                 */
2721                public boolean equals(Object s) {
2722                        return s instanceof Size && equivalent((Size) s, false);
2723                }
2724               
2725                /**
2726                 * Calculate hash code.
2727                 */
2728                public int hashCode() {
2729                        int res = 0;
2730                        for (int i = 0; i < size.length; i++)
2731                                res = (res << 8) ^ size[i];
2732                        return res;
2733                }
2734               
2735                /**
2736                 * Check if another size is equivalent to this one.
2737                 *
2738                 * @param allowUnknown  if <code>true</code>, consider unknown lengths equal to any length,
2739                 *                      otherwise consider unknown lengths to differ from all lengths, including
2740                 *                      other unknown lengths
2741                 */
2742                public boolean equivalent(Size s, boolean allowUnknown) {
2743                        return equivalentExcept(s, allowUnknown, -1);
2744                }
2745               
2746                /**
2747                 * Check if another size is equivalent to this one, except in a given dimension.
2748                 *
2749                 * @param allowUnknown  if <code>true</code>, consider unknown lengths equal to any length
2750                 * @param dim                   dimension not to check
2751                 */
2752                public boolean equivalentExcept(Size s, boolean allowUnknown, int dim) {
2753                        if (size.length != s.size.length)
2754                                return false;
2755                        for (int i = 0; i < size.length; i++) 
2756                                if (i != dim && !equivalentDim(s, allowUnknown, i, i)) 
2757                                        return false;
2758                        return true;
2759                }
2760               
2761                /**
2762                 * Check if a specific dimension of another size is equivalent to a specific
2763                 *        dimension of this one.
2764                 *
2765                 * @param allowUnknown  if <code>true</code>, consider unknown lengths equal to any length
2766                 * @param myDim         the dimension in this Size to compare
2767                 * @param itsDim        the dimension in the other Size to compare
2768                 */
2769                public boolean equivalentDim(Size s, boolean allowUnknown, int myDim, int itsDim) {
2770                        int myLen = read(myDim);
2771                        int itsLen = s.read(itsDim);
2772                        boolean same = myLen == itsLen;
2773                        if (same || !allowUnknown)
2774                                return same;
2775                        return myLen == UNKNOWN || itsLen == UNKNOWN;
2776                }
2777               
2778                /**
2779                 * Make sure that size is final, then get value of size[i].
2780                 */
2781                protected int read(int i) {
2782                        return size[i];
2783                }
2784               
2785                private static final String SEP = ", ";
2786               
2787                /**
2788                 * Returns a string representation on the form "[l1, l2, l3]".
2789                 */
2790                public String toString() {
2791                        if (size.length == 0)
2792                                return "scalar";
2793                        StringBuilder buf = new StringBuilder("[");
2794                        String prefix = "";
2795                        for (int i = 0; i < size.length; i++) {
2796                                buf.append(prefix);
2797                                buf.append(toString(i));
2798                                prefix = SEP;
2799                        }
2800                        buf.append("]");
2801                        return buf.toString();
2802                }
2803               
2804                /**
2805                 * Returns a string representation of a single length.
2806                 */
2807                protected String toString(int i) {
2808                        return (size[i] == UNKNOWN) ? ":" : Integer.toString(size[i]);
2809                }
2810               
2811                /**
2812                 * Returns a string representation on the form "l1, l2, l3".
2813                 */
2814                public String toUnclosedString() {
2815                        String tmp = toString();
2816                        return tmp.substring(1, tmp.length() - 1);
2817                }
2818
2819        /**
2820         * Creates a new Size that is a copy of this one, but with dimensions removed
2821         * from each side. If nothing is changed, <code>this</code> is returned.
2822         *
2823         * @param left   the number of dimensions to remove from the left side
2824         * @param right  the number of dimensions to remove from the right side
2825         */
2826        public Size contract(int left, int right) {
2827            int ndims = size.length - left - right;
2828            if (ndims == size.length)
2829                return this;
2830            if (ndims <= 0)
2831                return Size.SCALAR;
2832            int[] ns = new int[ndims];
2833            System.arraycopy(size, left, ns, 0, ndims);
2834            return new Size(ns);
2835        }
2836
2837                /**
2838                 * Creates a new Size that is a copy of this one, but with dimensions removed
2839                 * from the left side. If nothing is changed, <code>this</code> is returned.
2840                 *
2841                 * @param n   the number of dimensions of the new size
2842                 */
2843                public Size contractLeft(int n) {
2844                        return contract(size.length - n, 0);
2845                }
2846               
2847                /**
2848                 * Creates a new Size that is a copy of this one, but with dimensions removed
2849                 * from the right side. If nothing is changed, <code>this</code> is returned.
2850                 *
2851                 * @param n   the number of dimensions of the new size
2852                 */
2853                public Size contractRight(int n) {
2854                        return contract(0, size.length - n);
2855                }
2856               
2857                /**
2858                 * Creates a new Size that is a copy of this one, but with one more dimension
2859                 * on the left side.
2860                 *
2861                 * @param s  the length of the new dimension
2862                 */
2863                public Size expand(int s) {
2864                        int[] ns = new int[size.length + 1];
2865                        ns[0] = s;
2866                        System.arraycopy(size, 0, ns, 1, size.length);
2867                        return new Size(ns);
2868                }
2869               
2870        /**
2871         * Creates a new Size that is a copy of this one, but with one more dimension
2872         * on the right side.
2873         *
2874         * @param s  the length of the new dimension
2875         */
2876        public Size expandRight(int s) {
2877            int[] ns = new int[size.length + 1];
2878            System.arraycopy(size, 0, ns, 0, size.length);
2879            ns[size.length] = s;
2880            return new Size(ns);
2881        }
2882
2883        /**
2884         * Creates a new Size that is a concatenation of <code>s</code> and this size.
2885         *
2886         * <code>s</code> is added on the left side.
2887         */
2888        public Size expand(Size s) {
2889            return s.createExpanded(s, this);
2890        }
2891
2892        /**
2893         * Creates a new Size that is a concatenation of this size and <code>s</code>.
2894         *
2895         * <code>s</code> is added on the right side.
2896         */
2897        public Size expandRight(Size s) {
2898            return s.createExpanded(this, s);
2899        }
2900
2901        /**
2902         * Delegate method for expand(Size) and expandRight(Size).
2903         *
2904         * Creates a new size that is the concatenation of a and b.
2905         */
2906        protected Size createExpanded(Size a, Size b) {
2907            int ndims = a.size.length + b.size.length;
2908            if (ndims == 0)
2909                return Size.SCALAR;
2910            int[] ns = new int[ndims];
2911            System.arraycopy(a.size, 0, ns, 0, a.size.length);
2912            System.arraycopy(b.size, 0, ns, a.size.length, b.size.length);
2913            return new Size(ns);
2914        }
2915       
2916        /**
2917         * Create an FArraySubscripts that defines this size as used in variable declarations.
2918         *
2919         * Dimension that nothing is known about get an FColonSubscript.
2920         */
2921        public FArraySubscripts createFArraySubscripts() {
2922            return FArraySubscripts.createFArraySubscripts(createFArraySubscriptsList());
2923        }
2924       
2925        public FArraySubscripts createFArrayExpSubscripts() {
2926            return new FArrayExpSubscripts(createFArraySubscriptsList());
2927        }
2928       
2929        private List<FSubscript> createFArraySubscriptsList() {
2930            List<FSubscript> list = new List<FSubscript>();
2931            for (int i = 0; i < ndims(); i++) {
2932                list.add(createFSubscript(i));
2933            }
2934            return list;
2935        }
2936       
2937        /**
2938         * Create an FSubscript that defines the length of dimension <code>d</code>.
2939         *
2940         * If nothing is known of the length of the dimension, an FColonSubscript is created.
2941         */
2942        public FSubscript createFSubscript(int d) {
2943            return hasValue(d) ? createFExp(d).createFSubscript() : new FColonSubscript();
2944        }
2945               
2946                /**
2947                 * Create an FArraySubscripts that spans this size.
2948                 *
2949                 * Dimension that nothing is known about get an FColonSubscript.
2950                 */
2951                public FArraySubscripts createExpandedFArraySubscripts() {
2952            List<FSubscript> list = new List<FSubscript>();
2953            for (int i = 0; i < ndims(); i++) {
2954                list.add(createExpandedFSubscript(i));
2955                        }
2956                        return FArraySubscripts.createFArraySubscripts(list);
2957                }
2958
2959        /**
2960         * Create an FSubscript that spans the length of dimension <code>d</code>.
2961         *
2962         * If nothing is known of the length of the dimension, an FColonSubscript is created.
2963         */
2964        public FSubscript createExpandedFSubscript(int d) {
2965            if (!isUnknown(d)) {
2966                return createRangeExp(d).createFSubscript();
2967            } else {
2968                return new FColonSubscript();
2969            }
2970        }
2971
2972        /**
2973         * Create a range expression spanning this size.
2974         */
2975        public FRangeExp createRangeExp(int d) {
2976            List<FExp> lim = new List<FExp>();
2977            lim.add(new FIntegerLitExp(1));
2978            lim.add(createFExp(d));
2979            return new FRangeExp(lim);
2980        }
2981
2982                /**
2983                 * Create an FExp that describes this size.
2984                 *
2985                 * The resulting expression is not expanded like createSizeFExp().
2986                 */
2987                public FExp createFExp() {
2988                        List<FExp> cells = new List<FExp>();
2989                        for (int i = 0; i < size.length; i++)
2990                                cells.add(createFExp(i));
2991                        return new FArray(cells);
2992                }
2993               
2994                /**
2995                 * Create an FExp that describes the length of dimension <code>d</code>.
2996                 *
2997                 * The resulting expression is not expanded like createSizeFExp().
2998                 */
2999                public FExp createFExp(int d) {
3000                        return new FIntegerLitExp(size[d]);
3001                }
3002               
3003        public FExp createFExpForced(int d) {
3004            return createFExp(d);
3005        }
3006               
3007                /**
3008                 * Create an FExp that describes the number of elements of this size.
3009                 */
3010                public FExp createNumElementsFExp() {
3011                        return new FIntegerLitExp(numElements());
3012                }
3013
3014        /**
3015         * Create a zero expression of this size.
3016         */
3017        public FExp createZeroFExp() {
3018            if (size.length == 0) {
3019                return new FIntegerLitExp(0);
3020            } else {
3021                return fillDimsOfExp(new FZeros());
3022            }
3023        }
3024
3025        /**
3026         * Add dimensions to an FArrayDimAsArgsExp so that it will have this size
3027         * (assuming a scalar expression for fill).
3028         */
3029        public FArrayDimAsArgsExp fillDimsOfExp(FArrayDimAsArgsExp exp) {
3030            for (int i = 0; i < size.length; i++)
3031                exp.addFExp(createFExp(i));
3032            return exp;
3033        }
3034        }
3035       
3036        /**
3037         * A mutable Size that can handle FExp sizes, possibly with unknown ceval().
3038         */
3039        public class MutableSize extends Size {
3040               
3041                private int i;
3042                private FExp[] exps;
3043                private boolean[] evaluated;
3044               
3045                /**
3046                 * Constructs a new mutable Size of <code>ndims</code> dimensions.
3047                 */
3048                public MutableSize(int ndims) {
3049                        super(new int[ndims]);
3050                        Arrays.fill(size, UNKNOWN);
3051                        exps = new FExp[ndims];
3052                        i = 0;
3053                        evaluated = new boolean[ndims];
3054                }
3055               
3056                /**
3057                 * Constructs the size described by a vector expression.
3058                 */
3059                public MutableSize(FExp exp) {
3060                        this(exp.ndims() == 1 ? exp.size().get(0) : 0);
3061                        for (FExp dim : exp.getArray().iterable())
3062                                append(dim);
3063                }
3064               
3065                /**
3066                 * Sets the next length to <code>s</code>.
3067                 *
3068                 * May overwrite lengths set with <code>set()</code>.
3069                 */
3070                public void append(int s) {
3071                        set(i++, s);
3072                }
3073               
3074                /**
3075                 * Sets the next length to the value of <code>e</code>.
3076                 *
3077                 * May overwrite lengths set with <code>set()</code>.
3078                 */
3079                public void append(FExp e) {
3080                        set(i++, e);
3081                }
3082               
3083                /**
3084                 * Sets the next length to the length of dimension <code>d</code>
3085                 *        of <code>s</code>.
3086                 *
3087                 * May overwrite lengths set with <code>set()</code>.
3088                 */
3089                public void append(Size s, int d) {
3090                        set(i++, s, d);
3091                }
3092               
3093                /**
3094                 * Sets the next <code>s.ndims()</code> lengths from <code>s</code>.
3095                 *
3096                 * May overwrite lengths set with <code>set()</code>.
3097                 */
3098                public void append(Size s) {
3099                        if (s instanceof MutableSize) {
3100                                MutableSize ms = (MutableSize) s;
3101                                for (int j = 0; j < ms.size.length; j++, i++) {
3102                                        exps[i] = ms.exps[j];
3103                                        size[i] = ms.size[j];
3104                                }
3105                        } else {
3106                                for (int si : s.size) {
3107                                        size[i++] = si;
3108                                }
3109                        }
3110                }
3111               
3112                /**
3113                 * Sets length <code>i</code> to <code>s</code>.
3114                 */
3115                public void set(int i, int s) {
3116                        size[i] = s;
3117                }
3118
3119        /**
3120         * Sets length <code>d</code> to the value of <code>e</code>.
3121         */
3122        public void set(int d, FExp e) {
3123            int s = UNKNOWN;
3124            if (okExp(e) && e.hasOnlyLiterals()) {
3125                try {
3126                    CValue val = e.ceval();
3127                    if (val.hasIntValue()) {
3128                        s = val.intValue();
3129                    }
3130                } catch (ConstantEvaluationException cee) {
3131                }
3132            }
3133            size[d] = s;
3134            exps[d] = (s == UNKNOWN) ? e : null;
3135        }
3136
3137        /**
3138         * Sets length <code>d1</code> to the length of dimension <code>d2</code>
3139         *        of <code>s</code>.
3140         *
3141         * May overwrite lengths set with <code>set()</code>.
3142         */
3143        public void set(int d1, Size s, int d2) {
3144            if (d2 >= s.size.length) {
3145                size[d1] = -1;
3146                exps[d1] = null;
3147            } else {
3148                size[d1] = s.size[d2];
3149                exps[d1] = (s instanceof MutableSize) ? ((MutableSize) s).exps[d2] : null;
3150            }
3151        }
3152
3153        /**
3154         * Make sure dimension i of size is ready to use.
3155         */
3156        private void evaluate(int i) {
3157            if (i >= 0 && i < evaluated.length && !evaluated[i]) {
3158                evaluated[i] = true;
3159                if (exps[i] != null) {
3160                    try {
3161                        CValue val = exps[i].ceval();
3162                        if (val.hasIntValue()) {
3163                            size[i] = val.intValue();
3164                        }
3165                    } catch (ConstantEvaluationException e) {
3166                    }
3167                }
3168            }
3169        }
3170
3171                /**
3172                 * Make sure size is ready to use.
3173                 */
3174                private void evaluate() {
3175                        for (int i = 0; i < size.length; i++) 
3176                                evaluate(i);
3177                }
3178               
3179                /**
3180                 * Adds <code>s</code> to length <code>d</code>.
3181                 */
3182                public void add(int d, int s) {
3183            if (size[d] == Size.UNKNOWN || s == Size.UNKNOWN) {
3184                size[d] = Size.UNKNOWN;
3185            } else {
3186                size[d] = size[d] + s;
3187            }
3188        }
3189
3190        /**
3191         * Adds the value of <code>e</code> to length <code>d</code>.
3192         */
3193        public void add(int d, FExp e) {
3194            boolean ok = false;
3195            try {
3196                CValue val = e.ceval();
3197                if (val.hasIntValue()) {
3198                    add(d, val.intValue());
3199                    ok = true;
3200                }
3201            } catch (ConstantEvaluationException cee) {}
3202            if (!ok) {
3203                FExp e2 = new FAddExp(createFExp(d), e.createSizeFExp());
3204                exps[d] = e.dynamicFExp(e2);
3205                size[d] = UNKNOWN;
3206            }
3207        }
3208
3209                /**
3210                 * Adds the length of dimension <code>d2</code> of <code>s</code>
3211                 *        to length <code>d1</code> of this size.
3212         *
3213         * Adds both expressions and evaluated sizes.
3214                 */
3215                public void add(int d1, Size s, int d2) {
3216            addFExp(d1, s, d2);
3217            add(d1, s.size[d2]);
3218                }
3219               
3220        /**
3221         * If there is an expression in dimension <code>d1</code> of <code>this</code> or
3222         * dimension <code>d2</code> of size <code>s</code>, add the two size representations
3223         * into a new <code>FExp</code> in <code>this</code>.
3224         */
3225        protected void addFExp(int d1, Size s, int d2) {
3226            FExp n = null;
3227            if (hasFExp(d1)) {
3228                n = getFExp(d1);
3229            } else if (s instanceof MutableSize) {
3230                MutableSize ms = (MutableSize) s;
3231                if (ms.hasFExp(d2)) {
3232                    n = ms.getFExp(d2);
3233                }
3234            }
3235           
3236            if (n == null) {
3237                return;
3238            }
3239           
3240            FExp e = new FAddExp(createFExpForced(d1), s.createFExpForced(d2));
3241            exps[d1] = n.dynamicFExp(e);
3242        }
3243       
3244        /**
3245         * Returns true if there is an FExp representing size in
3246         * dimension <code>d</code>, else false.
3247         */
3248        protected boolean hasFExp(int d) {
3249            return exps[d] != null;
3250        }
3251       
3252        /**
3253         * Get the FExp representing size in dimension <code>d</code>.
3254         * It might be null.
3255         */
3256        protected FExp getFExp(int d) {
3257            return exps[d];
3258        }
3259
3260        /**
3261         * Get length in the <code>i</code>th dimension.
3262         */
3263        public int get(int i) {
3264            evaluate(i);
3265            if (i < 0 || i >= size.length)
3266                return UNKNOWN;
3267            if (size[i] != Size.UNKNOWN) // We want to evaluate FColonSizeExps as well
3268                return size[i];
3269            try {
3270                if (exps[i] != null)
3271                    return exps[i].ceval().intValue();
3272            } catch (ConstantEvaluationException e) {
3273            }
3274            return UNKNOWN;
3275        }
3276
3277                /**
3278                 * Check if the lengths in the given dimension has a value (fix length or integer).
3279                 */
3280                protected boolean hasValue(int dim) {
3281            return size[dim] != UNKNOWN || okExp(dim);
3282                }
3283               
3284        /**
3285         * Check if an expression is valid.
3286         */
3287        protected static boolean okExp(FExp e) {
3288            return okExp(e, false);
3289        }
3290       
3291        protected boolean okExp(int i) {
3292            return okExp(i, false);
3293        }
3294       
3295        protected static boolean okExp(FExp e, boolean allowUnknownSize) {
3296            return e != null && e.isValidExp(allowUnknownSize);
3297        }
3298       
3299        protected boolean okExp(int i, boolean allowUnknownSize) {
3300            return size[i] == Size.UNKNOWN && okExp(exps[i], allowUnknownSize);
3301        }
3302               
3303                /**
3304                 * Copy value of dimension <code>d2</code> in size of <code>exp</code> to dimension
3305                 *        <code>d1</code> in <code>this</code>.
3306                 */
3307                protected void copyFrom(int d1, FExp exp, int d2) {
3308                        set(d1, exp.size(), d2);
3309            if (exps[d1] != null && exps[d1] instanceof FColonSizeExp) {
3310                exps[d1] = exp.dynamicFExp(exps[d1].createSizeFExp());
3311            }
3312                        if (!hasValue(d1)) {
3313                                FExp copyExp = exp.fullCopy();
3314                                Opt dimExp = new Opt(new FIntegerLitExp(d2 + 1));
3315                                FSizeExp sizeExp  = new FSizeExp(copyExp, dimExp);
3316                                exps[d1] = exp.dynamicFExp(sizeExp);
3317                        }
3318                }
3319               
3320                /**
3321                 * Creates a new Size that is a copy of this one, but with dimensions removed
3322                 * from each side.
3323                 *
3324                 * @param left   the number of dimensions to remove from the left side
3325                 * @param right  the number of dimensions to remove from the right side
3326                 */
3327                public Size contract(int left, int right) {
3328                        int ndims = size.length - left - right;
3329                        if (ndims == 0)
3330                                return Size.SCALAR;
3331                        MutableSize ns = new MutableSize(ndims);
3332                        System.arraycopy(size, left, ns.size, 0, ndims);
3333                        System.arraycopy(exps, left, ns.exps, 0, ndims);
3334                        return ns;
3335                }
3336               
3337                /**
3338                 * Creates a new Size that is a copy of this one, but with one more dimension
3339                 * on the left side.
3340                 *
3341                 * @param s  the length of the new dimension
3342                 */
3343                public Size expand(int s) {
3344                        evaluate();
3345                        MutableSize ns = new MutableSize(size.length + 1);
3346                        ns.size[0] = s;
3347                        ns.exps[0] = null;
3348                        System.arraycopy(size, 0, ns.size, 1, size.length);
3349                        System.arraycopy(exps, 0, ns.exps, 1, size.length);
3350                        return ns;
3351                }
3352
3353        /**
3354         * Creates a new Size that is a concatenation of <code>s</code> and this size.
3355         *
3356         * <code>s</code> is added on the left side.
3357         */
3358        public Size expand(Size s) {
3359            return createExpanded(s, this);
3360        }
3361
3362        /**
3363         * Creates a new Size that is a concatenation of this size and <code>s</code>.
3364         *
3365         * <code>s</code> is added on the right side.
3366         */
3367        public Size expandRight(Size s) {
3368            return createExpanded(this, s);
3369        }
3370
3371        /**
3372         * Delegate method for expand(Size) and expandRight(Size). Creates a new size that is the concatenation of a and b.
3373         */
3374        protected Size createExpanded(Size a, Size b) {
3375            int ndims = a.size.length + b.size.length;
3376            if (ndims == 0)
3377                return Size.SCALAR;
3378            MutableSize ns = new MutableSize(ndims);
3379            if (a instanceof MutableSize) {
3380                MutableSize m = (MutableSize) a;
3381                m.evaluate();
3382                System.arraycopy(m.exps, 0, ns.exps, 0, m.size.length);
3383            }
3384            if (b instanceof MutableSize) {
3385                MutableSize m = (MutableSize) b;
3386                m.evaluate();
3387                System.arraycopy(m.exps, 0, ns.exps, a.size.length, m.size.length);
3388            }
3389            System.arraycopy(a.size, 0, ns.size, 0, a.size.length);
3390            System.arraycopy(b.size, 0, ns.size, a.size.length, b.size.length);
3391            return ns;
3392        }
3393       
3394                /**
3395                 * Create an FExp that describes the length of dimension <code>d</code>.
3396                 *
3397                 * the resulting expression is not expanded like createSizeFExp().
3398                 */
3399                public FExp createFExp(int d) {
3400                        evaluate(d);
3401            return (okExp(d, true)) ?
3402                                        exps[d].createSizeFExp() : 
3403                                        super.createFExp(d);
3404                }
3405       
3406        /**
3407         * Create an FExp that describes the length of dimension <code>d</code>.
3408         *
3409         * Uses the FExp even if there is an evaluated size.
3410         */
3411        public FExp createFExpForced(int d) {
3412            return (hasFExp(d)) ?
3413                    getFExp(d).createSizeFExp() : 
3414                    super.createFExpForced(d);
3415        }
3416       
3417                /**
3418                 * Create an FExp that describes the number of elements of this size.
3419                 */
3420                public FExp createNumElementsFExp() {
3421                        evaluate();
3422                        int known = 1;
3423                        FExp res = null;
3424                        for (int i = 0; i < size.length; i++) {
3425                                // TODO: this will fail if hasValue(i) == false
3426                                if (size[i] == UNKNOWN) {
3427                                        FExp e = exps[i].unboundCopy();
3428                                        res = (res == null) ? e : new FMulExp(res, e);
3429                                } else {
3430                                        known *= size[i];
3431                                }
3432                        }
3433                        if (res == null)
3434                                res = new FIntegerLitExp(known);
3435                        else if (known > 1)
3436                                res = new FMulExp(res, new FIntegerLitExp(known));
3437                        return res;
3438                }
3439
3440                /**
3441         * If this size contains any dimensions that are represented with expressions, then creates
3442         * and attempts to evaluate a copy of this size. Otherwise, return this.
3443         */
3444        public Size evaluated() {
3445            boolean copy = false;
3446            for (FExp e : exps) {
3447                if (e != null) {
3448                    copy = true;
3449                    break;
3450                }
3451            }
3452            if (copy) {
3453                MutableSize res = new MutableSize(size.length);
3454                System.arraycopy(size, 0, res.size, 0, size.length);
3455                System.arraycopy(exps, 0, res.exps, 0, exps.length);
3456                res.evaluate();
3457                return res;
3458            } else {
3459                return this;
3460            }
3461        }
3462       
3463        /**
3464         * Create a new FSubscript with a range spanning dimension <code>i</code>.
3465         */
3466        public FSubscript rangeFSubscript(int i) {
3467            evaluate(i);
3468            return !okExp(i) ? super.rangeFSubscript(i) : 
3469                new FExpSubscript(new FRangeExp(new FIntegerLitExp(1), exps[i].fullCopy()));
3470        }
3471
3472                /**
3473                 * Returns a string representation of a single length.
3474                 */
3475                protected String toString(int i) {
3476                        evaluate(i);
3477            return !okExp(i) ? super.toString(i) : exps[i].prettyPrint("");
3478                }
3479               
3480                /**
3481                 * Create a copy of this size.
3482                 */
3483                protected MutableSize clone() {
3484                        MutableSize ms = new MutableSize(size.length);
3485                        System.arraycopy(size, 0, ms.size, 0, size.length);
3486                        System.arraycopy(exps, 0, ms.exps, 0, exps.length);
3487                        ms.evaluated = evaluated;
3488                        return ms;
3489                }
3490               
3491                /**
3492                 * Create a copy of this size as a MutableSize.
3493                 */
3494                public MutableSize mutableClone() {
3495                        return clone();
3496                }
3497               
3498                /**
3499                 * Create a copy of this with <code>dim</code> dimensions, if necessary
3500                 *        adding dimensions of length 1 to the right side, or removing dimensions
3501                 *        from the left side.
3502                 */
3503                public Size promote(int dim) {
3504                        evaluate();
3505                        if (dim == size.length) 
3506                                return this;
3507                        if (dim == 0)
3508                                return SCALAR;
3509                        MutableSize ns = new MutableSize(dim);
3510                        int old = dim < size.length ? dim : size.length;
3511                        System.arraycopy(size, size.length - old, ns.size, 0, old);
3512                        System.arraycopy(exps, exps.length - old, ns.exps, 0, old);
3513                        Arrays.fill(ns.size, old, dim, 1);
3514                        return ns;
3515                }
3516               
3517                /**
3518                 * Make sure that size is final, then get value of size[i].
3519                 */
3520                protected int read(int i) {
3521                        evaluate(i);
3522                        return size[i];
3523                }
3524               
3525                public boolean isUnknown() {
3526                        evaluate();
3527                        return super.isUnknown();
3528                }
3529               
3530        @Override
3531        public boolean isUnknownNoEval() {
3532            return super.isUnknown();
3533        }
3534               
3535        }
3536   
3537    public interface Array {
3538        /**
3539         * Creates an iterator that iterates over all FExp nodes in this Array.
3540         */
3541        public Iterator<FExp> iteratorFExp();
3542       
3543        /**
3544         * Returns an Iterable<FExp> containing all expressions in Array.
3545         */
3546        public Iterable<FExp> iterable();
3547       
3548        /**
3549         * Creates a left-hand iterator for multiplication.
3550         *
3551         * Creates an iterator that iterates over all FExp nodes involved in
3552         * calculating the cell i in a multiplication with this Array at the
3553         * left side.
3554         */
3555        public Iterator<FExp> leftMulIterator(Index i);
3556       
3557        /**
3558         * Creates a right-hand iterator for multiplication.
3559         *
3560         * Creates an iterator that iterates over all FExp nodes involved in
3561         * calculating the cell i in a multiplication with this Array at the
3562         * right side.
3563         */
3564        public Iterator<FExp> rightMulIterator(Index i);
3565        public FExp getFExp(int i);
3566        public FExp get(Index i);
3567        public FExp get(int i);
3568        public Indices indices();
3569        public int ndims();
3570        public Size size();
3571       
3572        /**
3573         * Create an FExp describing the part of this array indicated by <code>i</code>.
3574         */
3575        public FExp subArrayFExp(Index i);
3576        public FExp subArrayFExp(Index i, NonConsecutiveIndices indices);
3577        public ASTNode unboundCopy();
3578    }
3579   
3580        public class ArrayExp implements Array {
3581               
3582                protected Indices indices;
3583                protected int length;
3584               
3585                /**
3586                 * Create an ArrayExp spanning a given Indices.
3587                 */
3588                public ArrayExp(Indices indices) {
3589                        this.indices = indices;
3590                        setChild(new List<FExp>(), 0);
3591                        length = indices.numElements();
3592                        if (length > 0)
3593                                setFExp(null, length - 1);
3594                }
3595               
3596                /**
3597                 * Creates an iterator that iterates over all FExp nodes in this Array.
3598                 */
3599                public Iterator<FExp> iteratorFExp() {
3600                        return getFExps().iterator();
3601                }
3602               
3603                /**
3604                 * Returns an Iterable<FExp> containing all expressions in Array.
3605                 */
3606                public Iterable<FExp> iterable() {
3607                        return getFExps();
3608                }
3609               
3610                /**
3611                 * Creates a left-hand iterator for multiplication.
3612                 *
3613                 * Creates an iterator that iterates over all FExp nodes involved in
3614                 * calculating the cell i in a multiplication with this Array at the
3615                 * left side.
3616                 *
3617                 * If this Array is a vector, i is ignored and an iterator that iterates
3618                 * over all elements in the Array is returned.
3619                 *
3620                 * If this Array is a matrix, an iterator that iterates over the row
3621                 * specified by i is returned.
3622                 */
3623                public Iterator<FExp> leftMulIterator(Index i) {
3624                        if (ndims() < 2)
3625                                return new AIterator();
3626                        else
3627                                return createMatrixRowIterator(i.first(), size().get(1));
3628                }
3629               
3630                /**
3631                 * Creates a right-hand iterator for multiplication.
3632                 *
3633                 * Creates an iterator that iterates over all FExp nodes involved in
3634                 * calculating the cell i in a multiplication with this Array at the
3635                 * right side.
3636                 *
3637                 * If this Array is a vector, i is ignored and an iterator that iterates
3638                 * over all elements in the Array is returned.
3639                 *
3640                 * If this Array is a matrix, an iterator that iterates over the column
3641                 * specified by i is returned.
3642                 */
3643                public Iterator<FExp> rightMulIterator(Index i) {
3644                        if (ndims() < 2)
3645                                return new AIterator();
3646                        else
3647                                return createMatrixColIterator(i.last(), size().get(1), size().get(0));
3648                }
3649               
3650                /**
3651                 * Returns the element referenced by <code>i</code> in this Array.
3652                 */
3653                public FExp get(Index i) {
3654                        return getFExp(i.internal(indices));
3655                }
3656               
3657                /**
3658                 * Returns element <code>i</code> in this Array.
3659                 *
3660                 * For vectors, this is equivalent to <code>get(new Index(new int[]{i}))</code>.
3661                 */
3662                public FExp get(int i) {
3663                        return getFExp(i - 1);
3664                }
3665               
3666                /**
3667                 * Sets the element referenced by <code>i</code> in this Array to <code>exp</code>.
3668                 */
3669                public void set(Index i, FExp exp) {
3670                        setFExp(exp.unboundCopy(), i.internal(indices));
3671                }
3672               
3673                /**
3674                 * Returns the Indices associated with this Array.
3675                 */
3676                public Indices indices() {
3677                        return indices;
3678                }
3679               
3680                /**
3681                 * Set all expressions in Array to copies of <code>exp</code>.
3682                 *
3683                 * If <code>exp</code> is an array, it is duplicated as many times as
3684                 * nessecary to fill this Array with scalar expressions.
3685                 *
3686                 * @return <code>this</code>
3687                 */
3688                public ArrayExp fill(FExp exp) {
3689                        if (exp.isArray()) {
3690                                int n = exp.size().numElements();
3691                                for (int i = 0; i < length; i++)
3692                                        setFExp(exp.getArray().getFExp(i % n).fullCopy(), i);
3693                        } else {
3694                                for (int i = 0; i < length; i++)
3695                                        setFExp(exp.fullCopy(), i);
3696                        }
3697                        return this;
3698                }
3699               
3700                /**
3701                 * Returns the number of dimensions spanned by this Array.
3702                 */
3703                public int ndims() {
3704                        return indices.ndims();
3705                }
3706               
3707                /**
3708                 * Returns the size of this Array in each dimension.
3709                 */
3710                public Size size() {
3711                        return indices.size();
3712                }
3713               
3714            /**
3715             * Recursive method for building an FArray describing this Array.
3716             *        For use by methods creating specific types of FArrays.
3717             * 
3718             * @param it       the iterator returned by a call to {@link #iteratorFExp()}
3719             * @param builder  helper object that processes each subexpression
3720             * @param dim      the dimension to start at, use 0 to process entire array
3721             *
3722             * @see #buildScalarized(java.util.Map,FExp)
3723             */
3724        protected FExp buildFArray(Iterator<FExp> it, ElementBuilder builder, int dim) {
3725            return buildFArray(it, builder, dim, size(), null);
3726        }
3727       
3728        protected FExp buildFArray(Iterator<FExp> it, ElementBuilder builder, int dim, Size size, boolean[] b) {
3729            FArray arr = new FArray(new List<FExp>());
3730            int n = size.get(dim);
3731            if (b != null) {
3732                if (dim >= b.length) {
3733                    return builder.build(it.next().unboundCopy());
3734                } else if (!b[dim]) {
3735                    return buildFArray(it, builder, dim + 1, size, b);
3736                }
3737            }
3738            if (dim < size.ndims() - 1) {
3739                for (int i = 0; i < n; i++)
3740                    arr.addFExp(buildFArray(it, builder, dim + 1, size, b));
3741            } else {
3742                for (int i = 0; i < n; i++) 
3743                    arr.addFExp(builder.build(it.next()).unboundCopy());
3744            }
3745            return arr;
3746        }
3747               
3748            /**
3749             * Build an FArray describing this Array.
3750             *        For use by methods creating specific types of FArrays.
3751             * 
3752             * @param builder  helper object that processes each subexpression
3753             *
3754             * @see #buildScalarized(java.util.Map,FExp)
3755             * @see #buildFArray(Iterator,ElementBuilder,int)
3756             */
3757            protected FExp buildFArray(ElementBuilder builder) {
3758                        Size s = size();
3759                        if (s.isEmpty()) {
3760                                List<FExp> dims = new List<FExp>();
3761                                for (int i = 0, n = s.ndims(); i < n ; i++)
3762                                        dims.add(s.createFExp(i));
3763                                return new FFillExp(dims, type().zeroLiteral());
3764                        } else {
3765                        return buildFArray(iteratorFExp(), builder, 0);
3766                        }
3767            }
3768           
3769        protected FExp buildFArray() {
3770            return buildFArray(new IdentityBuilder());
3771        }
3772           
3773            /**
3774             * Create an FExp describing the part of this array indicated by <code>i</code>.
3775             *
3776             * If <code>i</code> has fewer dimensions than this, an FArray is created.
3777             * Otherwise a copy of a specific cell is returned.
3778             */
3779        public FExp subArrayFExp(Index i) {
3780            if (i.ndims() >= ndims())
3781                return get(i).fullCopy();
3782            int start = i.internal(indices);
3783            Iterator<FExp> it = new AIterator(start, 1, length - start);
3784            return buildFArray(it, new IdentityBuilder(), i.ndims());
3785        }
3786           
3787        public FExp subArrayFExp(Index i, NonConsecutiveIndices indices) {
3788            if (i.ndims() >= ndims())
3789                return get(indices.translate(i)).fullCopy();
3790           
3791            boolean[] b = new boolean[ndims()];
3792            indices = indices.locked(i, b);
3793            Iterator<FExp> it = new IndexIterator(indices);
3794            return buildFArray(it, new IdentityBuilder(), 0, indices.size(), b);
3795        }
3796       
3797        public class IndexIterator implements Iterator<FExp> {
3798           
3799           
3800            private Iterator<Index> it;
3801            private Indices indices;
3802           
3803            public IndexIterator(Indices indices) {
3804                this.indices = indices;
3805                this.it = indices.iterator();
3806            }
3807           
3808            @Override
3809            public boolean hasNext() {
3810                return it.hasNext();
3811            }
3812
3813            @Override
3814            public FExp next() {
3815                return get(indices.translate(it.next()));
3816            }
3817
3818            @Override
3819            public void remove() {
3820                throw new UnsupportedOperationException();
3821            }
3822        }
3823               
3824                /**
3825                 * Create an iterator that iterates over a row. Assumes the Array is a matrix.
3826                 */
3827                private AIterator createMatrixRowIterator(int row, int width) {
3828                        return new AIterator((row - 1) * width, 1, width);
3829                }
3830               
3831                /**
3832                 * Create an iterator that iterates over a column. Assumes the Array is a matrix.
3833                 */
3834                private AIterator createMatrixColIterator(int col, int width, int height) {
3835                        return new AIterator(col - 1, width, height);
3836                }
3837
3838               
3839            /**
3840             * Discribes the helper object for {@link #buildFArray(Iterator,ElementBuilder,int)}.
3841             */
3842            protected interface ElementBuilder {
3843                public FExp build(FExp e);
3844            }
3845           
3846            /**
3847             * Builder for buildFArray(), that returns a straight copy of the FExp.
3848             */
3849            public class IdentityBuilder implements ElementBuilder {
3850                public FExp build(FExp exp) {
3851                        return exp.fullCopy();
3852                }
3853            }
3854               
3855           
3856                /**
3857                 * Iterates over FExp nodes in this Array.
3858                 */
3859                private class AIterator implements Iterator<FExp> {
3860                       
3861                        private int i = 0;
3862                        private int s;
3863                        private int l;
3864                        private int n;
3865                       
3866                        /**
3867                         * Create an iterator that iterates over all elements in the Array.
3868                         */
3869                        public AIterator() {
3870                                s = 0;
3871                                l = 1;
3872                                n = length;
3873                        }
3874                       
3875                        /**
3876                         * Create an iterator that iterates over a consecutive strech of the elements
3877                         * in the Array.
3878                         */
3879                        public AIterator(int start, int step, int number) {
3880                                s = start;
3881                                l = step;
3882                                n = number;
3883                        }
3884                       
3885                        public boolean hasNext() {
3886                                return i < n;
3887                        }
3888                       
3889                        public FExp next() {
3890                                if (i >= n)
3891                                        throw new NoSuchElementException();
3892                                return getFExp(s + l * i++);
3893                        }
3894                       
3895                        public void remove() {
3896                                throw new UnsupportedOperationException();
3897                        }
3898                       
3899                }
3900               
3901        }
3902
3903    public class FExp implements Array {
3904       
3905        public Iterator<FExp> iteratorFExp() {
3906            return iterable().iterator();
3907        }
3908        public Iterable<FExp> iterable() {return Collections.singleton(this);}
3909        public Iterator<FExp> leftMulIterator(Index i) {return iteratorFExp();}
3910        public Iterator<FExp> rightMulIterator(Index i) {return iteratorFExp();}
3911       
3912        public FExp getFExp(int i) {
3913            return this;
3914        }
3915       
3916        public FExp get(Index i) {
3917            return this;
3918        }
3919       
3920        public FExp get(int i) {
3921            return this;
3922        }
3923       
3924        public FExp subArrayFExp(Index i) {
3925            return this;
3926        }
3927       
3928        public FExp subArrayFExp(Index i, NonConsecutiveIndices indices) {
3929            return this;
3930        }
3931    }
3932
3933       
3934        /**
3935         * Represents the index/indices of a single cell in an (possibly
3936         *        multi-dimensional) array.
3937         *       
3938         * Index objects are reused to a high degree. Always use fix() when retaining
3939         * an Index object.
3940         */
3941        public class Index {
3942               
3943                public static final Index NULL = new Index(0);
3944               
3945                protected int[] index;
3946               
3947                /**
3948                 * Construct an Index representing the indices given in <code>ind</code>.
3949                 */
3950                public Index(int[] ind) {
3951                        index = ind;
3952                }
3953               
3954                /**
3955                 * Returns the indices that specify this cell.
3956                 */
3957                public int[] index() {
3958                        return index;
3959                }
3960               
3961                /**
3962                 * Returns the number of dimensions of this Index.
3963                 */
3964                public int ndims() {
3965                        return index.length;
3966                }
3967               
3968                /**
3969                 * Returns the index for the first dimension.
3970                 */
3971                public int first() {
3972                        return index.length > 0 ? index[0] : -1;
3973                }
3974               
3975                /**
3976                 * Returns the index for the last dimension.
3977                 */
3978                public int last() {
3979                        return index.length > 0 ? index[index.length - 1] : -1;
3980                }
3981       
3982        /**
3983         * Returns an iterator over the indices for each dimension.
3984         */
3985        public IntIterator iterator() {
3986            return new IntIterator() {
3987                int d = 0;
3988               
3989                public boolean hasNext() { return d < index.length; }
3990               
3991                public int next() { return index[d++]; }
3992            };
3993        }
3994       
3995                /**
3996                 * Returns the index for the <code>i</code>th dimension (zero-based).
3997                 */
3998                public int get(int i) {
3999                        return index[i];
4000                }
4001               
4002                /**
4003                 * Sets the index for the <code>i</code>th dimension (zero-based).
4004                 */
4005                public void set(int i, int index) {
4006                        this.index[i] = index;
4007                }
4008               
4009                /**
4010                 * Compare two Index for equality.
4011                 */
4012                public boolean equals(Object i) {
4013                        return (i instanceof Index) && Arrays.equals(index, ((Index) i).index);
4014                }
4015               
4016                /**
4017                 * Calculate hash code.
4018                 *
4019                 * Creates perfect hash when ndims() <= 3 and all indices are <= 1023.
4020                 */
4021                public int hashCode() {
4022                        int shift = index.length <= 3 ? 10 : 5;
4023                        int res = 0;
4024                        for (int i = 0; i < index.length; i++)
4025                                res = (res << shift) ^ index[i];
4026                        return res;
4027                }
4028               
4029                /**
4030                 * Returns an Index that describes the last <code>ndims() - level</code> dimensions
4031                 * of this Index.
4032                 *
4033                 * @param level  the first index to copy. Must be between 0 and ndims(), inclusive.
4034                 */
4035                public Index subIndex(int level) {
4036                        return partIndex(level, index.length);
4037                }
4038       
4039        /**
4040         * Returns an Index that describes dimensions from <code>i</code>, inclusively,
4041         * to <code>j</code>, excludingly, of this Index.
4042         *
4043         * @param i  the first index to copy. Must be between 0 and ndims(), inclusively.
4044         * @param j  the index after the last to copy. Must be between <code>i</code> and ndims(), inclusively.
4045         */
4046        public Index partIndex(int i, int j) {
4047            if (i == 0 && j == index.length)
4048                return this;
4049            if (i == j)
4050                return Index.NULL;
4051            Index copy = new Index(j - i);
4052            System.arraycopy(index, i, copy.index, 0, copy.index.length);
4053            return copy;
4054        }
4055               
4056                /**
4057                 * Creates a new Index that is a copy of this Index, but promoted to <code>ndims</code>
4058                 * dimensions by adding ones to the end.
4059                 *
4060                 * The new Index will not be bound to any Indices object.
4061                 */
4062                public Index promote(int ndims) {
4063                        return adjusted(0, 0, ndims);
4064                }
4065               
4066                /**
4067                 * Creates a new Index that is a copy of this Index, but with <code>adj</code>
4068                 *        added to dimension <code>dim</code> and promoted to <code>ndims</code>
4069                 *        dimensions by adding ones to the end.
4070                 *
4071                 * The new Index will not be bound to any Indices object.
4072                 */
4073                public Index adjusted(int dim, int adj, int ndims) {
4074                        Index copy = new Index(new int[ndims]);
4075                        System.arraycopy(index, 0, copy.index, 0, index.length);
4076                        Arrays.fill(copy.index, index.length, ndims, 1);
4077                        copy.index[dim] += adj;
4078                        return copy;
4079                }
4080               
4081                /**
4082                 * Create a new FArraySubscripts object describing this index.
4083                 */
4084                public FArraySubscripts createFArraySubscripts() {
4085                        return new FArrayLitSubscripts(index);
4086                }
4087
4088        /**
4089         * Returns an Index that has the same value as this one, but will not be changed by
4090         * an iterator that might have returned this Index. Usually creates a copy.
4091         * Always use fix() when saving an Index.
4092         */
4093        public Index fix() {
4094            if (index.length == 0) {
4095                return Index.NULL;
4096            } else {
4097                return new Index(index.clone());
4098            }
4099        }
4100
4101                /**
4102                 * Returns an Index that is the result of appending <code>i</code> to this Index.
4103                 *
4104                 * @param i  the Index to append.
4105                 */
4106                public Index expand(Index i) {
4107                        if (index.length == 0)
4108                                return i;
4109                        if (i.index.length == 0)
4110                                return this;
4111                        Index expanded = new Index(index.length + i.index.length);
4112                        System.arraycopy(index, 0, expanded.index, 0, index.length);
4113                        System.arraycopy(i.index, 0, expanded.index, index.length, i.index.length);
4114                        return expanded;
4115                }
4116               
4117                /**
4118                 * Return a string representation on the form "[i1,i2,i3]".
4119                 */
4120                public String toString() {
4121                        return buildString(new StringBuilder("[")).append(']').toString();
4122                }
4123               
4124                /**
4125                 * Return a string representation on the form "i1,i2,i3".
4126                 */
4127                public String toUnclosedString() {
4128                        return buildString(new StringBuilder()).toString();
4129                }
4130               
4131                /**
4132                 * Internal implementation of toString methods.
4133                 *
4134                 * Note that this must give the same result as a prettyPrint() on an equivalent
4135                 * FArraySubscripts, or inlining breaks.
4136                 */
4137                private StringBuilder buildString(StringBuilder buf) {
4138                        boolean sep = false;
4139                        for (int i : index) {
4140                                if (sep)
4141                                        buf.append(',');
4142                                buf.append(i);
4143                                sep = true;
4144                        }
4145                        return buf;
4146                }
4147               
4148               
4149                /**
4150                 * Return the internal index in an Array of the cell this Index refers to.
4151                 *        Only for use from Array.
4152                 *
4153                 * @param ind  the indices to resolve the internal index with
4154                 */
4155                public int internal(Indices ind) {
4156                        return ind.internal(this);
4157                }
4158               
4159                /**
4160                 * Construct an empty Index.
4161                 */
4162                protected Index() {
4163                }
4164               
4165                /**
4166                 * Construct an Index of ndims dimensions,
4167                 *        pointing at the spot before the first cell.
4168                 */
4169                protected Index(int ndims) {
4170                        index = new int[ndims];
4171                        for (int i = ndims - 2; i >= 0; i--)
4172                                index[i] = 1;
4173                        if (ndims > 0)
4174                                index[ndims - 1] = 0;
4175                }
4176               
4177        }
4178       
4179        /**
4180         * Indices represents the set of array indices in each dimension.
4181         *
4182         * Only supports indices of the form (1..n1, 1..n2, ... , 1..nk).
4183         * See {@link NonConsecutiveIndices}.
4184         *
4185         * New Indices objects should be created with the create() methods.
4186         * The subclass used is selected automatically.
4187         *
4188         * The Indices class is typically used to iterate over all possible indices
4189         * of an array access of declaration.
4190         */
4191        public class Indices implements Iterable<Index> {
4192                protected int ndims;
4193                protected Size size;
4194               
4195                /**
4196                 *  Used to represent the Indices of scalar expressions.
4197                 */
4198                public static final Indices SCALAR = new Indices(Size.SCALAR);
4199               
4200                /**
4201                 * A perfect hash for all Indices that have consecutive indicies,
4202                 *        ndims <= 3 and size[i] <= 1023 for 0 <= i < ndims. -1 for other
4203                 *        Indices.
4204                 */
4205                protected int hash;
4206               
4207                /**
4208                 * Create an Indices object based on array sizes.
4209                 */
4210                public static Indices create(Size size) {
4211                        if (size == Size.SCALAR)
4212                                return SCALAR;
4213                        else
4214                                return new Indices(size);
4215                }
4216               
4217                /**
4218                 * Create an Indices object based on FArraySubcripts.
4219                 */
4220                public static Indices createFromFas(FArraySubscripts fas) {
4221                        return NonConsecutiveIndices.createFromFas(fas);
4222                }
4223               
4224                /**
4225                 * Create an Indices object based on a list of FArraySubcripts.
4226                 */
4227                public static Indices createFromFas(java.util.List<FArraySubscripts> fasl) {
4228                        return NonConsecutiveIndices.createFromFas(fasl);
4229                }
4230               
4231                /**
4232                 * Create an Indices object based on a list of int arrays.
4233                 */
4234                public static Indices create(ArrayList<int[]> ind) {
4235                        return NonConsecutiveIndices.create(ind, true);
4236                }
4237               
4238                /**
4239                 * Create an Indices object based on a list of CommonForIndexes.
4240                 */
4241                public static Indices create(Iterable<? extends CommonForIndex> forIndices) {
4242                        ArrayList<int[]> ind = new ArrayList<int[]>();
4243                        for (CommonForIndex fi : forIndices) 
4244                                ind.add(fi.myIndices());
4245                        return NonConsecutiveIndices.create(ind, false);
4246                }
4247               
4248                /**
4249                 * Check that i is valid for this Indices object.
4250                 */
4251                public boolean isValid(Index i) {
4252                        if (i.ndims() != ndims)
4253                                return false;
4254                        int[] index = i.index();
4255                        for (int j = 0; j < ndims; j++)
4256                                if (index[j] < 1 || index[j] > size.get(j))
4257                                        return false;
4258                        return true;
4259                }
4260               
4261                /**
4262                 * Returns an Iterator, that iterates over all indices spanned by this Indices object.
4263                 */
4264                public Iterator<Index> iterator() {
4265                        return new IIterator();
4266                }
4267               
4268                /**
4269                 * Returns the number of elements spanned by this Indices object.
4270                 */
4271                public int numElements() {
4272                        return size.numElements();
4273                }
4274               
4275                /**
4276                 * Returns the number of dimensions spanned by this Indices object.
4277                 */
4278                public int ndims() {
4279                        return ndims;
4280                }
4281               
4282                /**
4283                 * Returns the size of this Indices object in each dimension.
4284                 */
4285                public Size size() {
4286                        return size;
4287                }
4288
4289        /**
4290         * Translates an Index to the corresponding Index in the underlying expression.
4291         * If i has fewer dimensions than this, than it should correspond to the outermost ones.
4292         *
4293         * Note that for some implementations, the returned index may be changed by subsequent
4294         * calls to this method.
4295         *
4296         * Default implementation always returns <code>i</code>.
4297         */
4298        public Index translate(Index i) {
4299            return i;
4300        }
4301
4302        public Indices translated() {
4303            return this;
4304        }
4305
4306                /**
4307                 * Add values to an index map for a given index from this set and a given set of for indices.
4308                 *
4309                 * Also sets the evaluation values of the index variables.
4310                 */
4311                public void fillIndexMap(Map<String,FExp> indexMap, Index i, Iterable<? extends CommonForIndex> forIndices) {
4312                        int j = 0;
4313                        int[] ii = translate(i).index();
4314                        for (CommonForIndex fi : forIndices) {
4315                                indexMap.put(fi.name(), new FIntegerLitExp(ii[j]));
4316                                fi.setEvaluationValue(CValueInteger.valueOf(ii[j]));
4317                                j++;
4318                        }
4319                }
4320                               
4321               
4322                /**
4323                 * Internal constructor to create an Indices object based on array sizes.
4324                 */
4325                protected Indices(Size size) {
4326                        ndims = size.ndims();
4327            this.size = size;
4328                        hash = -1;
4329                        if (ndims < 4) {
4330                                int h = 0;
4331                                for (int i = 0; i < ndims; i++) {
4332                                        int s = size.get(i);
4333                                        if (s > 1023) 
4334                                                return;
4335                                        h = (h << 10) | s;
4336                                }
4337                                hash = h;
4338                        }
4339                }
4340                               
4341                /**
4342                 * Calculate the internal index in an Array that spans this Indices.
4343                 */
4344                protected int internal(Index i) {
4345                        if (i.ndims() > ndims)
4346                                throw new UnsupportedOperationException("Too many dimensions in Index.");
4347                        int[] index = i.index();
4348                        int res = 0;
4349                        for (int j = 0; j < ndims; j++)
4350                                res = res * size.get(j) + (j < index.length ? index[j] - 1 : 0);
4351                        return res;
4352                }
4353               
4354        /**
4355         * Iterates over all indices spanned by this Indices.
4356         */
4357        protected class IIterator implements Iterator<Index> {
4358           
4359            protected IIndex index;
4360            protected int max;
4361           
4362            public IIterator() {
4363                index = new IIndex();
4364                max = numElements() - 1;
4365            }
4366           
4367            public boolean hasNext() {
4368                return index.internal < max;
4369            }
4370           
4371            public Index next() {
4372                if (index.internal >= max)
4373                    throw new NoSuchElementException();
4374                index.internal++;
4375                if (ndims == 0) {
4376                    return Index.NULL;
4377                }
4378                int[] ind = index.index();
4379                int i;
4380                for (i = ndims - 1; i > 0 && ind[i] >= size.get(i); i--)
4381                    ind[i] = 1;
4382                ind[i]++;
4383                return index;
4384            }
4385           
4386            public void remove() {
4387                throw new UnsupportedOperationException();
4388            }
4389           
4390        }
4391               
4392                /**
4393                 * Internal implementation of Index.
4394                 */
4395                protected class IIndex extends Index {
4396                       
4397                        public int internal;
4398                       
4399                        /**
4400                         * Construct an Index over the number of dimensions of the enclosing Indices,
4401                         *        pointing at the spot before the first cell.
4402                         */
4403                        public IIndex() {
4404                                super(ndims);
4405                                internal = -1;
4406                        }
4407                       
4408                        /**
4409                         * Return the internal index in an Array of the cell this Index refers to.
4410                         *        Only for use from Array.
4411                         *
4412                         * @param ind  the indices to resolve the internal index with
4413                         */
4414                        public int internal(Indices ind) {
4415                                if (Indices.this == ind || (hash != -1 && hash == ind.hash)) 
4416                                        return internal;
4417                                else
4418                                        return ind.internal(this);
4419                        }
4420                       
4421                }
4422               
4423        }
4424
4425        /**
4426         * NonConsecutiveIndices describes a set of array indices that isn't
4427         *        limited to 1..n.
4428         *
4429         * For example, consider the declaration Real x[4,4,4] and the access
4430         * x[:,1,1:2:4]. The array indices for the declaration is then
4431         * {1,2,3,4}, {1,2,3,4}, and {1,2,3,4} respectively for the three dimensions.
4432         * For the access, we have {1,2,3,4}, {1} and {1,3} respectively. The access
4433         * will have size [4,2], and this class will handle the necessary translations
4434         * between indices.
4435         */
4436        public class NonConsecutiveIndices extends Indices {
4437                // The indices are stored as a list of integer arrays.
4438                protected ArrayList<int[]> indices; 
4439                protected Index trans;
4440                protected boolean[] trim;
4441               
4442                /**
4443                 * Create a NonConsecutiveIndices object based on FArraySubcripts.
4444                 *        Use Indices.create(FArraySubscripts fas).
4445                 */
4446        public static NonConsecutiveIndices createFromFas(FArraySubscripts fas) {
4447                        int n = fas.numSubscript();
4448                        ArrayList<int[]> ind = new ArrayList<int[]>(n);
4449                        boolean[] trim = new boolean[n];
4450            createFromFas(Collections.singleton(fas), ind, trim);
4451                        return new NonConsecutiveIndices(ind, trim, 0);
4452                }
4453               
4454                /**
4455                 * Create a NonConsecutiveIndices object based on a list of FArraySubcripts.
4456                 *        Use Indices.create(ArrayList<FArraySubscripts> fasl).
4457                 */
4458                public static NonConsecutiveIndices createFromFas(java.util.List<FArraySubscripts> fasl) {
4459                        int n = 0;
4460                        for (FArraySubscripts fas : fasl)
4461                                n += fas.numSubscript();
4462                        ArrayList<int[]> ind = new ArrayList<int[]>(n);
4463                        boolean[] trim = new boolean[n];
4464            createFromFas(fasl, ind, trim);
4465                        return new NonConsecutiveIndices(ind, trim, 0);
4466                }
4467       
4468        private static void createFromFas(Iterable<FArraySubscripts> fasl, ArrayList<int[]> ind, boolean[] trim) {
4469            int i = 0;
4470            for (FArraySubscripts fas : fasl) {
4471                for (Subscript s : fas.subscripts()) { 
4472                    ind.add(s.myIndices());
4473                    trim[i++] = s.ndims() == 0;
4474                }
4475            }
4476        }
4477       
4478        /**
4479         * Create a NonConsecutiveIndices object based on a list of int arrays
4480         *        Use Indices.create(ArrayList<int[]> ind).
4481         *
4482         * @param ind   one array for each dimension, containing the indices to span for that dimension.
4483         * @param trim  remove dimensions that only span one index.
4484         */
4485        public static NonConsecutiveIndices create(ArrayList<int[]> ind, boolean trim) {
4486            boolean[] trims = new boolean[ind.size()];
4487            for (int i = 0; i < trims.length; i++)
4488                trims[i] = trim && ind.get(i).length == 1;
4489            return new NonConsecutiveIndices(ind, trims, 0);
4490        }
4491
4492        /**
4493         * Create a NonConsecutiveIndices object based on a Size, an array of dimensions to trim,
4494         * and a number of extra dimensions to add to the end.
4495         */
4496        public static NonConsecutiveIndices create(Size s, int[] dim, int extra) {
4497            int n = s.ndims();
4498            ArrayList<int[]> ind = new ArrayList<int[]>(n);
4499            boolean[] trims = new boolean[n];
4500            for (int i = 0; i < n; i++) {
4501                ind.add(new int[] { 1 });
4502                trims[i] = true;
4503            }
4504            for (int d : dim) {
4505                if (d < n) {
4506                    int[] ii = new int[s.get(d)];
4507                    for (int i = 0; i < ii.length; i++)
4508                        ii[i] = i + 1;
4509                    ind.set(d, ii);
4510                    trims[d] = false;
4511                }
4512            }
4513            return new NonConsecutiveIndices(ind, trims, extra);
4514        }
4515
4516        /**
4517         * Internal constructor to create a NonConsecutiveIndices object based on a
4518         * list of int arrays containing the used indexes on the underlying array.
4519         *
4520         * @param trim   the dimensions to remove
4521         * @param extra  number of extra dimensions of length 1 to add
4522         */
4523        protected NonConsecutiveIndices(ArrayList<int[]> ind, boolean[] trim, int extra) {
4524            super(getSize(ind, trim, extra));
4525            this.trim = trim;
4526            indices = ind;
4527            trans = intializeTranslated(ind.size());
4528        }
4529
4530        /**
4531         * Translates an Index to the corresponding Index in the underlying expression.
4532         * If i has fewer dimensions than this, than it should correspond to the outermost ones.
4533         *
4534         * Note that the returned Index may be changed by subsequent calls to this method,
4535         * use {@link Index.fix()} if you need to save it.
4536         */
4537        @Override
4538        public Index translate(Index i) {
4539            int[] ii = i.index();
4540            int transNDims = ii.length + trim.length - ndims;
4541            if (trans.ndims() != transNDims) {
4542                trans = intializeTranslated(transNDims);
4543            }
4544            int[] ti = trans.index();
4545            for (int ji = 0, jt = 0; ji < ndims && jt < ti.length; ji++, jt++) {
4546                while (trim[jt]) {
4547                    jt++;
4548                }
4549                ti[jt] = indices.get(jt)[ii[ji] - 1];
4550            }
4551            return trans;
4552        }
4553
4554        /**
4555         * Prepare a new Index for returning from the translate method.
4556         */
4557        protected Index intializeTranslated(int n) {
4558            Index trans = new Index(n);
4559            for (int i = 0; i < n; i++) {
4560                if (indices.get(i).length > 0) {
4561                    trans.index()[i] = indices.get(i)[0];
4562                }
4563            }
4564            return trans;
4565        }
4566
4567        @Override
4568        public Indices translated() {
4569            return new TranslatedIndices(this);
4570        }
4571
4572        private static class TranslatedIndices extends Indices {
4573           
4574            private NonConsecutiveIndices indices;
4575           
4576            private TranslatedIndices(NonConsecutiveIndices indices) {
4577                super(indices.size);
4578                this.indices = indices;
4579            }
4580           
4581            @Override
4582            public Iterator<Index> iterator() {
4583                return new Iter();
4584            }
4585           
4586            private class Iter implements Iterator<Index> {
4587               
4588                private Iterator<Index> iterator;
4589               
4590                private Iter() {
4591                    iterator = indices.iterator();
4592                }
4593               
4594                public boolean hasNext() {
4595                    return iterator.hasNext();
4596                }
4597                public Index next() {
4598                    return indices.translate(iterator.next());
4599                }
4600                public void remove() {
4601                    iterator.remove();
4602                }
4603            }
4604        }
4605
4606                /**
4607                 * Calculate size for this indices from a list of int arrays containing the
4608                 * used indexes on the underlying array.
4609                 */
4610                protected static Size getSize(ArrayList<int[]> ind, boolean[] trim, int extra) {
4611                        int n = 0;
4612                        for (boolean tr : trim)
4613                                if (!tr)
4614                                        n++;
4615            if (n + extra == 0) {
4616                return Size.SCALAR;
4617            }
4618                        MutableSize size = new MutableSize(n + extra);
4619                        for (int i = 0; i < trim.length; i++)
4620                                if (!trim[i])
4621                                        size.append(ind.get(i).length);
4622                        for (int i = 0; i < extra; i++)
4623                                size.append(1);
4624                        return size;
4625                }
4626               
4627        /**
4628         * Create a new Indices object with the earlier active dimensions (trim=false)
4629         * specified by the corresponding position in index and the earlier inactive
4630         * dimensions enabled.
4631         */
4632        public NonConsecutiveIndices locked(Index index, boolean[] b) {
4633            ArrayList<int[]> newInd = new ArrayList<int[]>();
4634            boolean[] newTrim = new boolean[indices.size()];
4635            index = translate(index);
4636            for (int k = 0; k < indices.size(); k++) {
4637                if (trim[k]) {
4638                    newInd.add(indices.get(k));
4639                } else {
4640                    int[] t = new int[1];
4641                    t[0] = index.index()[k];
4642                    newInd.add(t);
4643                }
4644                b[k] = trim[k];
4645                newTrim[k] = false;
4646            }
4647            return new NonConsecutiveIndices(newInd, newTrim, 0);
4648        }
4649       
4650        /**
4651         * Create a new Indices object with the earlier inactive dimensions
4652         * enabled and replaced using the surrounding size for the corresponding
4653         * dimension in fas.
4654         */
4655        public static NonConsecutiveIndices expIndices(Size s, FArraySubscripts fas) {
4656            int n2 = s.ndims();
4657            int n1 = n2 - fas.ndims();
4658            ArrayList<int[]> newInd = new ArrayList<int[]>();
4659            boolean[] newTrim = new boolean[n2];
4660            for (int k = 0; k < n1; k++) {
4661                newInd.add(ASTNode.range(s.get(k)));
4662                newTrim[k] = false;
4663            }
4664            fas.expIndices(newInd, newTrim, n1);
4665            return new NonConsecutiveIndices(newInd, newTrim, 0);
4666        }
4667       
4668        /**
4669         * Create a new Indices object with the earlier inactive dimensions
4670         * enabled and replaced using subscript size for the corresponding
4671         * dimension in fas. Earlier active dimensions are disabled.
4672         */
4673        public static NonConsecutiveIndices fasIndices(FArraySubscripts fas) {
4674            ArrayList<int[]> newInd = new ArrayList<int[]>();
4675            boolean[] newTrim = new boolean[fas.numSubscript()];
4676            for (int k = 0; k < newTrim.length; k++) {
4677                Subscript fs = fas.subscript(k);
4678                if (fs.ndims() == 0 || fs.variability().indexParameterOrLess()) {
4679                    newInd.add(new int[0]);
4680                    newTrim[k] = true;
4681                } else {
4682                    newInd.add(ASTNode.range(fs.size().numElements()));
4683                    newTrim[k] = false;
4684                }
4685            }
4686            return new NonConsecutiveIndices(newInd, newTrim, 0);
4687        }
4688    }
4689   
4690    public abstract void FArraySubscripts.expIndices(ArrayList<int[]> newInd, boolean[] newTrim, int offset);
4691    public void FArrayExpSubscripts.expIndices(ArrayList<int[]> newInd, boolean[] newTrim, int offset) {
4692        for (int k = 0; k < getNumFSubscript(); k++) {
4693            FSubscript fs = getFSubscript(k);
4694            if (fs.variability().indexParameterOrLess()) {
4695                int[] i = fs.myIndices();
4696                newInd.add(i);
4697                newTrim[k + offset] = false;
4698            } else {
4699                newInd.add(ASTNode.range(fs.mySize().get(0)));
4700                newTrim[k + offset] = true;
4701            }
4702        }
4703    }
4704    public void FArrayLitSubscripts.expIndices(ArrayList<int[]> newInd, boolean[] newTrim, int offset) {
4705        for (int k = 0; k < subscripts.length; k++) {
4706            int[] i = subscript(k).myIndices();
4707            newInd.add(i);
4708            newTrim[k + offset] = false;
4709        }
4710    }
4711
4712
4713    public static int[] ASTNode.range(int n) {
4714        int[] res = new int[n];
4715        for (int i = 0; i < n; i++) {
4716            res[i] = i + 1;
4717        }
4718        return res;
4719    }
4720}
Note: See TracBrowser for help on using the repository browser.