source: branches/dev-5819/Compiler/ModelicaCompilerCasADi/src/jastadd/FExpToCasADi.jrag @ 13800

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

#5819 Merged trunk into branch

File size: 26.3 KB
Line 
1/*
2Copyright (C) 2013 Modelon AB
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, version 3 of the License.
6
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10GNU General Public License for more details.
11
12You should have received a copy of the GNU General Public License
13along with this program.  If not, see <http://www.gnu.org/licenses/>.
14*/
15
16import ifcasadi.ifcasadi;
17import ifcasadi.GenericType;
18import ifcasadi.MX;
19import ifcasadi.MXFunction;
20import ifcasadi.MXVector;
21
22aspect FExpToCasADi {
23
24    // Workaround since it's troublesome to wrap the ModelicaCompiler-nested
25    // class TargetObject with jcc
26    public class ModelicaCompiler {
27        public FClass compileModelNoCodeGen(String name[], String cl)
28          throws ModelicaException, FileNotFoundException, IOException, beaver.Parser.Exception {
29            OptionRegistry tempOptions = options.copy();
30            TargetObject target = createTargetObject("nocodegen", null);
31            target.setDefaultOptions(options);
32            try {
33                return compileModel(name, cl, target, null);
34            } finally {
35                options.copyAllOptions(tempOptions);
36            }
37        }
38    }
39
40
41    /******** MXFunction ********/
42   
43    public interface FCallable {
44        public MXFunction toMXFunction();
45    }
46   
47    /**
48     * Creates A MXFunction for this FFunctionDecl. The MXFunction requires a single expression
49     * for all output variables, and only functions for which this is possible are supported.
50     * @return A MXFunction
51     */
52    syn lazy MXFunction FFunctionDecl.toMXFunction() { 
53        MXVector finalExpressions = generateFinalExpressionVector();
54        MXFunction f = new MXFunction(generateInputVector(),pickMXCorrespondingToOutputs(finalExpressions));
55        f.setOption("name",new GenericType(name()));
56        f.init();
57        return f; 
58    }
59   
60    syn MXFunction FFunctionVariable.toMXFunction() {
61        throw new UnsupportedOperationException();
62    }
63   
64    /**
65     * Puts the MX for all function variables in a single vector. Arrays
66     * and records are flattened.
67     * @return A MXVector
68     */
69    MXVector FFunctionDecl.getMXVectorForFuncVars(){
70        MXVector MXVec = new MXVector();
71        for (FFunctionVariable funcVar : getFFunctionVariables()) {
72            MXVector funcVarMXVec = funcVar.asMXVector();
73            for (int i = 0; i < funcVarMXVec.size(); ++i) {
74                MXVec.add(funcVarMXVec.get(i));
75            }
76        }
77        return MXVec;
78    }
79   
80    /**
81     * Calculates an inlined expression for all variables in this FFunctionDecl.
82     * Handles the statements sequentially, and returns a vector with the expressions.
83     * @return A MXVector
84     */
85    MXVector FFunctionDecl.generateFinalExpressionVector() {
86        MXVector allVars = getMXVectorForFuncVars();
87        MXVector expressions = getMXVectorForFuncVars();
88        for (FStatement statement : getFAlgorithm().getFStatementList()) {
89            if (statement instanceof FReturnStmt) {
90                break;
91            }
92            expressions = statement.updateExpressionsAccordingToStatement(expressions, allVars);
93        }
94        return expressions;
95    }
96   
97    /**
98     * Collects the MX for the function variables that occur as inputs in
99     * A MXVector
100     * @return A MXVector
101     */
102    MXVector FFunctionDecl.generateInputVector() {
103        MXVector allVars = getMXVectorForFuncVars();
104        MXVector MXVec = new MXVector();
105        for (FFunctionVariable funcVar : getFFunctionVariables()) {
106            if (funcVar.isInput()) {
107                MXVector funcVarMXVec = funcVar.asMXVector();
108                for (int i = 0; i < funcVarMXVec.size(); ++i) {
109                    MXVec.add(funcVarMXVec.get(i));
110                }
111            }   
112        }
113        return MXVec;
114    }
115       
116    /**
117     * Picks out the MX in the MXVector, that is supplied as input, that
118     * corresponds to variables that occur as output for this function.
119     * Assumes that the variables in the supplied vector is ordered in the
120     * same way as the variables in this function's variable list.
121     * @param A MXVector mixedCausality
122     * @return A MXVector
123     */
124    MXVector FFunctionDecl.pickMXCorrespondingToOutputs(MXVector mixedCausality) {
125        MXVector allVars = getMXVectorForFuncVars();
126        MXVector MXVec = new MXVector();
127        int index = 0;
128        for (FFunctionVariable funcVar : getFFunctionVariables()) {
129            if (funcVar.isOutput()) {
130                for (int i = 0; i < funcVar.asMXVector().size(); ++i) {
131                    MXVec.add(mixedCausality.get(index));
132                    index++;
133                }
134            } else {
135                index += funcVar.asMXVector().size();
136            }   
137        }
138        return MXVec;
139    }
140   
141    /**
142     * Update the supplied expressions to reflect this statement.
143     * @param A MXVector with expressions
144     * @param A MXVector with MX for the function variables
145     * @return A MXVector
146     */
147    MXVector FStatement.updateExpressionsAccordingToStatement(MXVector expressions, MXVector allVars) {
148        return expressions;
149    }
150   
151    /**
152     * Update the supplied expressions to reflect this statement.
153     * @param A MXVector with expressions
154     * @param A MXVector with MX for the function variables
155     * @return A MXVector
156     */
157    MXVector FFunctionCallStmt.updateExpressionsAccordingToStatement(MXVector expressions, MXVector allVars) {   
158        if (getCall().isIgnored()) {
159            return expressions;
160        }
161        if (isIgnoredForCasADi()) {
162            System.err.println("Warning: Ignored statement:\n" + this);
163            return expressions;
164        }
165        MXVector lhsVec = new MXVector();
166        for (FFunctionCallLeft fleft : getLefts()) {
167            if (fleft.hasFExp()) {
168                MXVector fleftExpAsMXVex = fleft.getFExp().toMXVector();
169                for (int i = 0; i < fleftExpAsMXVex.size(); ++i) {
170                    lhsVec.add(fleftExpAsMXVex.get(i));
171                }
172            }
173        }
174        MXVector updatedRhsExpressions = ifcasadi.substitute(getCall().toMXVector(), allVars, expressions);
175        for (int i = 0; i < lhsVec.size(); ++i) {
176            expressions.set(findIndexOfMXInMXVector(lhsVec.get(i), allVars), updatedRhsExpressions.get(i));   
177        }
178        return expressions;
179    }
180   
181    /**
182     * Update the supplied expressions to reflect this statement.
183     * @param A MXVector with expressions
184     * @param A MXVector with MX for the function variables
185     * @return A MXVector
186     */
187    MXVector FAssignStmt.updateExpressionsAccordingToStatement(MXVector expressions, MXVector allVars) {
188        MXVector lhsVec = new MXVector();
189        MX left = getLeft().toMX();
190        if (left == null) {
191            throw new UnsupportedOperationException("The variable on the LHS does not exists: " + toString());
192        }
193        lhsVec.add(left);
194        MXVector rhsVec = getRight().toMXVector();
195       
196        MX updatedRhsExpression = ifcasadi.substitute(rhsVec, allVars, expressions).get(0);
197        int indexInAllCurrVars = findIndexOfMXInMXVector(lhsVec.get(0), allVars);
198        expressions.set(indexInAllCurrVars, updatedRhsExpression);
199        return expressions;
200    }
201   
202    MXVector FIfStmt.updateExpressionsAccordingToStatement(MXVector expressions, MXVector allVars) {
203        throw new UnsupportedOperationException("If-Statements are unsupported (try to rewrite into if-expressions): " + toString());
204    }
205   
206    MXVector FForStmt.updateExpressionsAccordingToStatement(MXVector expressions, MXVector allVars) {
207        for (FStatement stmt : getUnrolledForStmts()) {
208            expressions = stmt.updateExpressionsAccordingToStatement(expressions, allVars);
209        }
210        return expressions;
211    }
212   
213    /**
214     * @param A MX that is searched for
215     * @param A MXVector that is searched in
216     * @return An index >= 0 if successful
217     */
218    int FStatement.findIndexOfMXInMXVector(MX node, MXVector vec){
219        for (int i = 0; i < vec.size(); ++i) {
220            if (vec.get(i).isEqual(node)) {
221                return i;
222            }
223        }
224        return -1;
225    }
226   
227   
228    /******** Equations ********/
229    /** @return An empty MX */
230    syn MX FAbstractEquation.toMXForLhs() = new MX();
231    /** @return An empty MX */
232    syn MX FAbstractEquation.toMXForRhs() = new MX();
233    /** @return A MX the left hand side expression */
234    eq FEquation.toMXForLhs() = getLeft().toMX();
235    /** @return A MX the eight hand side expression */
236    eq FEquation.toMXForRhs()  = getRight().toMX();
237    /** @return A possibly stacked MX for the variables that are to be set by the function call */
238    eq FFunctionCallEquation.toMXForLhs() {
239        MX myLefts = new MX();
240        for (FFunctionCallLeft fleft : getLefts()) {
241            if (fleft.hasFExp()) {
242                MXVector fleftExpAsMXVex = fleft.getFExp().toMXVector();
243                for (int i = 0; i < fleftExpAsMXVex.size(); ++i) {
244                    myLefts.append(fleftExpAsMXVex.get(i));
245                }
246            }
247        }
248        return myLefts;
249    }
250    /** @return A possibly stacked MX for the outputs of the function call */
251    eq FFunctionCallEquation.toMXForRhs() {
252        MXVector rhsVec = getCall().toMXVector();
253        MX returnMX = new MX();
254        for (int i = 0; i < rhsVec.size(); ++i) {
255            returnMX.append(rhsVec.get(i));
256        }
257        return returnMX;
258    }
259   
260   
261    /********* Expressions **********
262     * Expressions are transformed to MX expressions recursively.
263     * The transformation of expressions to MX produces several MX
264     * for some expressions, such as some function calls and FAccessExps.
265     */
266     
267    /**
268     * Returns this expression as A MXVector.
269     * @return A MXVector
270     */ 
271    syn MXVector FExp.toMXVector()  {
272        MXVector MXVec = new MXVector();
273        MXVec.add(toMX());
274        return MXVec;
275    }
276    /**
277     * Returns this expression as A MX. Note that this might
278     * not make sense for some expressions, e.g. function calls with
279     * several outputs and FAccessExp for arrays.
280     * @return A MX
281     */
282    syn MX FExp.toMX() {
283        throw new UnsupportedOperationException("Cannot convert expression to MX: " + toString());
284    }
285   
286    // Arithmetic expressions
287    eq FDotAddExp.toMX() = getLeft().toMX().__add__(getRight().toMX());
288    eq FDotSubExp.toMX() = getLeft().toMX().__sub__(getRight().toMX());
289    eq FDotMulExp.toMX() = getLeft().toMX().__mul__(getRight().toMX());
290    eq FDotDivExp.toMX() = getLeft().toMX().__div__(getRight().toMX());
291   
292    // Trigonometric expression
293    eq FAtan2Exp.toMX() = getFExp().toMX().arctan2(getY().toMX()); 
294    eq FSinExp.toMX()   = getFExp().toMX().sin();
295    eq FSinhExp.toMX()  = getFExp().toMX().sinh();
296    eq FAsinExp.toMX()  = getFExp().toMX().arcsin();
297    eq FCosExp.toMX()   = getFExp().toMX().cos();
298    eq FCoshExp.toMX()  = getFExp().toMX().cosh();
299    eq FAcosExp.toMX()  = getFExp().toMX().arccos();
300    eq FTanExp.toMX()   = getFExp().toMX().tan();
301    eq FTanhExp.toMX()  = getFExp().toMX().tanh();
302    eq FAtanExp.toMX()  = getFExp().toMX().arctan();
303   
304    // Elementary functions 
305    eq FMinExp.toMX() = getX().toMX().fmin(getY().toMX());
306    eq FMaxExp.toMX() = getX().toMX().fmax(getY().toMX());
307    eq FDotPowExp.toMX() = getLeft().toMX().__pow__(getRight().toMX());
308    eq FLogExp.toMX() = getFExp().toMX().log();
309    eq FLog10Exp.toMX() = getFExp().toMX().log10();
310    eq FSqrtExp.toMX() = getFExp().toMX().sqrt();
311    eq FAbsExp.toMX() = getFExp().toMX().fabs();
312    eq FExpExp.toMX() = getFExp().toMX().exp();
313   
314    // Boolean expressions
315    eq FIfExp.toMX() =  ifcasadi.if_else(getIfExp().toMX(), getThenExp().toMX(), getElseExp().toMX());
316    eq FGeqExp.toMX() = getRight().toMX().__le__(getLeft().toMX());
317    eq FGtExp.toMX() = getRight().toMX().__lt__(getLeft().toMX());
318    eq FLeqExp.toMX() = getLeft().toMX().__le__(getRight().toMX());
319    eq FLtExp.toMX() = getLeft().toMX().__lt__(getRight().toMX());
320    eq FEqExp.toMX() = getLeft().toMX().__eq__(getRight().toMX());
321    eq FNeqExp.toMX() = getLeft().toMX().__ne__(getRight().toMX());
322    eq FAndExp.toMX() = getLeft().toMX().logic_and(getRight().toMX());
323    eq FOrExp.toMX() = getLeft().toMX().logic_or(getRight().toMX());
324   
325    // Other expressions
326    eq FSubscriptedExp.toMX() = select().toMX();
327    syn lazy MX FClass.timeMX() = ifcasadi.msym("time");
328    eq FTimeExp.toMX() = myFClass().timeMX();
329    /** @return A MX with the first output, and perhaps only output, for this function call */
330    eq FFunctionCall.toMX() { 
331        return toMXVector().get(0); 
332    }
333    /** @return A MXVector with the outputs from this function call */
334    eq FFunctionCall.toMXVector() {
335        MXFunction f = myFCallable().toMXFunction();
336        MXVector argVec = new MXVector();
337        for (FExp exp : getArgs()) {
338            MXVector expMXVec = exp.toMXVector();
339            for (int i = 0; i < expMXVec.size(); ++i) {
340                argVec.add(expMXVec.get(i));
341            }
342        }
343        // To handle the case where some outputs are not used.
344        return  myLefts().size() > 0 ? retrieveUsedOutputsFromMXFunctionCall(f.call(argVec)) : f.call(argVec);
345    }
346       
347    /** @return A MXVector with the used MX outputs for this function call */
348    MXVector FFunctionCall.retrieveUsedOutputsFromMXFunctionCall(MXVector callVector) {
349        MXVector usedCalls = new MXVector();
350        ArrayList<FFunctionCallLeft> lefts = myLefts();
351        int index = 0;
352        ArrayList<FFunctionCallLeft> myLefts = myLefts();
353        ArrayList<FFunctionVariable> myOutVars = myFCallable().myOutputs();
354        for (int i = 0; i < myLefts.size(); ++i) {
355            if (myLefts.get(i).hasFExp()) {
356                for (int j = 0; j < myLefts.get(i).getFExp().toMXVector().size(); ++j) {
357                    usedCalls.add(callVector.get(index + j));
358                }
359            } 
360            index += myOutVars.get(i).asMXVector().size();
361        }
362        return usedCalls;
363    }
364   
365   
366   
367    /**
368     * Connects the use of a variable in an expression with
369     * the symbolic and lazy MX for that variable.
370     * Note that sometimes FAccessExp points to a whole
371     * matrices or record, and these should be transformed to vectors
372     * of MX instead.
373     * @return A MX
374     */
375    eq FAccessExp.toMX() {
376        if (myFV().inRecord()) {
377            return getParent().getMXVariableFromRecordHashMap(getFAccess().toString());
378        } else if (hasFArraySubscripts() && inFunction()) {
379            int flatIndex = getFArraySubscripts().computeFlattenedIndexBasedOnSizeData(myFV().size());
380            return myFV().asMXVector().get(flatIndex);
381        } else {
382            return myFV().asMXVariable();
383        }
384    }
385   
386    eq FGlobalAccessExp.toMX() {
387        return ceval().buildLiteral().toMX();
388    }
389   
390    /**
391     * Connects the use of a variable in an expression with
392     * the symbolic and lazy MX for that variable.
393     * Note that this function can handle the case when the FAccessExp
394     * points to whole matrices or records, e.g. as outputs of
395     * function calls inside functions.
396     * @return A MX
397     */
398    eq FAccessExp.toMXVector() {
399        if (inFunction() && (size().numElements() > 1 || type().isRecord())) {
400            return myFV().asMXVector();
401        } else {
402            MXVector MXVec = new MXVector();
403            MXVec.add(toMX());
404            return MXVec;
405        }
406    }
407   
408    eq FGlobalAccessExp.toMXVector() {
409        return ceval().buildLiteral().toMXVector();
410    }
411   
412    /**
413     * Returns a zero-based index for flattened arrays and records.
414     * Row-major, e.g. Real[2,2] is indexed as : [1,2] -> 1, [2,1] -> 2
415     */
416    int FArraySubscripts.computeFlattenedIndexBasedOnSizeData(Size size) {
417        int flattenedIndex = 0;
418        ArrayList<Subscript> subs = new ArrayList<>(numSubscript());
419        for (Subscript sub : subscripts()) {
420            subs.add(sub);
421        }
422        int nbrOfSizeDimsZeroBased = subs.size() - 1;
423       
424        try {
425            flattenedIndex += subs.get(nbrOfSizeDimsZeroBased).value() - 1;
426            int base = 1;
427            for (int i = nbrOfSizeDimsZeroBased; i > 0 ; --i) {
428                base*=size.get(i);
429                flattenedIndex +=  base*(subs.get(i - 1).value() - 1);
430            }
431            return flattenedIndex;
432        } catch (ConstantEvaluationException exp) {
433            throw new UnsupportedOperationException("Indexing into arrays with expressions that can't be preevaluated is not supported in CasADiInterface");
434        }
435    }
436   
437    eq FNegExp.toMX() = getFExp().toMX().__neg__();
438    eq FPreExp.toMX() = myFV().asMXVariable();
439    eq FNoEventExp.toMX() = getFExp().toMX();
440    eq FSmoothExp.toMX() = getFExp().toMX();
441    eq FInStreamEpsExp.toMX() = new MX(1e-8);
442   
443    eq FArray.toMXVector() {
444        MXVector MXVec = new MXVector();
445        for (FExp exp : getFExps()) {
446            MXVector expMXVec = exp.toMXVector();
447            for (int i = 0; i < expMXVec.size(); ++i) {
448                MXVec.add(expMXVec.get(i));
449            }
450        }
451        return MXVec;
452    }
453    eq FRecordConstructor.toMXVector() {
454        MXVector MXVec = new MXVector();
455        for (FExp exp : getArgList()) {
456            MXVector argVector = exp.toMXVector();
457            for (int i = 0; i < argVector.size(); ++i) {
458                MXVec.add(argVector.get(i));
459            }
460        }
461        return MXVec;
462    }
463   
464    // Literal expression
465    eq FBooleanLitExpTrue.toMX() = new MX(1);
466    eq FBooleanLitExpFalse.toMX() = new MX(0);
467    eq FStringLitExp.toMX() = ifcasadi.msym(getString());
468    eq FRealLitExp.toMX() = new MX(getValue());
469    eq FIntegerLitExp.toMX() = new MX((double)getValue());
470   
471    /************ Variables ************
472     * Note that Variables are lazy. This is necessary for the CasADi-toolchain.
473     * A variable can occur in different places, e.g. equations, and it is
474     * necessary that it is always the same variable as CasADi is symbolic.
475     */ 
476     
477     /**
478      * For retrieving the MXVector representation of this variable.
479      * Some variables, e.g. arrays can only be represented
480      * as MXVector
481      * @return A MXVector
482      */
483    syn lazy MXVector FAbstractVariable.asMXVector() {
484        MXVector MXVec = new MXVector();
485        MXVec.add(asMXVariable());
486        return MXVec;
487    }
488   
489    /**
490     * For retrieving the MX representation of this variable.
491     * Note that some variables can not be represented as a single MX, e.g.
492     * arrays. These may need to be represented as MXVector.
493     */
494    syn lazy MX FAbstractVariable.asMXVariable();
495    eq UnknownFVariable .asMXVariable() { throw new UnsupportedOperationException("Cannot convert unknown variable to MX"); }
496    eq FEnumLiteral     .asMXVariable() { throw new UnsupportedOperationException("Cannot convert enum literal to MX"); }
497    eq FVariable        .asMXVariable() = ifcasadi.msym(name());
498    eq FFunctionVariable.asMXVariable() = ifcasadi.msym(getFAccess().toString());
499   
500    /**
501     * Retrieves the MXVector for this variable.
502     * Note that this method handles records. MX variables for records
503     * are created by recursive flattening. These MX variables are saved in
504     * a hashmap in the FFunctionDecl, put there via AST traversation. Furthermore
505     * the key for the variables in the hashmap is the same as the FAccess
506     * of the CommonAccess's that later refer to them.
507     * @return A MXVector.
508     */ 
509    eq FFunctionVariable.asMXVector() {
510        MXVector MXVec = new MXVector();
511        if (isArray()) {
512            for (int i = 0; i < size().numElements(); ++i) {
513                MX mx = ifcasadi.msym(getFAccess().toString() + "_" +i);
514                MXVec.add(mx);
515            }
516        } else if (isRecord()) {
517            for (FVariable fvar : myFRecordDecl().getFVariables()) {             
518                ArrayList<String> myFlattenedVariables = new ArrayList<String>();
519                myFlattenedVariables.add(name());
520                myFlattenedVariables = fvar.createFullNestedName(myFlattenedVariables);
521                for (String str : myFlattenedVariables) {
522                    MX mx = ifcasadi.msym(str);
523                    MXVec.add(mx);
524                    getParent().setMXVariableInFunctionDeclRecordVariableMap(str, mx);
525                }
526            }
527        } else {
528            MXVec.add(asMXVariable());
529        }
530        return MXVec;
531    }
532   
533    ArrayList<String> FRecordVariable.createFullNestedName(ArrayList<String> parts) {
534        ArrayList<String> outList = new ArrayList<String>(); 
535        if (size().numElements() > 1) {
536            for (Index ind : size().rangeFArraySubscripts().indices()) {
537                outList.addAll(createFullNestedNameForAllMyVariables(appendStringToAllEntriesInList(parts, "." + name() + ind.toString())));
538            }
539        } else {
540            outList.addAll(createFullNestedNameForAllMyVariables(appendStringToAllEntriesInList(parts, "." + name())));
541       
542        }
543       
544        return outList;
545    }
546       
547    private ArrayList<String> FRecordVariable.createFullNestedNameForAllMyVariables(ArrayList<String> parts) {
548        ArrayList<String> outList = new ArrayList<String>(); 
549        for (FVariable fvar : myFRecordDecl().getFVariables()) {
550            outList.addAll(fvar.createFullNestedName(parts));
551        }
552        return outList;
553    }
554   
555    ArrayList<String> FVariable.createFullNestedName(ArrayList<String> parts) {
556        if (size().numElements() > 1) {
557            ArrayList<String> outList = new ArrayList<String>(size().numElements()*parts.size());
558            for (Index ind : size().rangeFArraySubscripts().indices()) {
559                outList.addAll(appendStringToAllEntriesInList(parts, "." + name() + ind.toString()));
560            }
561            return outList;
562        } else {
563            return appendStringToAllEntriesInList(parts, "." + name());
564        }
565    }
566       
567    ArrayList<String> FVariable.appendStringToAllEntriesInList(ArrayList<String> list, String str) {
568        ArrayList<String> outList = new ArrayList<String>(list.size());
569        for (String string : list) {
570            outList.add(string + str);
571        }
572        return outList;
573    }
574   
575   
576    /**
577     * Returns the binding expression for this variable if there is one, otherwhise null.
578     * @return A MX
579     */
580    syn MX FVariable.findMXBindingExpressionIfPresent() {
581        return hasBindingExp() ? getBindingExp().toMX() :  (hasParameterEquation() ? parameterEquationToMXBindingExpression() : null);
582    }
583   
584    /**
585     * Creates a binding expression for the parameter equation of this variable.
586     * Note that this handles cases where the parameter equation is a function call equation.
587     * @return A MX
588     */
589    syn MX FVariable.parameterEquationToMXBindingExpression() {
590        if (hasParameterEquation() && parameterEquation().hasFunctionCallEquationsWithLefts()) {
591            // E.g. for the case: parameter Real[2] p2 = function(p1);
592            // Need to find which output from the FFunctionCallEquation that
593            // corresponds to this variable.
594            FFunctionCallEquation feq = (FFunctionCallEquation) parameterEquation();
595            MXVector outs = feq.getCall().toMXVector();
596            int myOutIndex = 0;
597           
598            for (FFunctionCallLeft fleft : feq.getLefts()) {
599                if (fleft.hasFExp()) {
600                    MXVector fleftExpAsMXVex = fleft.getFExp().toMXVector();
601                    for (int i = 0; i < fleftExpAsMXVex.size(); ++i) {
602                        if (fleftExpAsMXVex.get(i).isEqual(asMXVariable())) {
603                            return outs.get(myOutIndex);
604                        }
605                        myOutIndex++;
606                    }
607                }
608            }
609        }
610        return hasParameterEquation() ? ((FEquation)parameterEquation()).getRight().toMX() : new MX(); 
611    }
612   
613    /** Is used for handling record variables */
614    private HashMap<String,MX> FFunctionDecl.hashMapWithMXForRecordVariables = new HashMap<String, MX>();
615   
616    /**
617     * Does a recursive AST traversation up to the first encountered FFunctionDecl. The FFunctionDecl has an hash map that contains
618     * MX symbolic variables for records, and the MX for the passed in key (which should be equal to the FAccess of the variable) is returned.
619     * @param A String
620     * @return A MX
621     */
622    syn MX ASTNode.getMXVariableFromRecordHashMap(String key) {
623        if (getParent() != null) {
624            return getParent().getMXVariableFromRecordHashMap(key);
625        } else {
626            return null;
627        }
628    }
629   
630    /**
631     * Retrieves the MX for the record variable with this key (which should be equal to the FAccess of the variable).
632     * @param A String
633     * @return A MX
634     */
635    eq FFunctionDecl.getMXVariableFromRecordHashMap(String key) = hashMapWithMXForRecordVariables.get(key); 
636   
637    /**
638     * Does a recursive AST traversation to the first encountered FFunctionDecl. The FFunctionDecl
639     * has a hash map where the key,value-pair passed in is set. The key should be the FAccess of a
640     * variable  in a record and value its symbolic MX.
641     * @param A String
642     * @param A MX
643     */
644    public void ASTNode.setMXVariableInFunctionDeclRecordVariableMap(String key, MX val) {
645        if (getParent() != null) {
646            getParent().setMXVariableInFunctionDeclRecordVariableMap(key, val);
647        }
648    }
649   
650    /**
651     * Sets the passed in key,value-pair in the map, where the key should be the FAccess
652     * of a variable in a record, and value its symbolic MX.
653     * @param A String
654     * @param A MX
655     */
656    public void FFunctionDecl.setMXVariableInFunctionDeclRecordVariableMap(String key, MX val) {
657        hashMapWithMXForRecordVariables.put(key, val);
658    }
659
660    public boolean FAbstractEquation.isIgnoredForCasADi() { return false; }
661    public boolean FFunctionCallEquation.isIgnoredForCasADi() {
662        // Ignore things that we don't support right now, such as asserts
663        return getNumLeft() == 0;
664    }   
665    public boolean FStatement.isIgnoredForCasADi() { return false; }
666    public boolean FFunctionCallStmt.isIgnoredForCasADi() {
667        // Ignore things that we don't support right now, such as asserts
668        return getNumLeft() == 0;
669    }   
670}
Note: See TracBrowser for help on using the repository browser.