source: trunk/Compiler/ModelicaFlatTree/src/jastadd/Arrays.jrag @ 12940

Last change on this file since 12940 was 12940, checked in by tgutzmann, 6 months ago

#5788 Addressed many warnings. Most noteworthy changes:

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