001/* An actor that evaluates matlab expressions with input ports
002 providing variables
003
004 Copyright (c) 1998-2018 The Regents of the University of California and
005 Research in Motion Limited.
006 All rights reserved.
007 Permission is hereby granted, without written agreement and without
008 license or royalty fees, to use, copy, modify, and distribute this
009 software and its documentation for any purpose, provided that the above
010 copyright notice and the following two paragraphs appear in all copies
011 of this software.
012
013 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA OR RESEARCH IN MOTION
014 LIMITED BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
015 INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
016 SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
017 OR RESEARCH IN MOTION LIMITED HAVE BEEN ADVISED OF THE POSSIBILITY OF
018 SUCH DAMAGE.
019
020 THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION LIMITED
021 SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
023 PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
024 BASIS, AND THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION
025 LIMITED HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 ENHANCEMENTS, OR MODIFICATIONS.
027
028 PT_COPYRIGHT_VERSION_2
029 COPYRIGHTENDKEY
030
031 */
032package ptolemy.matlab;
033
034import java.util.HashMap;
035import java.util.Iterator;
036import java.util.Map;
037import java.util.Set;
038import java.util.StringTokenizer;
039
040import ptolemy.actor.Director;
041import ptolemy.actor.IOPort;
042import ptolemy.actor.TypedAtomicActor;
043import ptolemy.actor.TypedIOPort;
044import ptolemy.actor.gui.style.CheckBoxStyle;
045import ptolemy.actor.gui.style.TextStyle;
046import ptolemy.data.BooleanToken;
047import ptolemy.data.DoubleToken;
048import ptolemy.data.IntToken;
049import ptolemy.data.StringToken;
050import ptolemy.data.Token;
051import ptolemy.data.expr.Parameter;
052import ptolemy.data.expr.StringParameter;
053import ptolemy.data.expr.UtilityFunctions;
054import ptolemy.data.expr.Variable;
055import ptolemy.data.type.BaseType;
056import ptolemy.graph.Inequality;
057import ptolemy.kernel.CompositeEntity;
058import ptolemy.kernel.util.IllegalActionException;
059import ptolemy.kernel.util.NameDuplicationException;
060import ptolemy.kernel.util.Workspace;
061import ptolemy.matlab.Engine.ConversionParameters;
062
063///////////////////////////////////////////////////////////////////
064//// Expression
065
066/**
067 On each firing send an expression for evaluation to a matlab {@link
068 Engine}. The expression is any valid matlab expression, e.g.:
069
070 <pre>
071 [out1, out2, ... ] = SomeMatlabFunctionOrExpression( in1, in2, ... );...
072 </pre>
073
074 <p>The expression may include references to the input port names, current
075 time (<i>time</i>), and a count of the firing (<i>iteration</i>). This
076 is similar to <a href="../../ptolemy/actor/lib/Expression.html">Expression</a>.
077 To refer to parameters in scope, use $name or ${name} within
078 the expression.</p>
079
080 <p>The matlab engine is opened (started) during prefire() by the first
081 matlab Expression actor. Subsequent open()s simply increment a use
082 count.</p>
083
084 <p>At the start of fire(), <i>clear variables;clear globals</i> commands are
085 sent to matlab to clear its workspace. This helps detect errors where the
086 matlab expression refers to a matlab variable not initialized from the
087 input ports of this actor instance.</p>
088
089 <p>After the evaluation of the matlab expression is complete, the fire()
090 method iterates through names of output ports and converts matlab
091 variables with corresponding names to Tokens that are sent to the
092 corresponding output ports. Incorrect expressions are usually first
093 detected at this point by not finding the expected variables. If an
094 output port variable is not found in the matlab {@link Engine}, an
095 exception is thrown. The exception description string contains the last
096 stdout of the matlab engine that usually describes the error.</p>
097
098 <p>The {@link #get1x1asScalars} and {@link #getIntegerMatrices} control
099 data conversion (see {@link Engine} and
100 {@link Engine.ConversionParameters}).</p>
101
102 <p>A Parameter named <i>packageDirectories</i> may be added to this actor
103 to augment the search path of the matlab engine during the firing of this
104 actor. The value of this parameter should evaluate to a StringToken,
105 e.g.:
106
107 <pre>
108 "path1, path2, ..."
109 </pre>
110
111 <p> containing a comma-separated list of paths to be prepended to the matlab
112 engine search path before <i>expression</i> is evaluated. The list may
113 contain paths relative to the directory in which ptolemy was started,
114 or any directory listed in the current classpath (in that order, first
115 match wins). See {@link ptolemy.data.expr.UtilityFunctions#findFile(String)}.
116 After evaluation, the previous search path is restored.</p>
117
118 <p>A Parameter named <i>_debugging</i> may be used to turn on debug print
119 statements to stdout from {@link Engine} and the ptmatlab JNI. An IntToken
120 with a value of 1 turns on Engine debug statements, a value of 2 adds
121 ptmatlab debug statements as well.  A value of 0 or the absence of the
122 <i>_debugging</i> parameter yields normal operation.</p>
123
124 <p>For this actor to work, Matlab must be installed on your local
125 machine.  In addition, your environment must be set properly. The
126 <code>$PTII/bin/vergil</code> script does this for you, below are
127 instructions for users, such as Eclipse users, who are not using
128 <code>$PTII/bin/vergil</code>.</p>
129
130 <p>Add the Matlab shared libraries to your the library path. In the examples
131 below <code>$MATLAB</code>
132 should be the location of your Matlab installation. For example, if
133 /usr/bin/matlab is a link:
134 <pre>
135 bash-3.2$ which matlab
136 /usr/bin/matlab
137 bash-3.2$ ls -l /usr/bin/matlab
138 lrwxr-xr-x  1 root  wheel  42 Jan 15 20:57 /usr/bin/matlab -&gt; /Applications/MATLAB_R2009b.app/bin/matlab
139 bash-3.2$
140 </pre>
141
142 Then $MATLAB would be /Applications/MATLAB_R2009b.app
143
144 <dl>
145 <dt>32 Bit Mac (10.5?, Edit ~/.MacOSX/environment.plist)</dt>
146 <dd><code>export DYLD_LIBRARY_PATH=$MATLAB/bin/maci</code></dd>
147 <dt>64 Bit Mac (10.6?, Edit ~/.MacOSX/environment.plist)</dt>
148 <dd><code>export DYLD_LIBRARY_PATH=$MATLAB/bin/maci64</code></dd>
149 <dt>32 Bit Linux (Edit</dt>
150 <dd><code>export LD_LIBRARY_PATH=$MATLAB/bin/gnlx86</code></dd>
151 <dt>64 Bit Linux</dt>
152 <dd><code>export LD_LIBRARY_PATH=$MATLAB/bin/glnxa64</code></dd>
153 <dt>Windows (Start|My Computer|Properties|Advanced
154       Environment Variables| Add the directory that contains
155       matlab.exe to your path)</dt>
156 <dd><code>Be sure that the matlab binary is in your path</code></dd>
157 </dl>
158
159 <h2>Notes about Matlab 10.8 and later</h2>
160
161 <p>Note that under recent version of MacOS, the DYLD_LIBRARY_PATH is no longer used.
162 The workaround is to be sure that matlab is in your path and to run ./configure.</p>
163
164 <p>For example:</p>
165 <pre>
166 bash-3.2$ bash-3.2$ which matlab
167 /Applications/MATLAB_R2018a.app/bin/matlab
168 </pre>
169
170 <p>Then, running:</p>
171 <pre>
172 ./configure --enable-verbose
173 </pre>
174
175 <p>shows:</p>
176
177 <pre>
178 checking for matlab... /Applications/MATLAB_R2018a.app/bin/matlab
179 checking the value of the Matlab root directory ... '/Applications/MATLAB_R2018a.app'
180 checking for gcc... checking for gcc... /usr/bin/gcc
181 checking for malloc_size... yes
182 checking the extension for Matlab .mex files... mexmaci64
183 checking which major type of OS we are running under... MacOSX
184 using '/Applications/MATLAB_R2018a.app/bin/maci' for Matlab's engine libraries
185 </pre>
186
187 <p>Then run</p>
188 <pre>
189 cd $PTII
190 ant
191 cd $PTII/bin
192 make
193 cd $PTII/ptolemy/matlab
194 make clean; make
195 </pre>
196
197 <p>Here's what libraries are used by libptmatlab.jnilib</p>
198
199 <pre>
200 bash-3.2$ otool -L libptmatlab.jnilib
201 libptmatlab.jnilib:
202         libptmatlab64.jnilib (compatibility version 0.0.0, current version 0.0.0)
203         @rpath/libeng.dylib (compatibility version 0.0.0, current version 0.0.0)
204         @rpath/libmx.dylib (compatibility version 0.0.0, current version 0.0.0)
205         @rpath/libmex.dylib (compatibility version 0.0.0, current version 0.0.0)
206         /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
207 bash-3.2$
208 </pre>
209
210 <p>To see the value of rpath:</p>
211
212 <pre>
213 otool -l libptmatlab.jnilib
214 ...
215 Load command 14
216           cmd LC_RPATH
217       cmdsize 56
218          path /Applications/MATLAB_R2018a.app/bin/maci64 (offset 12)
219 </pre>
220
221 <p>So, the above says that the shared library has an RPATH of /Applications/MATLAB_R2018a.app/bin/maci64, which is where libeng.dylib is:</p>
222
223 <pre>
224 bash-3.2$ ls -l /Applications/MATLAB_R2018a.app/bin/maci64/libeng.dylib
225 -r-xr-xr-x  1 cxh  admin  15664 Feb  6 01:17 /Applications/MATLAB_R2018a.app/bin/maci64/libeng.dylib
226 </pre>
227
228 </p>Edit loadLibrary() in
229 $PTII/ptolemy/data/expr/UtilityFunctions.java and set debug to true,
230 then I can see what file is loaded by loading the demo</p>
231
232 <pre>
233 bash-3.2$ $PTII/bin/vergil $PTII/ptolemy/matlab/demo/MatlabExpression/MatlabExpression.xml
234 UtilityFunctions.loadLibrary(ptolemy/matlab/ptmatlab)
235 UtilityFunctions.loadLibrary(ptolemy/matlab/ptmatlab): System.load()
236 UtilityFunctions.loadLibrary(ptolemy/matlab/ptmatlab): java.lang.UnsatisfiedLinkError: Expecting an absolute path ofthe library: ptolemy/matlab/ptmatlab
237 UtilityFunctions._loadLibrary(ptolemy/matlab/ptmatlab, jnilib): osName: Mac OS X
238 UtilityFunctions._loadLibrary(ptolemy/matlab/libptmatlab, jnilib): libraryWithSuffix: ptolemy/matlab/libptmatlab.jniib libraryPathExiststrue
239 UtilityFunctions._loadLibrary(ptolemy/matlab/libptmatlab, jnilib): System.load(/Users/cxh/src/ptII11.0.devel/ptolemy/matlab/libptmatlab.jnilib)
240 <pre>
241
242 <p>Use the <code>otool</code> <code>-L</code> and <code>-l</code>
243 commands to ensure that <code>libeng.dylib</code> can be found.</p>
244
245 @author Zoltan Kemenczy and Sean Simmons, Research in Motion Limited
246 @version $Id$
247 @since Ptolemy II 2.0
248 @Pt.ProposedRating Yellow (zkemenczy)
249 @Pt.AcceptedRating Red (cxh)
250 */
251public class Expression extends TypedAtomicActor {
252    /** Construct an actor with the given container and name.
253     *  @param container The container.
254     *  @param name The name of this actor.
255     *  @exception IllegalActionException If the actor cannot be contained
256     *   by the proposed container.
257     *  @exception NameDuplicationException If the container already has an
258     *   actor with this name.
259     */
260    public Expression(CompositeEntity container, String name)
261            throws NameDuplicationException, IllegalActionException {
262        super(container, name);
263
264        output = new TypedIOPort(this, "output", false, true);
265        expression = new StringParameter(this, "expression");
266        new TextStyle(expression, "Matlab expression");
267
268        _dataParameters = new Engine.ConversionParameters();
269
270        get1x1asScalars = new Parameter(this, "get1x1asScalars",
271                new BooleanToken(_dataParameters.getScalarMatrices));
272        new CheckBoxStyle(get1x1asScalars, "style");
273
274        getIntegerMatrices = new Parameter(this, "getIntegerMatrices",
275                new BooleanToken(_dataParameters.getIntMatrices));
276        new CheckBoxStyle(getIntegerMatrices, "style");
277
278        clearEnvironment = new Parameter(this, "clearEnvironment",
279                new BooleanToken(true));
280        clearEnvironment.setTypeEquals(BaseType.BOOLEAN);
281        clearEnvironment.setToken(BooleanToken.TRUE);
282
283        // _time is not needed, fire() sets a matlab variable directly
284        _iteration = new Variable(this, "_iteration", new IntToken(1));
285    }
286
287    ///////////////////////////////////////////////////////////////////
288    ////                     ports and parameters                  ////
289
290    /** The output port. */
291    public TypedIOPort output;
292
293    /** The parameter that is evaluated to produce the output.
294     *  Typically, this parameter evaluates an expression involving
295     *  the inputs. To refer to parameters in scope within the expression,
296     *  use $name or ${name}, where "name" is the name of the parameter.
297     */
298    public StringParameter expression;
299
300    /** If true (checked), 1x1 matrix results are converted to
301     ScalarTokens instead of a 1x1 MatrixToken, default is
302     <i>true</i>. */
303    public Parameter get1x1asScalars;
304
305    /** If true, all double-valued matrix results are checked to see if
306     all elements represent integers, and if so, an IntMatrixToken is
307     returned, default is <i>false</i> for performance reasons. */
308    public Parameter getIntegerMatrices;
309
310    /** If true, clear variables and globals before each execution. */
311    public Parameter clearEnvironment;
312
313    ///////////////////////////////////////////////////////////////////
314    ////                         public methods                    ////
315
316    /** Clone the actor into the specified workspace. This calls the
317     *  base class and then sets the <code>iteration</code>
318     *  public member to the parameters of the new actor.
319     *  @param workspace The workspace for the new object.
320     *  @return A new actor.
321     *  @exception CloneNotSupportedException If a derived class contains
322     *   an attribute that cannot be cloned.
323     */
324    @Override
325    public Object clone(Workspace workspace) throws CloneNotSupportedException {
326        Expression newObject = (Expression) super.clone(workspace);
327
328        newObject._addPathCommand = null;
329        newObject._iteration = (Variable) newObject.getAttribute("_iteration");
330        newObject._iterationCount = 1;
331        newObject._previousPath = null;
332        newObject._inputTokens = new HashMap<String, Token>();
333        return newObject;
334    }
335
336    /** Open a matlab engine.
337     *  @exception IllegalActionException If matlab engine not found.
338     */
339    @Override
340    public void preinitialize() throws IllegalActionException {
341        super.preinitialize();
342        _initializeEngine();
343    }
344
345    /** Initialize the iteration count to 1.
346     *  @exception IllegalActionException If the parent class throws it.
347     */
348    @Override
349    public void initialize() throws IllegalActionException {
350        super.initialize();
351
352        // Check to make sure that the engine has been initialized.
353        synchronized (Engine.semaphore) {
354            if (engine == null) {
355                _initializeEngine();
356            }
357        }
358
359        _iterationCount = 1;
360        _iteration.setToken(new IntToken(_iterationCount));
361
362        // Process any additional directories to be added to matlab's
363        // path. The list may contain paths relative to the directory in
364        // which ptolemy was started or any directory listed in the current
365        // classpath (in this order, first match wins). See
366        // UtilityFunctions.findFile()
367        _addPathCommand = null; // Assume none
368        _previousPath = null;
369
370        Parameter packageDirectories = (Parameter) getAttribute(
371                "packageDirectories");
372
373        if (packageDirectories != null) {
374            StringTokenizer dirs = new StringTokenizer(
375                    ((StringToken) packageDirectories.getToken()).stringValue(),
376                    ",");
377            StringBuffer cellFormat = new StringBuffer(512);
378            cellFormat.append("{");
379
380            if (dirs.hasMoreTokens()) {
381                cellFormat.append("'"
382                        + UtilityFunctions.findFile(dirs.nextToken()) + "'");
383            }
384
385            while (dirs.hasMoreTokens()) {
386                cellFormat.append(",'"
387                        + UtilityFunctions.findFile(dirs.nextToken()) + "'");
388            }
389
390            cellFormat.append("}");
391
392            if (cellFormat.length() > 2) {
393                _addPathCommand = "addedPath_ = " + cellFormat.toString()
394                        + ";addpath(addedPath_{:});";
395
396                synchronized (Engine.semaphore) {
397                    matlabEngine.evalString(engine, "previousPath_=path");
398                    _previousPath = matlabEngine.get(engine, "previousPath_");
399                }
400            }
401        }
402
403        _dataParameters.getScalarMatrices = ((BooleanToken) get1x1asScalars
404                .getToken()).booleanValue();
405        _dataParameters.getIntMatrices = ((BooleanToken) getIntegerMatrices
406                .getToken()).booleanValue();
407    }
408
409    /** Return true if all input ports have at least one token.
410     *  @return True if this actor is ready for firing, false otherwise.
411     *  @exception IllegalActionException Not thrown in this base class.
412     */
413    @Override
414    public boolean prefire() throws IllegalActionException {
415        Iterator inputPorts = inputPortList().iterator();
416
417        while (inputPorts.hasNext()) {
418            IOPort port = (IOPort) inputPorts.next();
419
420            if (!port.hasToken(0)) {
421                return false;
422            }
423        }
424
425        return super.prefire();
426    }
427
428    /** Evaluate the expression and send its result to the output.
429     *  @exception IllegalActionException If the evaluation of the expression
430     *   triggers it, or the evaluation yields a null result, or the evaluation
431     *   yields an incompatible type, or if there is no director.
432     */
433    @Override
434    public void fire() throws IllegalActionException {
435        super.fire();
436        Director director = getDirector();
437
438        if (director == null) {
439            throw new IllegalActionException(this, "No director!");
440        }
441
442        boolean clearEnvironmentValue = ((BooleanToken) clearEnvironment
443                .getToken()).booleanValue();
444
445        try {
446
447            // Read the input ports before acquiring the engine lock since
448            // get() may block depending on the director, e.g., PN.
449            for (TypedIOPort port : inputPortList()) {
450                _inputTokens.put(port.getName(), port.get(0));
451            }
452
453            synchronized (Engine.semaphore) {
454
455                if (clearEnvironmentValue) {
456                    // The following clears variables, but preserves any
457                    // persistent storage created by a function (this usually
458                    // for speed-up purposes to avoid recalculation on every
459                    // function call)
460                    matlabEngine.evalString(engine,
461                            "clear variables;clear globals");
462                }
463
464                if (_addPathCommand != null) {
465                    matlabEngine.evalString(engine, _addPathCommand);
466                }
467
468                try {
469                    matlabEngine.put(engine, "time", new DoubleToken(
470                            director.getModelTime().getDoubleValue()));
471                } catch (IllegalActionException ex) {
472                    throw new IllegalActionException(this, ex,
473                            "Failed to set the \"time\" variable in the Matlab "
474                                    + "engine to " + new DoubleToken(director
475                                            .getModelTime().getDoubleValue()));
476                }
477                try {
478                    matlabEngine.put(engine, "iteration",
479                            _iteration.getToken());
480                } catch (IllegalActionException ex) {
481                    throw new IllegalActionException(this, ex,
482                            "Failed to set the \"iteration\" variable in the Matlab "
483                                    + "engine to " + _iteration.getToken());
484                }
485
486                for (Map.Entry<String, Token> entry : _inputTokens.entrySet()) {
487                    matlabEngine.put(engine, entry.getKey(), entry.getValue());
488                }
489
490                matlabEngine.evalString(engine, expression.stringValue());
491
492                Iterator outputPorts = outputPortList().iterator();
493
494                while (outputPorts.hasNext()) {
495                    IOPort port = (IOPort) outputPorts.next();
496
497                    // FIXME: Handle multiports
498                    if (port.isOutsideConnected()) {
499                        port.send(0, matlabEngine.get(engine, port.getName(),
500                                _dataParameters));
501                    }
502                }
503
504                // Restore previous path if path was modified above
505                if (_previousPath != null) {
506                    matlabEngine.put(engine, "previousPath_", _previousPath);
507                    matlabEngine.evalString(engine, "path(previousPath_);");
508                }
509            }
510        } finally {
511            // Remove references to any tokens that were read from input ports.
512            _inputTokens.clear();
513        }
514    }
515
516    /** Increment the iteration count.
517     *  @exception IllegalActionException If the superclass throws it.
518     */
519    @Override
520    public boolean postfire() throws IllegalActionException {
521        _iterationCount++;
522        _iteration.setToken(new IntToken(_iterationCount));
523
524        // This actor never requests termination.
525        return super.postfire();
526    }
527
528    /** Close matlab engine if it was open.
529     *  @exception IllegalActionException Not thrown in this base class.
530     */
531    @Override
532    public void wrapup() throws IllegalActionException {
533        super.wrapup();
534
535        synchronized (Engine.semaphore) {
536            if (matlabEngine != null) {
537                matlabEngine.close(engine);
538            }
539        }
540
541        engine = null;
542    }
543
544    ///////////////////////////////////////////////////////////////////
545    ////                         protected methods                 ////
546
547    /** Default type constraints do not apply in this case, since the input
548     *  type may be totally unrelated to the output type and cannot be
549     *  inferred; return null.
550     *  @return null
551     */
552    @Override
553    protected Set<Inequality> _defaultTypeConstraints() {
554        return null;
555    }
556
557    ///////////////////////////////////////////////////////////////////
558    ////                         private methods                   ////
559
560    /** Initialize the Matlab Engine.
561     *  @exception IllegalActionException If the connection to the
562     *  Matlab engine cannot be intialized.
563     */
564    private void _initializeEngine() throws IllegalActionException {
565        synchronized (Engine.semaphore) {
566            // The intialization used to occur in preinitialize(), but this
567            // meant that the Matlab Expression actor could not be used
568            // in a RunComposite because RunComposite invokes _executeInsideModel()
569            // which does not invoke preinitialize().  If _executeInsideModel()
570            // invokes preinitialize(), then the PortParameters of the RunComposite
571            // are constantly reset to the value of the _persistentExpression.
572            try {
573                matlabEngine = new Engine();
574            } catch (Throwable throwable) {
575                // LinkageError is and Error, not an exceptoin
576                throw new IllegalActionException(this, throwable,
577                        "There was a problem invoking the Ptolemy II Matlab "
578                                + "interface.\nThe interface has been tested under "
579                                + "Linux, Mac OS X, and Windows.\n"
580                                + "The interface requires that Matlab be installed "
581                                + "on the local machine and that the ptmatlab "
582                                + "shared library available.\n"
583                                + "* Under Linux, you must have the LD_LIBRARY_PATH "
584                                + "environment variable set to include the directories "
585                                + "that contain libmx.so and libptmatlab.so.\n"
586                                + "* Under Mac OS X, you must have the DYLD_LIBRARY_PATH "
587                                + "environment variable set to include the directories "
588                                + "that contain libmx.dylib and libptmatlab.jnilib.\n"
589                                + "* Under Windows, you must have your PATH set to include "
590                                + "the Matlab bin/win32 or equivalent directory so that "
591                                + "libmex.dll is found and the directory that contains "
592                                + "libptmatlab.dll. "
593                                + "In addition, if you are running under Windows from "
594                                + "the Cygwin bash prompt, then you must start Vergil with "
595                                + "the -jni argument: $PTII/bin/vergil -jni. For details, "
596                                + "see $PTII/jni/package.html.\n"
597                                + "Refer to $PTII/ptolemy/matlab/makefile for more "
598                                + "information.");
599            }
600
601            // First set default debugging level, then check for more
602            matlabEngine.setDebugging((byte) 0);
603
604            Parameter debugging = (Parameter) getAttribute("_debugging");
605
606            if (debugging != null) {
607                Token t = debugging.getToken();
608
609                if (t instanceof IntToken) {
610                    matlabEngine.setDebugging((byte) ((IntToken) t).intValue());
611                }
612            }
613
614            engine = matlabEngine.open();
615        }
616    }
617
618    private transient Engine matlabEngine = null;
619
620    long[] engine = null;
621
622    private Variable _iteration;
623
624    private int _iterationCount = 1;
625
626    private String _addPathCommand = null;
627
628    private Token _previousPath = null;
629
630    private transient ConversionParameters _dataParameters;
631
632    /** A map of input port names to tokens. */
633    private Map<String, Token> _inputTokens = new HashMap<String, Token>();
634}