source: branches/dev-5819/Compiler/ModelicaFrontEnd/src/jastadd/flattening/connections/Connections.jrag @ 13800

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

#5819 Merged trunk into branch

File size: 53.2 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.Arrays;
18import java.util.Iterator;
19import java.util.LinkedHashSet;
20import java.util.ArrayList;
21import java.util.Collection;
22import java.util.Map;
23import java.util.HashMap;
24import java.util.Queue;
25import java.util.Set;
26import java.util.ArrayDeque;
27import java.util.PriorityQueue;
28
29import org.jmodelica.util.Enumerator;
30import org.jmodelica.util.collections.GrowableSetIterable;
31import org.jmodelica.util.collections.ParallelIterable;
32
33aspect Connections {
34
35        /* Machinery to manage connection sets */
36
37        public ConnectionSetManager FClass.connectionSetManager = new ConnectionSetManager();
38       
39        public ConnectionSetManager FClass.getConnectionSetManager() {
40                return connectionSetManager;
41        }
42
43    public void FClass.genConnectionEquations(Flattener f) {
44        beginStep("genConnectionEquations()");
45        for (ConnectionSet set : connectionSetManager.getConnectionSetList()) 
46            set.generateEquations(f);
47        connectionSetManager.generateEqualityConstraints(f);
48        connectionSetManager.disconnectFromInstanceTree();
49        endStep("genConnectionEquations()");
50    }
51
52    public void ASTNode.enableStreamsRewrite() {
53        for (ASTNode n : this)
54            n.enableStreamsRewrite();
55    }
56
57    public void FStreamBuiltIn.enableStreamsRewrite() {
58        super.enableStreamsRewrite();
59        rewriteStreams = true;
60        is$Final = false;
61    }
62
63    protected boolean FStreamBuiltIn.rewriteStreams = false;
64
65    public class FClass {
66        public class enableStreamsRewrite extends Transformation {
67            // Depends on enableIfEquationElimination being done
68            public void perform() {
69                enableStreamsRewrite();
70                change();
71            }
72        }
73    }
74
75    /**
76     * Rewrite the inSteam operator to expanded form.
77     */
78    rewrite FInStream {
79        when (rewriteStreams) to FExp expandInStreamExp();
80    }
81
82    protected FExp FInStream.expandInStreamExp() {
83        // Always create expression from the connection set where the variable is an inside connector.
84        FAccess name = getFExp().asCommonAccess().asFAccess();
85        ConnectionSet cs = myFClass().getConnectionSetManager().getStreamConnectionSet(name.name(), false);
86        return cs.expandInStreamExp(name);
87    }
88
89    protected FExp FDerStream.expandInStreamExp() {
90        // Note: this handles both enableStreamsRewrite and enableExpandedInStreamRewrite
91        if (getFExp().needsLaterInStreamRewrite()) {
92            return new FDerStream(getFExp().treeCopy());
93        } else {
94            return getFExp().diff(FExp.TIME);
95        }
96    }
97
98    syn boolean FExp.needsLaterInStreamRewrite() = false;
99    eq FExInStream.needsLaterInStreamRewrite()   = true;
100    eq FDerStream.needsLaterInStreamRewrite()    = true;
101
102    public class FClass {
103        public class enableExpandedInStreamRewrite extends Transformation {
104            // Depends on variabilityPropagationIfSet and the following aliasEliminationIfSet being done
105            public void perform() {
106                enableExpandedInStreamRewrite();
107                change();
108            }
109        }
110    }
111   
112    public void ASTNode.enableExpandedInStreamRewrite() {
113        for (ASTNode n : this)
114            n.enableExpandedInStreamRewrite();
115    }
116   
117    public void FDerStream.enableExpandedInStreamRewrite() {
118        super.enableExpandedInStreamRewrite();
119        rewriteStreams = true;
120        is$Final = false;
121    }
122
123    public void FExInStream.enableExpandedInStreamRewrite() {
124        super.enableExpandedInStreamRewrite();
125       
126        // We don't need to add anything for < 2 contributors
127        FExp stream = getDefault().treeCopy();
128        int n = 0;
129        for (InStreamPart cont : contributors()) {
130            stream = cont.stream.treeCopy();
131            n++;
132            if (n > 1) {
133                break;
134            }
135        }
136        if (n < 2) {
137            replaceMe(stream);
138            return;
139        }
140       
141        FExp eps   = getEps();
142        FExp alpha = generateAlpha(eps, generateS());
143       
144        // Generate replacement expression
145        ArrayList<FExp> nominatorTerms   = new ArrayList<FExp>();
146        ArrayList<FExp> denominatorTerms = new ArrayList<FExp>();
147        for (InStreamPart cont : contributors()) {
148            stream = cont.stream.treeCopy();
149            FExp flow = cont.flow.treeCopy();
150            if (!cont.outside) {
151                flow = new FNegExp(flow);
152            }
153            FExp posMax = positiveMax(eps, flow, alpha);
154            nominatorTerms.add(new FMulExp(posMax.treeCopyNoTransform(), stream));
155            denominatorTerms.add(posMax);
156        }
157        replaceMe(new FDivExp(
158                FExp.createBalancedBinaryTree(new FAddExp(), nominatorTerms),
159                FExp.createBalancedBinaryTree(new FAddExp(), denominatorTerms)));
160    }
161
162    /**
163     * Generate and add variable with varType, add an equation for the variable with rhs <code>exp</code>.
164     */
165    private FExp FExInStream.addEquation(FlatVariableMap.GeneratedVarType varType, FExp exp) {
166        String name = calcGeneratedVarName(varType);
167        TypePrefixVariability v = variability().combine(Variability.FIXEDPARAMETER);
168        myFClass().addFVariable(type().createTempFVariable(new FAccessString(name), variability()));
169        myFClass().equationList(v).add(new FEquation(new FAccessExp(name), exp));
170        return new FAccessExp(name);
171    }
172   
173    /**
174     * Get (no transform) equation list matching the variability <code>v</code>.
175     */
176    public List<FAbstractEquation> FClass.equationList(TypePrefixVariability v) {
177        if (v.knownParameterOrLess()) {
178            throw new UnsupportedOperationException();
179        } else if (v.fixedParameterVariability()) {
180            return getParameterEquationsNoTransform();
181        } else if (v.initialParameterVariability()) {
182            return getFInitialEquationsNoTransform();
183        } else {
184            return getFAbstractEquationsNoTransform();
185        }
186    }
187
188    /**
189     * Add variable and equation for s_i, return reference to s_i
190     */
191    private FExp FExInStream.generateS() {
192        ArrayList<FExp> terms = new ArrayList<FExp>();
193        for (InStreamPart cont : contributors()) {
194            FExp flow = cont.flow.treeCopy();
195            if (!cont.outside) {
196                flow = new FNegExp(flow);
197            }
198            terms.add(new FMaxExp(flow, new Opt<FExp>(new FIntegerLitExp(0))));
199           
200        }
201        return addEquation(FlatVariableMap.GeneratedVarType.STREAM_S,
202                FExp.createBalancedBinaryTree(new FAddExp(), terms));
203    }
204
205    /**
206     * Add variable and equation for alpha_i, return reference to alpha_i
207     */
208    private FExp FExInStream.generateAlpha(FExp eps, FExp s) {
209        FExp sDivEps = new FDivExp(s.treeCopyNoTransform(), eps.treeCopyNoTransform());
210        FExp alpha = new FSmoothExp(
211                new FIntegerLitExp(1), 
212                new FIfExp(
213                        new FGtExp(
214                                s.treeCopyNoTransform(),
215                                eps.treeCopyNoTransform()),
216                        new FIntegerLitExp(1),
217                        new FIfExp(
218                                new FGtExp(
219                                        s.treeCopyNoTransform(),
220                                        new FIntegerLitExp(0)),
221                                new FMulExp(
222                                        sDivEps.treeCopyNoTransform(), 
223                                        new FMulExp(
224                                                sDivEps.treeCopyNoTransform(),
225                                                new FSubExp(
226                                                        new FIntegerLitExp(3),
227                                                        new FMulExp(
228                                                                new FIntegerLitExp(2),
229                                                                s.treeCopyNoTransform())))),
230                                new FIntegerLitExp(0))));
231        return addEquation(FlatVariableMap.GeneratedVarType.STREAM_ALPHA, alpha);
232    }
233
234    /**
235     * Add variable and equation for positiveMax_i, return reference to positiveMax_i
236     */
237    private FExp FExInStream.positiveMax(FExp eps, FExp flow, FExp alpha) {
238        FExp exp = new FAddExp(
239                new FMulExp(
240                        alpha.treeCopyNoTransform(),
241                        new FMaxExp(
242                                flow,
243                                new Opt<FExp>(new FIntegerLitExp(0)))),
244                new FMulExp(
245                        new FSubExp(
246                                new FIntegerLitExp(1),
247                                alpha.treeCopyNoTransform()),
248                        eps.treeCopyNoTransform()));
249        return addEquation(FlatVariableMap.GeneratedVarType.STREAM_POSMAX, exp);
250    }
251
252
253    syn int FExInStream.numVars() = getNumVar() / 3;
254
255    syn FExp FExInStream.flowExp(int i) = getVar(i * 3);
256
257    syn FExp FExInStream.streamExp(int i) = getVar(i * 3 + 1);
258
259    syn FExp FExInStream.isOutsideExp(int i) = getVar(i * 3 + 2);
260
261    syn boolean FExInStream.isOutside(int i) = isOutsideExp(i).ceval().booleanValue();
262
263    public class FExInStream {
264        /**
265         * An iterable over all stream/flow pairs that contribute to this inStream().
266         */
267        public Iterable<InStreamPart> contributors() {
268            return new ContributorIterable();
269        }
270       
271        public class InStreamPart {
272            public final FExp flow;
273            public final FExp stream;
274            public final boolean outside;
275
276            public InStreamPart(int i) {
277                flow = flowExp(i);
278                stream = streamExp(i);
279                outside = isOutside(i);
280            }
281
282            public boolean contributes() {
283                if (outside) {
284                    return flow.maxRealValue() > 0;
285                } else {
286                    return flow.minRealValue() < 0;
287                }
288            }
289        }
290
291        private class ContributorIterable implements Iterable<InStreamPart> {
292            private int n = numVars();
293           
294            public Iterator<InStreamPart> iterator() {
295                return new ContributorIterator();
296            }
297
298            private class ContributorIterator implements Iterator<InStreamPart> {
299                private int i;
300                private InStreamPart next;
301
302                public ContributorIterator() {
303                    i = -1;
304                    step();
305                }
306
307                public boolean hasNext() {
308                    return i < n;
309                }
310
311                public InStreamPart next() {
312                    InStreamPart res = next;
313                    step();
314                    return res;
315                }
316               
317                public void remove() {
318                    throw new UnsupportedOperationException();
319                }
320
321                private void step() {
322                    do {
323                        i++;
324                        next = (i < n) ? new InStreamPart(i) : null;
325                    } while (i < n && !next.contributes());
326                }
327            }
328        }
329    }
330
331    /**
332     * Check if this expression is multiplied with the given variable.
333     */
334    inh boolean FExp.isMultipliedWith(FVariable v);
335    eq BaseNode.getChild().isMultipliedWith(FVariable v)          = false;
336    eq FDotMulExp.getRight().isMultipliedWith(FVariable v)        = getLeft().isMultiplicationOf(v) || isMultipliedWith(v);
337    eq FDotMulExp.getLeft().isMultipliedWith(FVariable v)         = getRight().isMultiplicationOf(v) || isMultipliedWith(v);
338    eq FSemiLinearExp.getPosSlope().isMultipliedWith(FVariable v) = getX().isMultiplicationOf(v) || isMultipliedWith(v);
339    eq FSemiLinearExp.getNegSlope().isMultipliedWith(FVariable v) = getX().isMultiplicationOf(v) || isMultipliedWith(v);
340
341    /**
342     * Check if this expression is an access to v or a multiplication where one of the
343     * multiplicands is an access to v.
344     */
345    syn boolean FExp.isMultiplicationOf(FVariable v) = false;
346    eq FAccessExp.isMultiplicationOf(FVariable v)    = v == myFV();
347    eq FNegExp.isMultiplicationOf(FVariable v)       = getFExp().isMultiplicationOf(v);
348    eq FDotMulExp.isMultiplicationOf(FVariable v)    = 
349        getLeft().isMultiplicationOf(v) || getRight().isMultiplicationOf(v);
350
351    rewrite FActualStream {
352        when (rewriteStreams) to FExp {
353            // Get the stream variable name prefix
354            FAccess varName = getFExp().asFAccessExp().getFAccess();
355            FAccess prefix = varName.copyPrefix();
356            ArrayList<ConnectionSetEntry> cses = 
357                myFClass().getConnectionSetManager().getFlowVariables(prefix.name());
358            ConnectionSetEntry cse = null;
359            if (cses.size() == 1) {
360                cse = cses.get(0);
361            } else if (cses.size() == 2) {
362                cse = cses.get(0);
363                // Check that this is an inside and an outside entry for the same name
364                ConnectionSetEntry cse2 = cses.get(1);
365                if (cse.isInside() == cse2.isInside() || !cse.name().equals(cse2.name()))
366                    cse = null;
367            }
368            if (cse != null) {
369                // Get the name of the single flow variable of the connector, then get the variables.
370                FAccess flowVarName = cse.getFAccess();
371                FRealVariable var = (FRealVariable) varName.myFV();
372                FRealVariable flowVar = (FRealVariable) varName.lookupFV(cse.name());
373               
374                // Decide what parts are valid
375                boolean constant = flowVar.isConstant();
376                double min = constant ? flowVar.ceval().realValue() : flowVar.minAttribute();
377                double max = constant ? min : flowVar.maxAttribute();
378                boolean multFlow = isMultipliedWith(flowVar);
379                boolean badMinMax = min > max;
380                boolean thenValid = badMinMax || max > 0.0;
381                boolean elseValid = badMinMax || min < 0.0 || (min == 0.0 && !(thenValid && multFlow));
382               
383                // Generate the expression
384                FExp res = null, elseExp = null;
385                FInStream thenExp = null;
386                if (thenValid) {
387                    res = thenExp = new FInStream(var.createAccessExp());
388                    thenExp.rewriteStreams = true; // Enable further rewrite of the inStream operator.
389                }
390                if (elseValid) 
391                    res = elseExp = var.createAccessExp();
392                if (thenValid && elseValid) {
393                    FExp guard = new FGtExp(flowVar.createAccessExp(), new FRealLitExp(0.0));
394                    res = new FIfExp(guard, thenExp, elseExp);
395                    if (multFlow)
396                        res = new FSmoothExp(0, res);
397                }
398                return res;
399            }
400            // There should already have been an error message in this case, so we should never come here.
401            throw new UnsupportedOperationException("Rewriting actualStream() for '" + varName.name() + 
402                    "': found " + cses.size() + " matching flow variables");
403        }
404    }
405
406       
407        public abstract class ConnectionSet extends TreeSet<ConnectionSetEntry> {
408               
409                protected ConnectionSet(ConnectionSetEntry e) {
410                        add(e);
411                }
412               
413                public static ConnectionSet create(ConnectionSetEntry e) {
414                        if (e.isFlow())
415                                return new FlowConnectionSet(e);
416                        else if (e.isStream())
417                                return new StreamConnectionSet(e);
418                        else 
419                                return new PotentialConnectionSet(e);
420                }
421               
422                public void disconnectFromInstanceTree() {
423                        for (ConnectionSetEntry e : this)
424                                e.disconnectFromInstanceTree();
425                }
426               
427                public int getNumInside() {
428                        int nInside = 0;
429                        for (ConnectionSetEntry cse : this) {
430                                if (cse.isInside()) {
431                                        nInside++;
432                                }
433                        }
434                        return nInside;
435                }
436               
437                public int getNumOutside() {
438                        int nOutside = 0;
439                        for (ConnectionSetEntry cse : this) {
440                                if (cse.isOutside()) {
441                                        nOutside++;
442                                }
443                        }
444                        return nOutside;
445                }
446
447                public ConnectionSetEntry getConnectionSetEntry(String name, boolean outside) {
448                        for (ConnectionSetEntry cse : this) {
449                                if (cse.equals(name, outside)) {
450                                        return cse;
451                                }
452                        }
453                        return null;
454                }
455               
456                /**
457                 * Check if a rewrite expression can be generated for an inStream() on a variable in this set.
458                 *
459                 * Default implementation returns false, since inStream() only applies to stream connecton sets.
460                 */
461                public boolean canCreateInStreamExp() {
462                        return false;
463                }
464               
465                /**
466                 * Create rewrite expression for an inStream() on a variable in this set.
467                 *
468                 * Only valid for stream connecton sets.
469                 *
470                 * @param name  the name of the variable to generate name for
471                 */
472                public FExp expandInStreamExp(FAccess name) {
473                        throw new UnsupportedOperationException();
474                }
475               
476                /**
477                 * Generate equations for this set.
478                 *
479                 * @param eqns  equation list to add equations to
480                 */
481                public abstract void generateEquations(Flattener f);
482               
483                /**
484                 * Return all ConnectionSetEntrys corresponding to flow variables based
485                 * on a name prefix. This method is useful when generating expressions
486                 * for actualStream operators when the name of the flow variable in a
487                 * stream connector is needed.
488                 */
489                public ArrayList<ConnectionSetEntry> getFlowVariables(String prefix) {
490                        return new ArrayList<ConnectionSetEntry>(0);
491                }
492               
493                public int numStreamVariables() {
494                        int n_stream_vars = 0;
495                        for (ConnectionSetEntry e : this) {
496                                if (e.isStream()) {
497                                        n_stream_vars++;
498                                }
499                        }
500                        return n_stream_vars;
501                }
502               
503                public String toString() {
504                        StringBuffer str = new StringBuffer();
505                       
506                        str.append("Connection set (");
507                        str.append(typeString());
508                        str.append("): {");
509                        String set_str = super.toString();
510                        str.append(set_str.substring(1, set_str.length() - 1));
511                        str.append("}\n");
512                        return str.toString();
513                }
514               
515                protected abstract String typeString();
516               
517        }
518       
519        public class FlowConnectionSet extends ConnectionSet {
520               
521                public FlowConnectionSet(ConnectionSetEntry e) {
522                        super(e);
523                }
524               
525                public String typeString() {
526                        return "flow";
527                }
528               
529                public ArrayList<ConnectionSetEntry> getFlowVariables(String prefix) {
530                        ArrayList<ConnectionSetEntry> cses = new ArrayList<ConnectionSetEntry>();
531                        for (ConnectionSetEntry cse : this) 
532                                if (cse.prefix().equals(prefix)) 
533                                        cses.add(cse);
534                        return cses;
535                }
536
537        public void generateEquations(Flattener f) {
538            ConnectionSetEntry fst = first();
539            InstComponentDecl fstVar = fst.getVar();
540            if (size() == 1 && fst.isInside() && fstVar.isTopLevelCausalOrConnector()
541                    && (fstVar.isInput() || fstVar.isOutput() || fstVar.useCausalPorts())) {
542                return;
543            }
544            FExp e = null;
545            for (ConnectionSetEntry cse : this) 
546                e = cse.buildFlow(f, e);
547            FExp zero = fst.createZeroExp(f);
548            f.addNormalEquation(new FEquation(e, zero));
549        }
550
551        }
552
553    public class StreamConnectionSet extends ConnectionSet {
554       
555        private static final String inStreamSuffix = "__instream_";
556
557        private double nominal = Double.MAX_VALUE;
558
559        public StreamConnectionSet(ConnectionSetEntry e) {
560            super(e);
561        }
562
563        public String typeString() {
564            return "stream";
565        }
566
567        public void generateEquations(Flattener f) {
568            for (ConnectionSetEntry e : this) {
569                nominal = Math.min(e.flowNominal(), nominal);
570            }
571            for (ConnectionSetEntry e : this) {
572                if (e.isOutside()) {
573                    FExp left = e.createFAccessExp();
574                    FExp right = expandInStreamExp(e, null, e.createZeroExp(f));
575                    f.addNormalEquation(new FEquation(left, right));
576                }
577            }
578        }
579
580        /**
581         * Create rewrite expression for an inStream() on a variable in this set.
582         *
583         * @param name  the name of the variable to generate name for
584         */
585        @Override
586        public FExp expandInStreamExp(FAccess access) {
587            String name = access.name();
588            ConnectionSetEntry e = getConnectionSetEntry(name, false);
589            if (access.useCausalPorts()) {
590                AnnotationNode instreamAnnotation = access.myFV().annotation().vendorNode().forPath("internal/instream");
591                if (instreamAnnotation.exists()) {
592                    String instreamName = instreamAnnotation.ceval().stringValue();
593                    access = nameWithSubscripts(instreamName, name);
594                }
595            }
596            FExp exp = expandInStreamExp(e, name, new FAccessExp(access));
597            exp.enableStreamsRewrite();
598            return exp;
599        }
600       
601        public FAccess nameWithSubscripts(String name, String access) {
602            String subscripts = (access.endsWith("]")) ? access.substring(access.lastIndexOf("[")) : "";
603            return new FAccessString(name + subscripts);
604       }
605
606        /**
607         * Create an expression for the inStream() of the given entry.
608         *
609         * Used for inStream() for inside entries and for additional equations for outside entries.
610         *
611         * @param cse   the entry to generate the expression for
612         * @param name  the name of the scalar var to generate the stream access for,
613         *              of null for the entire array (in scalar case they are equivalent)
614         * @param def   expression to use when there are no contributing streams
615         */
616        private FExp expandInStreamExp(ConnectionSetEntry cse, String name, FExp def) {
617            FExp stream = def;
618            List<FExp> vars = new List<FExp>();
619            for (ConnectionSetEntry e : this) {
620                if (cse != e) {
621                    stream = (name == null) ? e.createFAccessExp() : e.createCommonAccessExp(name, cse);
622                    if (e.isOutside()) 
623                        stream = new FInStream(stream);
624                    vars.add(e.createFlowCommonAccessExp());
625                    vars.add(stream);
626                    vars.add(FBooleanLitExp.create(e.isOutside()));
627                }
628            }
629           
630            if (vars.getNumChildNoTransform() < 6) {
631                return stream;
632            } else {
633                return new FExInStream(def, new FMulExp(new FInStreamEpsExp(), new FRealLitExp(nominal)), vars);
634            }
635        }
636    }
637
638    /**
639     * Find the flow variable corresponding to this stream variable.
640     *
641     * Only valid for stream variables.
642     */
643    inh InstComponentDecl InstComponentDecl.myFlowVar();
644    eq InstComponentDecl.getChild().myFlowVar() = isConnector() ? findFlowVar() : null;
645    eq InstClassDecl.getChild().myFlowVar()     = isConnector() ? findFlowVar() : null;
646    eq InstRoot.getChild().myFlowVar()          = null;
647    eq Root.getChild().myFlowVar()              = null;
648
649    /**
650     * Find the first flow variable in this node, if any.
651     */
652    syn InstComponentDecl InstNode.findFlowVar() {
653        for (InstComponentDecl icd : allInstComponentDecls())
654            if (icd.isFlow())
655                return icd;
656        return null;
657    }
658
659    public class PotentialConnectionSet extends ConnectionSet {
660       
661        public PotentialConnectionSet(ConnectionSetEntry e) {
662            super(e);
663        }
664
665        public String typeString() {
666            return "potential";
667        }
668
669        public void generateEquations(Flattener f) {
670            if (size() == 1) {
671                // Cell that is not connected to in array in expandable connector
672                f.addNormalEquation(first().createZeroEquation(f));
673            } else {
674                FExp e1 = null;
675                for (ConnectionSetEntry cse : this) {
676                    FExp e2 = cse.createFAccessExp();
677                    if (e1 != null) {
678                        f.addNormalEquation(new FEquation(e1, e2));
679                    }
680                    e1 = e2;
681                }
682            }
683        }
684       
685    }
686
687
688        public class ConnectionSetManager {
689       
690                private ArrayList<ConnectionSet> list = new ArrayList<ConnectionSet>();
691                private ArrayList<EqualityConstraintConnection> equalityConstraints = new ArrayList<EqualityConstraintConnection>();
692                private Map<ConnectionSetEntry, ConnectionSet> cseMap = new HashMap<ConnectionSetEntry, ConnectionSet>();
693                private Map<String, CSENameMapEntry> cseStreamMap = new HashMap<String, CSENameMapEntry>();
694                private OverconstrainedConnectionGraph graph = null;
695                private ExpandableConnectorSets expandable = null;
696               
697        private static class CSENameMapEntry {
698            private ConnectionSetEntry outsideCSE = null;
699            private ConnectionSet outside = null;
700            private ConnectionSetEntry insideCSE = null;
701            private ConnectionSet inside = null;
702        }
703
704        private void updateCSEMapEntry(ConnectionSetEntry cse, ConnectionSet newValue) {
705            cseMap.put(cse, newValue);
706            if (!cse.isStream()) {
707                return;
708            }
709
710            for (String name : cse.names()) {
711                CSENameMapEntry entry = cseStreamMap.get(name);
712                if (entry == null) {
713                    entry = new CSENameMapEntry();
714                    cseStreamMap.put(name, entry);
715                }
716                if (cse.isOutside()) {
717                    entry.outsideCSE = cse;
718                    entry.outside = newValue;
719                } else {
720                    entry.insideCSE = cse;
721                    entry.inside = newValue;
722                }
723            }
724        }
725               
726                public ArrayList<ConnectionSet> getConnectionSetList() {
727                        return list;
728                }
729               
730                public OverconstrainedConnectionGraph getGraph() {
731                        if (graph == null) 
732                                graph = new OverconstrainedConnectionGraph();
733                        return graph;
734                }
735       
736       public ExpandableConnectorSets getExpandable() {
737           if (expandable == null) 
738               expandable = new ExpandableConnectorSets();
739           return expandable;
740       }
741       
742      public boolean isExpandableConnectorsDone() {
743          return expandable != null && expandable.isExpansionDone();
744      }
745
746        public void buildOverconstrainedConnectionTrees() {
747            if (graph != null) 
748                graph.buildTrees(this);
749        }
750       
751        public void elaborateExpandableConnectors() {
752            if (expandable != null) {
753                expandable.elaborate(this);
754                expandable = null;
755            }
756        }
757
758        public void addFlowVar(InstComponentDecl var, boolean outside, FAccess name) {
759            addVar(ConnectionSetEntry.create(var, outside, name));
760        }
761
762        public void addExpandableArrayMember(InstComponentDecl var, FAccess name) {
763            // TODO: this does not seem to handle when the expandable connector is connected in turn,
764            //       i.e. no connection to outside an expandable connector
765            // If var is present as inner, don't add it as outer
766            if (getConnectionSet(ConnectionSetEntry.create(var, false, name)) == null)
767                addVar(ConnectionSetEntry.create(var, true, name));
768        }
769
770                /**
771                 * Add vars to connection sets.
772                 *
773                 * Filters out parameters and constants.
774                 */
775                public void addVars(ConnectionSetEntry cse1, ConnectionSetEntry cse2) {
776
777//                      log.debug("ConnectionSetManager.addVars");
778               
779//                  System.out.println(namePrefix1.name()+" . "+var1.name() + " outside: " + outside1);
780//                  System.out.println(namePrefix2.name()+" . "+var2.name() + " outside: " + outside2);
781               
782                        // Don't add parameters or constants to connection set
783                        // TODO: Add them, but generate asserts instead of equations
784                        if (cse1.getVar().variability().parameterOrLess() || cse2.getVar().variability().parameterOrLess()) 
785                                return;
786
787                        ConnectionSet setA = getConnectionSet(cse1);
788                        ConnectionSet setB = getConnectionSet(cse2);
789                       
790                        if (setA != null && setB != null) {
791                                if (setA != setB)
792                                        merge(setA, setB);
793                        } else if (setA != null && setB == null) {
794                                add(setA, cse2);
795                        } else if (setA == null && setB != null) {
796                                add(setB, cse1);
797                        } else if (setA == null && setB == null) {
798                                join(cse1, cse2);
799                        }
800                }
801               
802                public void addEqualityConstraint(ConnectionSetEntry cse1, ConnectionSetEntry cse2, FAccess prefix) {
803                        equalityConstraints.add(new EqualityConstraintConnection(cse1, cse2, prefix));
804                }
805       
806        private void addVar(ConnectionSetEntry entry) {
807            if (getConnectionSet(entry) == null) {
808                ConnectionSet set = ConnectionSet.create(entry);
809                list.add(set);
810                updateCSEMapEntry(entry, set);
811            }
812        }
813               
814                private void join(ConnectionSetEntry entryA, ConnectionSetEntry entryB) {
815                        ConnectionSet set = ConnectionSet.create(entryA);
816                        set.add(entryB);
817                        list.add(set);
818                        updateCSEMapEntry(entryA, set);
819                        updateCSEMapEntry(entryB, set);
820                }
821               
822                private void add(ConnectionSet set, ConnectionSetEntry entry) {
823                        set.add(entry);
824                        updateCSEMapEntry(entry, set);
825                }
826               
827                private void merge(ConnectionSet setA, ConnectionSet setB) {
828                        if (setA.size() < setB.size()) {
829                                ConnectionSet tmp = setA;
830                                setA = setB;
831                                setB = tmp;
832                        }
833                        for (ConnectionSetEntry entry : setB)
834                            updateCSEMapEntry(entry, setA);
835                        setA.addAll(setB);
836                        list.remove(setB);
837                }
838               
839                public ConnectionSet getConnectionSet(ConnectionSetEntry cse) {
840                        return cseMap.get(cse);
841                }
842
843                public ConnectionSet getStreamConnectionSet(String name, boolean outside) {
844            CSENameMapEntry entry = cseStreamMap.get(name);
845            if (entry == null)
846                return null;
847            if (outside)
848                return entry.outside;
849            else
850                return entry.inside;
851                }
852
853                public ArrayList<ConnectionSetEntry> getFlowVariables(String prefix) {
854                        ArrayList<ConnectionSetEntry> cses = new ArrayList<ConnectionSetEntry>();
855                        for (ConnectionSet set : list) {
856                                cses.addAll(set.getFlowVariables(prefix));             
857                        }
858                        return cses;
859                }
860               
861                public void disconnectFromInstanceTree() {
862                        for (ConnectionSet set : list)
863                                set.disconnectFromInstanceTree();
864            if (graph != null) 
865                graph.disconnectFromInstanceTree();
866                        equalityConstraints = null;
867                }
868               
869                public void generateEqualityConstraints(Flattener f) {
870                        for (EqualityConstraintConnection ecc : equalityConstraints)
871                                ecc.generate(f);
872                }
873               
874                public String printConnectionSets() {
875               
876                        StringBuffer str = new StringBuffer();
877                       
878                        str.append("Connection sets: " + list.size() + " sets\n");
879                       
880                        // Print connection sets
881                        for(ConnectionSet set : list) {
882                                str.append(set);
883                        }
884
885                        return str.toString();
886                }
887        }
888
889
890    public class ConnectionSetEntry implements Comparable<ConnectionSetEntry> {
891
892        private InstComponentDecl cd;
893        private boolean outside;
894        private FAccess access;
895        private String prefix;
896        private String str;
897        private String[] scalarNames;
898
899        public static ConnectionSetEntry create(InstComponentDecl cd, boolean outside, FAccess access) {
900            if (cd.isFlow()) {
901                return new FlowConnectionSetEntry(cd, outside, access);
902            }
903            if (cd.isStream()) { 
904                return new StreamConnectionSetEntry(cd, outside, access);
905            }
906            return new ConnectionSetEntry(cd, outside, access);
907        }
908
909        private ConnectionSetEntry(InstComponentDecl cd, boolean outside, FAccess access) {
910            //log.debug("Created ConnectionSetEntry: " + cd.name());
911            this.cd = cd;
912            this.outside = outside;
913            this.access = access;
914            prefix = null;
915        }
916
917        public void disconnectFromInstanceTree() {
918            cd = null;
919        }
920
921        public boolean isOutside() {
922            return outside;
923        }
924
925        public boolean isInside() {
926            return !outside;
927        }
928
929        public InstComponentDecl getVar() {
930            return cd;
931        }
932
933        public boolean isFlow() {
934            return false;
935        }
936
937        public boolean isStream() {
938            return false;
939        }
940
941        public String name() {
942           return access.name();
943        }
944       
945        public String[] names() {
946            if (scalarNames != null)
947                return scalarNames;
948            else
949                return new String[] {name()};
950        }
951
952        public String prefix() {
953            if (prefix == null) 
954                prefix = access.copyPrefix().name();
955            return prefix;
956        }
957
958        public boolean equals(String name, boolean outside) {
959            if (outside != this.outside)
960                return false;
961            if (scalarNames != null) {
962                for (String scalarName : scalarNames)
963                    if (name.equals(scalarName))
964                        return true;
965                return false;
966            } else {
967                return name.equals(name());
968            }
969        }
970
971        public String toString() {
972            if (str == null)
973                str = access + (outside ? " (o)" : " (i)");
974            return str;
975        }
976
977        public FAccess getFAccess() {
978            return access;
979        }
980
981        public FAccessExp createFAccessExp() {
982            return new FAccessExp(access.treeCopy());
983        }
984
985        /**
986         * Create an FAccessExp that is an access to a variable in this entry, that is connected to
987         * the variable named <code>name</code> in <code>other</code>.
988         */
989        public FAccessExp createCommonAccessExp(String name, ConnectionSetEntry other) {
990            if (other == this)
991                return new FAccessExp(name); 
992            if (scalarNames == null || other.scalarNames == null)
993                return createFAccessExp();
994            int i;
995            for (i = 0; i < other.scalarNames.length && !other.scalarNames[i].equals(name); i++);
996            return (i < scalarNames.length) ? new FAccessExp(scalarNames[i]) : createFAccessExp();
997        }
998
999        /**
1000         * Create a zero expression suitable for this entry.
1001         */
1002        public FExp createZeroExp(Flattener f) {
1003            FType t = cd.type();
1004            if (access.hasFArraySubscripts() && access.getFArraySubscripts().accessNdims() == 0) {
1005                t = t.scalarType();
1006            }
1007            return t.flattenZeroLiteral(f);
1008        }
1009
1010        /**
1011         * Create an equation setting the variable of this entry to zero.
1012         */
1013        public FAbstractEquation createZeroEquation(Flattener f) {
1014            return new FEquation(createFAccessExp(), createZeroExp(f));
1015        }
1016
1017        /**
1018         * Create an access to the var of this entry and add or subtract it to/from e.
1019         *
1020         * Used to build up flow equations.
1021         */
1022        public FExp buildFlow(Flattener f, FExp e) {
1023            return createFAccessExp().appendSum(f, e, outside, cd.type());
1024        }
1025
1026        public int hashCode() {
1027            return toString().hashCode();
1028        }
1029
1030        /**
1031         * Create a new connection set entry referring to a specific cell of the variable this refers to.
1032         *
1033         * Assumes that the variable is an array and that <code>i</code> is suitable.
1034         */
1035        public ConnectionSetEntry specifyCell(Index i) {
1036            InstComponentDecl cell = cd.specify(i);
1037            return ConnectionSetEntry.create(cell, outside, cell.getFAccess(i));
1038        }
1039
1040        public boolean equals(Object o) {
1041            return o instanceof ConnectionSetEntry && toString().equals(o.toString());
1042        }
1043   
1044        public int compareTo(ConnectionSetEntry cse) {
1045            return toString().compareTo(cse.toString());
1046        }
1047
1048        /**
1049         * Create an access expression to the associated flow variable.
1050         *
1051         * Only valid for stream connection entries.
1052         */
1053        public FExp createFlowCommonAccessExp() {
1054            throw new UnsupportedOperationException("Only supported for stream connection sets");
1055        }
1056
1057        /**
1058         * Get the epsilon to use when calculating flows, based on the associated flow variable's nominal value.
1059         *
1060         * Only valid for stream connection entries.
1061         */
1062         public double flowNominal() {
1063             throw new UnsupportedOperationException("Only supported for stream connection sets");
1064        }
1065
1066         /**
1067          * Check if this entry should contribute when calculating streams.
1068          *
1069          * Only valid for stream connection entries.
1070          */
1071          public boolean contributesToStream() {
1072              throw new UnsupportedOperationException("Only supported for stream connection sets");
1073        }
1074
1075
1076        private static class FlowConnectionSetEntry extends ConnectionSetEntry {
1077
1078            public FlowConnectionSetEntry(InstComponentDecl cd, boolean outside, FAccess access) {
1079                super(cd, outside, access);
1080            }
1081
1082            public boolean isFlow() {
1083                return true;
1084            }
1085
1086        }
1087
1088        private static class StreamConnectionSetEntry extends ConnectionSetEntry {
1089
1090            private FExp flowExp;
1091            private double nominal = 1;
1092            private boolean contribute = true;
1093
1094            public StreamConnectionSetEntry(InstComponentDecl cd, boolean outside, FAccess access) {
1095                super(cd, outside, access);
1096                InstComponentDecl flow = cd.myFlowVar();
1097                flowExp = new FAccessExp(flow.getFAccess().treeCopy());
1098                try {
1099                    CValue cval = flow.nominalAttributeCValue();
1100                    if (cval.hasRealValue()) {
1101                        nominal = Math.abs(cval.realValue());
1102                    }
1103                } catch (ConstantEvaluationException e) {}
1104                try {
1105                    CValue cval = isOutside() ? flow.maxAttributeCValue() : flow.minAttributeCValue();
1106                    if (cval.hasRealValue()) {
1107                        double val = cval.realValue();
1108                        contribute = isOutside() ? (val > 0) : (val < 0);
1109                    }
1110                } catch (ConstantEvaluationException e) {}
1111            }
1112
1113            public boolean isStream() {
1114                return true;
1115            }
1116
1117            public FExp createFlowCommonAccessExp() {
1118                return flowExp.fullCopy();
1119            }
1120
1121            public double flowNominal() {
1122                return nominal;
1123            }
1124
1125            public boolean contributesToStream() {
1126                return contribute;
1127            }
1128
1129        }
1130
1131    }
1132
1133
1134    /**
1135     * Connect the variables referenced in a connect or branch statement in the connection set manager.
1136     *
1137     * @param right   the other access
1138     * @param prefix  the prefix to use when flattening names
1139     * @param csm     the connection set manager to add variables to
1140     * @param source  the originating connect or branch statement
1141     */
1142    public void InstAccess.connectTo(InstAccess right, FAccess prefix, ConnectionSetManager csm, ConnectionEdge source) {
1143       
1144        if (!csm.isExpandableConnectorsDone() && 
1145                (isExpandableConnectorPart() || right.isExpandableConnectorPart())) {
1146            /* We currently allow connecting two declared members of expandable connectors
1147             * directly, and in that case we need to call addIntroducingConnection both ways.
1148             * It is not entirely clear if that is allowed by the spec.
1149             */
1150            if (isExpandableConnectorPart()) {
1151                csm.getExpandable().addIntroducingConnection(this, right, prefix, source);
1152            }
1153            if (right.isExpandableConnectorPart()) {
1154                csm.getExpandable().addIntroducingConnection(right, this, prefix, source);
1155            }
1156        } else {
1157            boolean leftOutside  = isOutsideConnector();
1158            boolean rightOutside = right.isOutsideConnector();
1159            InstComponentDecl leftComp  = lookupEvaluatingIndices();
1160            InstComponentDecl rightComp = right.lookupEvaluatingIndices();
1161           
1162            if (isArray() && !leftComp.isOverconstrainedConnection(rightComp)) {
1163                Indices leftInd = indices();
1164                Indices rightInd = right.indices();
1165                for (Index[] i : new ParallelIterable<Index>(new Index[2], leftInd, rightInd)) {
1166                    Index leftI = leftInd.translate(i[0]);
1167                    Index rightI = rightInd.translate(i[1]);
1168                    InstComponentDecl leftCompCell = lookupWithIndex(leftI);
1169                    InstComponentDecl rightCompCell = right.lookupWithIndex(rightI);
1170                    FAccess leftCellName  = leftCompCell.getFAccess(leftI);
1171                    FAccess rightCellName = rightCompCell.getFAccess(rightI);
1172                    connectCells(csm, source, prefix, 
1173                                 leftCompCell,  leftOutside,  leftCellName, 
1174                                 rightCompCell, rightOutside, rightCellName);
1175                }
1176            } else {
1177                FAccess leftName  = leftComp.getFAccess(accessIndex());
1178                FAccess rightName = rightComp.getFAccess(right.accessIndex());
1179                connectCells(csm, source, prefix, 
1180                             leftComp,  leftOutside,  leftName, 
1181                             rightComp, rightOutside, rightName);
1182            }
1183        }
1184    }
1185
1186    /**
1187     * Connect the variables referenced in a connect or branch statement in the connection set manager,
1188     * for a specific cell of the accesses.
1189     *
1190     * @param right   the other access
1191     * @param prefix  the prefix to use when flattening names
1192     * @param csm     the connection set manager to add variables to
1193     * @param source  the originating connect or branch statement
1194     */
1195    public static void InstAccess.connectCells(
1196            ConnectionSetManager csm, ConnectionEdge source, FAccess prefix, 
1197            InstComponentDecl leftComp,  boolean leftOutside,  FAccess leftName, 
1198            InstComponentDecl rightComp, boolean rightOutside, FAccess rightName) {
1199        if (!csm.isExpandableConnectorsDone() && leftComp.isExpandableConnector()) {
1200            csm.getExpandable().addSpanningConnection(leftComp, rightComp, prefix, source);
1201        } else {
1202            ConnectionSetEntry leftEntry = ConnectionSetEntry.create(leftComp, leftOutside, leftName);
1203            ConnectionSetEntry rightEntry = ConnectionSetEntry.create(rightComp, rightOutside, rightName);
1204            leftComp.connectTo(leftEntry, rightEntry, prefix, csm, source, true);
1205        }
1206    }
1207
1208    /**
1209     * Helper method for constructing FAccesses for connection sets
1210     */
1211    public FAccess InstComponentDecl.getFAccess(Index i) {
1212        FAccess res = getFAccess();
1213        if (isArray()) {
1214            if (i.ndims() > 0) {
1215                res = res.copyAndAddFas(i.subIndex(i.ndims() - ndims()).createFArraySubscripts());
1216            } else {
1217                res = res.copyAndAddFas(expandedSubscripts());
1218            }
1219        }
1220        return res;
1221    }
1222   
1223    syn Index InstAccess.accessIndex() = hasFArraySubscripts() ?
1224            getFArraySubscripts().createIndex() :
1225            Index.NULL;
1226
1227    syn Indices InstAccess.accessIndices() = indices().translated();
1228
1229    /**
1230     * Connect the variables referenced in a connect or branch statement in the connection set manager.
1231     *
1232     * @param left        describes current part of the left access
1233     * @param right       describes current part of the right access
1234     * @param prefix      the prefix to use when flattening names
1235     * @param csm         the connection set manager to add variables to
1236     * @param source      the originating connect or branch statement
1237     * @param buildGraph  if true, pass instances of overconstrained types to overconstrained connection graph
1238     */
1239    public void InstComponentDecl.connectTo(ConnectionSetEntry left, ConnectionSetEntry right, 
1240            FAccess prefix, ConnectionSetManager csm, ConnectionEdge source, boolean buildGraph) {
1241        if (!isDisabled() && !right.getVar().isDisabled()) {
1242            if (buildGraph && isOverconstrainedConnection(right.getVar())) {
1243                csm.getGraph().addConnection(left, right, prefix, source);
1244            } else if (isArray()) {
1245                for (Index i : indices()) {
1246                    ConnectionSetEntry leftEntry = left.specifyCell(i);
1247                    ConnectionSetEntry rightEntry = right.specifyCell(i);
1248                    leftEntry.getVar().connectTo(leftEntry, rightEntry, prefix, csm, source, buildGraph);
1249                }
1250            } else if (isOperatorRecord()) {
1251                connectToAsPrimitive(left, right, prefix, csm, source, buildGraph);
1252            } else {
1253                SortedSet<InstComponentDecl> rightChildren = right.getVar().containedInstComponents();
1254                for (InstComponentDecl leftComp : containedInstComponents()) {
1255                    SortedSet<InstComponentDecl> rightTail = rightChildren.tailSet(leftComp);
1256                    if (rightTail.size() > 0) {
1257                        InstComponentDecl rightComp = rightTail.first();
1258                        FAccess leftName  = leftComp.getFAccess(Index.NULL);
1259                        FAccess rightName = rightComp.getFAccess(Index.NULL);
1260                        ConnectionSetEntry leftEntry = ConnectionSetEntry.create(leftComp, left.isOutside(), leftName);
1261                        ConnectionSetEntry rightEntry = ConnectionSetEntry.create(rightComp, right.isOutside(), rightName);
1262                        leftComp.connectTo(leftEntry, rightEntry, prefix, csm, source, buildGraph);
1263                    }
1264                }
1265            }
1266            csm.countCardinality(left.getFAccess().scalarName());
1267            csm.countCardinality(right.getFAccess().scalarName());
1268        }
1269    }
1270
1271    public void InstPrimitive.connectTo(ConnectionSetEntry left, ConnectionSetEntry right, 
1272            FAccess prefix, ConnectionSetManager csm, ConnectionEdge source, boolean buildGraph) {
1273        if (!isDisabled() && !right.getVar().isDisabled())
1274            connectToAsPrimitive(left, right, prefix, csm, source, buildGraph);
1275    }
1276
1277    public void InstComponentDecl.connectToAsPrimitive(ConnectionSetEntry left, ConnectionSetEntry right, 
1278            FAccess prefix, ConnectionSetManager csm, ConnectionEdge source, boolean buildGraph) {
1279        if (left.equals(right)) {
1280            source.warning("Ignored connection from connector to itself");
1281        } else {
1282            if (buildGraph && isOverconstrainedConnection(right.getVar())) {
1283                csm.getGraph().addConnection(left, right, prefix, source);
1284            } else {
1285                // In the special case of members of expandable connectors, we need each cell separately.
1286                if (isArray() && (isExpandableConnectorMember() || right.getVar().isExpandableConnectorMember()) && 
1287                        !left.getFAccess().hasScalarSubscripts()) 
1288                    for (Index i : indices())
1289                        csm.addVars(left.specifyCell(i), right.specifyCell(i));
1290                else
1291                    csm.addVars(left, right);
1292            }
1293            csm.countCardinality(left.getFAccess().scalarName());
1294            csm.countCardinality(right.getFAccess().scalarName());
1295        }
1296    }
1297
1298    syn boolean FAccess.hasScalarSubscripts() {
1299        FArraySubscripts fas = getFArraySubscripts();
1300        if (fas == null)
1301            return false;
1302        for (Subscript s : fas.subscripts())
1303            if (s.ndims() > 0)
1304                return false;
1305        return true;
1306    }
1307
1308    syn boolean InstComponentDecl.isOverconstrainedConnection(InstComponentDecl right) =
1309            isOverconstrainedType() && right.isOverconstrainedType();
1310
1311        syn boolean InstAccess.isOutsideConnector() = getFirstInstAccess().myInstComponentDecl().isConnector();
1312       
1313       
1314        /**
1315         * Traverse tree and build connection sets and overconstranined connection graph from relevant constructs.
1316         *
1317         * @param prefix   the prefix to use when flattening names
1318         * @param csm      the connection set manager to add variables to
1319         * @param connect  if false, then we are in a dead branch, and shouldn't change sets or graph
1320         */
1321        public void ASTNode.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1322                for (ASTNode n : this) 
1323                        n.buildConnectionSets(prefix, csm, connect);
1324        }
1325
1326    public void InstNode.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1327        prefix = getFAccess();
1328        for (FAbstractEquation ae : getFAbstractEquations()) {
1329            ae.buildConnectionSets(prefix, csm, connect);
1330        }
1331
1332        getInstComponentDeclList().buildConnectionSets(prefix, csm, connect);
1333        getInstExtendsList().buildConnectionSets(prefix, csm, connect);
1334        }
1335
1336    public void InstClassDecl.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1337        super.buildConnectionSets(prefix, csm, connect);
1338        getInstGeneratedInners().buildConnectionSets(prefix, csm, connect);
1339    }
1340
1341        public void InstComponentDecl.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1342                if (useInFlattening()) 
1343                        super.buildConnectionSets(prefix, csm, connect);
1344        }
1345
1346    public void InstAssignable.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1347        if (useInFlattening() && hasBindingFExp())
1348            getBindingFExp().buildConnectionSets(prefix, csm, connect);
1349        if (isOperatorRecord())
1350            buildConnectionSetsAsPrimitive(prefix, csm, connect);
1351        else
1352            super.buildConnectionSets(prefix, csm, connect);
1353    }
1354
1355    public void InstPrimitive.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1356        buildConnectionSetsAsPrimitive(prefix, csm, connect);
1357        super.buildConnectionSets(prefix, csm, connect);
1358    }
1359
1360    public void InstComponentDecl.buildConnectionSetsAsPrimitive(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1361        if (useInFlattening() && (isFlow() || isStream())) {
1362            FAccess access = getFAccess(Index.NULL);
1363            csm.addFlowVar(this, false, access);
1364            if (inExpandableConnector()) {
1365                csm.addFlowVar(this, true, access);
1366            }
1367        }
1368    }
1369
1370    public void FIfEquation.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1371        boolean all = true;
1372        boolean test = false;
1373        try {
1374            CValue cval = getTest().ceval();
1375            if (cval.hasBooleanValue()) {
1376                test = cval.booleanValue();
1377                all = false;
1378            }
1379        } catch (ConstantEvaluationException e) {
1380        }
1381        getTest().buildConnectionSets(prefix, csm, connect);
1382        for (FAbstractEquation equ : getFAbstractEquations())
1383            equ.buildConnectionSets(prefix, csm, (all || test) && connect);
1384        if (hasElse())
1385            getElse().buildConnectionSets(prefix, csm, (all || !test) && connect);
1386    }
1387
1388        public void InstForClauseE.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1389                Indices indices = Indices.create(getInstForIndexs());
1390                for (Index i : indices) {
1391                        int j = 0;
1392                        int[] ii = indices.translate(i).index();
1393                        for (InstForIndex fi : getInstForIndexs()) {
1394                                fi.getInstPrimitive().setLocalCachedEvaluationValue(CValueInteger.valueOf(ii[j]));
1395                                j++;
1396                        }
1397                        for (FAbstractEquation equ : getFAbstractEquations())
1398                            equ.buildConnectionSets(prefix, csm, connect);
1399                        getFAbstractEquations().flushAllRecursive();
1400                }
1401                for (InstForIndex fi : getInstForIndexs()) {
1402                        fi.getInstPrimitive().setLocalCachedEvaluationValue(null);
1403                        fi.buildConnectionSets(prefix, csm, connect);
1404                }
1405        }
1406
1407    public void FConnectClause.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1408        if (!isDisabled() && connect) {
1409            InstAccess left  = getConnector1();
1410            InstAccess right = getConnector2();
1411            left.connectTo(right, prefix, csm, this);
1412        }
1413    }
1414
1415    syn boolean FConnectClause.isDisabled() = getConnector1().isDisabled() || getConnector2().isDisabled();
1416
1417}
1418
1419aspect Cardinality {
1420   
1421    private Map<String,Enumerator> ConnectionSetManager.cardinality = null;
1422   
1423    public void ConnectionSetManager.countCardinality(String name) {
1424        if (cardinality == null)
1425            cardinality = new HashMap<String,Enumerator>();
1426        Enumerator e = cardinality.get(name);
1427        if (e == null)
1428            cardinality.put(name, new Enumerator(1));
1429        else
1430            e.next();
1431    }
1432   
1433    public int ConnectionSetManager.getCardinality(String name) {
1434        if (cardinality == null)
1435            return 0;
1436        Enumerator e = cardinality.get(name);
1437        return (e == null) ? 0 : e.peek();
1438    }
1439
1440    // Can only be calculated after flattening - give dummy value before that to prevent error messages about structural parameters for cardinality()
1441    syn int FExp.cardinalityValue() {
1442        throw new UnsupportedOperationException();
1443    }
1444    eq InstAccessExp.cardinalityValue() = 1;
1445    eq FAccessExp.cardinalityValue()    = getFAccess().cardinalityValue();
1446
1447    syn int FAccess.cardinalityValue() = myFClass().getConnectionSetManager().getCardinality(scalarName());
1448
1449}
Note: See TracBrowser for help on using the repository browser.