source: trunk/Compiler/ModelicaFlatTree/src/jastadd/ConstantEvaluation/ExternalConstantEvaluation.jrag @ 13719

Last change on this file since 13719 was 13719, checked in by Christian Andersson, 2 months ago

Recommitted changeset:13700 to trunk with two bug fixes. Related to ticket:5837

File size: 13.6 KB
Line 
1/*
2    Copyright (C) 2009-2017 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
17
18import java.io.BufferedReader;
19import java.io.BufferedWriter;
20import java.io.FileNotFoundException;
21import java.io.InputStreamReader;
22import java.io.IOException;
23import java.io.OutputStreamWriter;
24import java.util.Map;
25import java.util.Timer;
26import java.util.TimerTask;
27
28import org.jmodelica.common.evaluation.ExternalFunctionCompiler;
29import org.jmodelica.common.evaluation.ExternalFunction;
30import org.jmodelica.common.evaluation.ExternalProcessCache;
31import org.jmodelica.common.evaluation.ExternalProcessCacheImpl;
32import org.jmodelica.common.evaluation.ExternalProcessMultiCache;
33import org.jmodelica.common.evaluation.FailedExternalFunction;
34import org.jmodelica.common.evaluation.ProcessCommunicator;
35
36aspect ExternalConstantEvaluation {
37   
38    public interface ExternalArgument {
39        CValue ceval();
40        FType type();
41       
42        String name_C();
43        boolean isOutput();
44    }
45   
46    public interface CommonVariableDecl extends ExternalArgument {}
47    FExp implements ExternalArgument;
48   
49    syn boolean FExp.isOutput() = false;
50   
51    class ModelicaCompiler {}
52   
53    ModelicaCompiler   implements ExternalFunctionCompiler<ExternalArgument, FExternalStmt>;
54    FExternalStmt      implements ExternalProcessMultiCache.External<ExternalArgument>;
55    ExternalArgument   extends    ExternalProcessMultiCache.Variable<CValue,FType>;
56    CValue             implements ExternalProcessMultiCache.Value;
57    FType              implements ExternalProcessMultiCache.Type<CValue>;
58   
59    public class ExternalFunctionCache extends ExternalProcessMultiCache<ExternalArgument, CValue, FType, FExternalStmt> {
60        public ExternalFunctionCache(ModelicaCompiler mc) {
61            super(mc);
62        }
63    }
64   
65    /**
66     * Check if this external function can be evaluated. Throw ConstantEvaluationException otherwise
67     */
68    public void FExternalStmt.checkCanEvaluate(AlgorithmEvaluator evaluator, Map<ExternalArgument, CValue> values) throws ConstantEvaluationException {
69        if (evaluator.externalEvaluation() == 0) {
70            throw new ConstantEvaluationException(null, "Could not evaluate external function, external evaluation disabled");
71        }
72        for (FExp arg : getArgs()) {
73            if (!arg.type().externalValid()) {
74                throw new ConstantEvaluationException(null, "Could not evaluate external function, invalid argument type");
75            }
76        }
77        if (hasReturnVar() && !getReturnVar().type().externalValid()) {
78            throw new ConstantEvaluationException(null, "Could not evaluate external function, invalid return type");
79        }
80        Collection<ExternalArgument> outputs = varsToDeserialize();
81        for (ExternalArgument arg : values.keySet()) {
82            if (!outputs.contains(arg)) {
83                if (values.get(arg).isPartlyUnknown()) {
84                    throw new ConstantEvaluationException(null, "Could not evaluate external function, unknown values in arguments");
85                }
86            }
87        }
88    }
89
90    /**
91     * Check if this external function should be cached as a live process.
92     */
93    syn int FExternalStmt.processLimit() =
94            myOptions().external_constant_evaluation_max_proc.getValue();
95   
96    syn boolean FExternalStmt.dynamicEvaluatorEnabled() = 
97            myOptions().external_constant_evaluation_dynamic.getValue()
98            && !externalObjectsToSerialize().iterator().hasNext();
99   
100    /**
101     * Returns a single scalar external object which can be cached. If there is not exactly
102     * one scalar external object, return null.
103     */
104    syn ExternalArgument FExternalStmt.cachedExternalObject() {
105        ExternalArgument eo = null;
106        for (ExternalArgument cvd : varsToSerialize()) {
107            if (cvd.type().isExternalObject() && cvd.type().isScalar()) {
108                if (eo != null) {
109                    return null;
110                } else {
111                    eo = cvd;
112                }
113            }
114        }
115        return eo;
116    }
117   
118    /**
119     * Mark external object CValue with name of external object. Used to track origin of CValue.
120     */
121    public void CValue.markExternalObject(String name) {
122       
123    }
124   
125    private String CValueExternalObject.marked = null;
126    public void CValueExternalObject.markExternalObject(String name) {
127        if (marked == null) {
128            marked = name;
129        }
130    }
131   
132    /**
133     * Get name of external object instance which this CValue represents.
134     */
135    public String CValue.getMarkedExternalObject() {
136        throw new ConstantEvaluationException();
137    }
138   
139    public String CValueExternalObject.getMarkedExternalObject() {
140        if (marked == null) {
141            return super.getMarkedExternalObject();
142        }
143        return marked;
144    }
145   
146    /**
147     * Evaluate this statement as an external function constructor call. Stores evaluated
148     * inputs in a CValueExternalObject.
149     */
150    public int FExternalStmt.evaluateConstructor(Map<CommonVariableDecl, CValue> values) {
151        ArrayList<FExp> args = myConstructorArgs();
152        CValue[] vals = new CValue[args.size()];
153        for (int i = 0; i < args.size(); i++)
154            vals[i] = args.get(i).ceval();
155        values.put(myConstructorOutput(), new CValueExternalObject(vals));
156        return EVAL_CONT;
157    }
158   
159    inh boolean FExternalStmt.isConstructorStmt();
160    eq Root.getChild().isConstructorStmt() = false;
161    eq FFunctionDecl.getChild().isConstructorStmt() = isConstructor();
162    eq InstClassDecl.getChild().isConstructorStmt() = isConstructor();
163   
164    inh boolean FExternalStmt.isDestructorStmt();
165    eq Root.getChild().isDestructorStmt() = false;
166    eq FFunctionDecl.getChild().isDestructorStmt() = isDestructor();
167    eq InstClassDecl.getChild().isDestructorStmt() = isDestructor();
168   
169    /**
170     * Retrieve {@link ExternalFunction} object which represents the external function
171     * this statement refers to.
172     */
173    public ExternalFunction<ExternalArgument, CValue> FExternalStmt.myExternalFunction() {
174        ExternalFunctionCache efc = root().getUtilInterface().getExternalFunctionCache();
175        if (efc == null) {
176            return FailedExternalFunction.<ExternalArgument, CValue, FType, FExternalStmt>failedEval(
177                    root().getUtilInterface().getModelicaCompiler(), 
178                    this, "external function cache unavailable", false);
179        }
180        return efc.getExternalProcessCache(getLibTopPackagePath()).getExternalFunction(this);
181    }
182   
183    /**
184     * Evaluate this external statement.
185     */
186    public int FExternalStmt.evaluateExternal(AlgorithmEvaluator evaluator) {
187       
188        Map<ExternalArgument, CValue> values = new LinkedHashMap<>();
189        for (ExternalArgument arg : varsToSerialize()) {
190            values.put(arg, arg.ceval());
191        }
192       
193        checkCanEvaluate(evaluator, values);
194       
195        if (isConstructorStmt()) {
196            return evaluateConstructor(evaluator.getValues());
197        }
198       
199        int res = 0;
200        int timeout = evaluator.externalEvaluation();
201        ExternalFunction<ExternalArgument,CValue> ef = myExternalFunction();
202        String error = null;
203        try {
204            res = ef.evaluate(this, values, timeout);
205            if (res != 0) {
206                error = "process returned '" + res + "'";
207            }
208        } catch (IOException e) {
209            error = "error in process communication: '"+ e.getMessage() + "'";
210        }
211       
212        if (error != null) {
213            throw new ConstantEvaluationException(null, FailedExternalFunction.failedEvalMsg(getName(), error));
214        }
215       
216        for (ExternalArgument output : varsToDeserialize()) {
217            evaluator.getValues().put((CommonVariableDecl)output, values.get(output));
218        }
219       
220        return EVAL_CONT;
221    }
222   
223    public String ModelicaCompiler.compileExternal(FExternalStmt ext) throws FileNotFoundException, CcodeCompilationException {
224        String executable = null;
225        if (outDir == null)
226            setRandomOutDir();
227        String source = ext.getName().replace(".", "_");
228        TargetObject target = createTargetObject("ceval", "0.1");
229        Set<String> incDirs = new LinkedHashSet<String>();
230        Set<String> libs    = new LinkedHashSet<String>();
231        Set<String> libDirs = new LinkedHashSet<String>();
232       
233        ext.externalDependencies(null, incDirs, libs, libDirs);
234       
235        OptionRegistry options = ext.myOptions();
236        ModulesSettings modulesSettings = createModulesSettings(options);
237       
238        target.getTemplates(options).generateCFiles(ModelicaCompiler.this, null, createCGenerator(ext), sourceDir, source);
239       
240        CCompilerDelegator ccompiler = getCCompiler();
241        ccompiler.setModuleLibraryNames(modulesSettings.getLibraryNames());
242       
243        CCompilerArguments ccArgs = new CCompilerArguments(source, options, target,
244                libs, libDirs, incDirs);
245        executable = ccompiler.compileCCodeLocal(ModelicaCompiler.log, ccArgs, outDir);
246        new File(sourceDir, source + ".c").delete();
247        return executable;
248    }
249}
250
251aspect ExternalConstantEvaluationCaching {
252   
253    protected ExternalFunctionCache ModelicaCompiler.externalFunctionCache = new ExternalFunctionCache(this);
254   
255    public ExternalFunctionCache ModelicaCompiler.getExternalFunctionCache() {
256        return externalFunctionCache;
257    }
258}
259
260aspect ExternalProcessCommunication {
261   
262    /**
263     * Print this constant value to <code>buff</code>
264     */
265    public void CValue.serialize(BufferedWriter buff) throws IOException {
266        throw new IOException("Unsupported type to serialize '" + getClass().getSimpleName() + "'");
267    }
268   
269    public void CValueUnknown.serialize(BufferedWriter buff) throws IOException {
270        throw new IOException("Uninitialized value when expecting initialized");
271    }
272    public void CValueArray.serialize(BufferedWriter buff) throws IOException {
273        for (int s : size().size) {
274            buff.write("" + s + "\n");
275        }
276        for (Index i : indices()) {
277            getCell(i).serialize(buff);
278        }
279    }
280    public void CValueRecord.serialize(BufferedWriter buff) throws IOException {
281        for (CValue value : values) {
282            value.serialize(buff);
283        }
284    }
285    public void CValueReal.serialize(BufferedWriter buff) throws IOException {
286        buff.write(Double.toString(realValue()));
287        buff.write("\n");
288    }
289    public void CValueInteger.serialize(BufferedWriter buff) throws IOException {
290        buff.write(Integer.toString(intValue()));
291        buff.write("\n");
292    }
293    public void CValueBoolean.serialize(BufferedWriter buff) throws IOException {
294        buff.write(booleanValue() ? "1\n" : "0\n");
295    }
296    public void CValueString.serialize(BufferedWriter buff) throws IOException {
297        String s = stringValue();
298        buff.write("" + s.length() + " ");
299        buff.write(s);
300        buff.write("\n");
301    }
302    public void CValueEnum.serialize(BufferedWriter buff) throws IOException {
303        buff.write(Integer.toString(intValue()));
304        buff.write("\n");
305    }
306    public void CValueExternalObject.serialize(BufferedWriter buff) throws IOException {
307        for (CValue v : values) {
308            v.serialize(buff);
309        }
310    }
311   
312   
313    /**
314     * Read a constant value of <code>this</code> type from <code>buff</code>
315     */
316    public CValue FType.deserialize(ProcessCommunicator com) throws IOException {
317        if (isArray()) {
318            CValueArray a = new CValueArray(size().ceval());
319            for (Index i : a.indices()) {
320                a.setCell(i, deserializeScalar(com));
321            }
322            return a;
323        } else {
324            return deserializeScalar(com);
325        }
326    }
327    public CValue FType.deserializeScalar(ProcessCommunicator com) throws IOException {
328        throw new IOException("Unsupported type to deserialize '" + getClass().getSimpleName() + "'");
329    }
330    public CValue FRecordType.deserializeScalar(ProcessCommunicator com) throws IOException {
331        CValueRecord res = new CValueRecord(this);
332        for (FRecordComponentType frct : getComponents()) {
333            res.setMember(frct.getName(), frct.getFType().deserialize(com));
334        }
335        return res;
336    }
337    public CValue FRealType.deserializeScalar(ProcessCommunicator com) throws IOException {
338        return CValueReal.valueOf(com.deserializeReal());
339    }
340    public CValue FIntegerType.deserializeScalar(ProcessCommunicator com) throws IOException {
341        return CValueInteger.valueOf((int) com.deserializeReal());
342    }
343    public CValue FBooleanType.deserializeScalar(ProcessCommunicator com) throws IOException {
344        return CValueBoolean.valueOf(com.deserializeReal() != 0);
345    }
346    public CValue FStringType.deserializeScalar(ProcessCommunicator com) throws IOException {
347        return new CValueString(com.deserializeString());
348    }
349    public CValue FEnumType.deserializeScalar(ProcessCommunicator com) throws IOException {
350        return new CValueEnum(this, (int) com.deserializeReal());
351    }
352}
353
354
Note: See TracBrowser for help on using the repository browser.