Mercurial > hg > plml
view README @ 37:89688ebc447f tip
Deprecating this repository.
author | samer |
---|---|
date | Mon, 05 Jan 2015 17:42:03 +0000 |
parents | 256016cddcba |
children |
line wrap: on
line source
*** Prolog Matlab interface *** *** Authors: *** Samer Abdallah *** Centre for Digital Music, *** Queen Mary, University of London *** *** Christophe Rhodes *** Centre for Computational Creativity *** Goldsmiths College, University of London *** *** 2004--2012 ------------------------------------------------------------------------- NB: output type tagging system has changed but this documentation has not yet. See pldoc documentation of plml.pl. Also: you need to make sure the required Matlab dynamic libraries are on your dyld search path before starting SWI Prolog. The bash script swiplml shows how you can do this by setting the DYLD_FALLBACK_LIBRARY_PATH environment variable before calling swipl, but be aware that there are several environment variables that can affect dynamic library loading and that they can have weird effects on your system if you have conflicting libraries is different places. See the dyld man page ('man dyld'). ------------------------------------------------------------------------- OVERVIEW PLML is a foreign interface that enables Matlab to be used as a computational engine from within SWI Prolog. The basic idea is that instead of using the standard is/2 operator to evaluate a certain class of terms, we can use the ===/2 operator to get Matlab to evaluate a (much richer) class of terms, eg ?- float(A)===trace(eye(3)). A = 3.0 We can also get Matlab to perform actions with side effects, like making sounds and graphics; obviously these do not fit into the declartive semantics of Prolog and have to be dealt with under the procedural semantics. If you want to execute a Matlab command in an imperative way and see the textual output, use the ??/1 operator, eg ?- ??disp(`hello). >> hello The interface works by using the Matlab Engine API, which starts up a Matlab process on the end of a pipe. The Matlab process can be on another machine, and multiple Matlab engines can be started on the same or different machines. Matlab expressions are sent down the pipe and executed. Matlab's textual output comes back through the pipe. In addition, Matlab variables can be transferred directly between the Matlab engine's memory space and SWI's memory space. *** Expression language Expressions to evaluate are given in a sublanguage of terms which is similar to but not exactly the same as Matlab. In particular, Prolog syntax cannot accommodate the single quoted Matlab strings, the Matlab syntax of matrices, (eg [1 2; 3 4]), and the Matlab syntax for slicing arrays (eg A(:,3:4)) if A is a Prolog variable. Strings are handled using the q/1 or `/1 functors, ie `hello and q(hello) both evaluate to 'hello'. Arrays can be given either as flat lists, which are interpreted as horizontal concatenation as in Matlab: ?- ??[1,2,3]. >> ans = 1 2 3 ?- ??[eye(2),magic(2)]. >> ans = 1 0 1 3 0 1 4 2 or as nested listed for multidimensional arrays using the arr/1 functor, where the innermost nesting corresponds to the FIRST Matlab dimensions ?- ??arr([1,2,3]). >> ans = 1 2 3 ?- ??arr([[1,2],[3,4]]). >> ans = 1 3 2 4 Cell arrays can be specified in a similar way using braces or the cell/1 functor. To help with accessing array elements, see the Matlab functions general/paren, general/row, and general/col in the matlab directory. *** Return values The results of computations can handled in several ways: 1. Keep the result in a Matlab workspace variable in the engine's memory space. The names of these variables are allocated automatically and stored in a Prolog atom. The atoms have a garbage collection callback which means that the Matlab workspace variable is deleted if the Prolog atom goes out of scope. ?- A===2+2, ??disp(A). >> 4 % matlab textual output A = ws(<ml:t_2311>) % Prolog blob pointing to Matlab variable t_2311 2. Convert the result to a prolog atom or term. The type of the resulting prolog term depends on the *right hand side* of the ===/2 operator: ?- int(A)===2+2. A = 4 ?- float(A)===2+2. A = 4.0 There are other types for strings and atoms: ?- atom(A) === q(hello). % q/1 means quote as Matlab string A = hello. ?- string(A) === `hello. % `/1 is shorthand for q/1 A = "hello". You can also get the result as a Matlab binary array on the Prolog side: ?- mx(A)===eye(4). % identity matrix A = <#0239c3a0> % Prolog blob handle (with garbage collection) I haven't completely settled on the best way of handling arrays as self-contained Prolog terms, but you can do this: ?- array(A)===magic(3). A = [[8.0, 3.0, 4.0], [1.0, 5.0, 9.0], [6.0, 7.0, 2.0]]::[[3, 3]] As you can see, multidimensional arrays are returned as nested lists, and the size of the array is given after the :: as [[3,3]]. 3. Store the result to a MAT file and return a Prolog term which points to the file. The names are generated automatically. This allows for persistence of values which are referred to by stable names that can be stored, eg in a database: ?- mat(A)===fft(buffer(wavread('somefile.wav'),256,128)). A = mat:d0608/m48598|x % dynamically generated unique locator This relies on the mechanism provided by the functions in matlab/db. A certain directory is designed the root of a 'matbase' (MAT file database). The Matlab function dbroot returns or sets this directory: ?- ??dbroot. >> ans = /Users/samer/matbase ?- ??dbroot(q('/usr/share/lib/matbase')). % switch to shared matbase >> ans = /usr/share/lib/matbase In this case, the locator mat:d0608/m48598|x refers to a Matlab variable called 'x' (it's always 'x') in the file /usr/share/lib/matbase/d0608/m48598.mat. A new directory is created each month, and the filenames are chosen dynamically to avoid clashes with existing files. *** Debugging/tracing To help with debugging, you can issue the command: ?- debug(plml). which will cause each Matlab expression to be printed in its Matlab form before execution. I'm afraid the best documentation is the code itself, but I do intend to produce a manual once some of the more embarrassing aspects of system are resolved! ------------------------------------------------------------------------- BUILDING/INSTALLATION See INSTALL ------------------------------------------------------------------------- CHANGES 12/04 - Using Prolog blobs with garbage collection to handle Matlab workspace temporary variables. Works but code is still a little messy. Would like to unify variable handling- the important functions are alloc, free, get, put. Also, garbage collection seems to be rather difficult to provoke. 2005-08-08 Handle Matlab errors in mlEXEC by setting lasterr() before and checking it after engEvalString. If we do get a Matlab error, then throw a Prolog exception, because nothing else is safe in general. CSR. 2005-08-09 Be a little more paranoid in handling workspace variables, both in terms of checking matlab engine error codes and for bounds checking of our own functions such as uniquevar. 2005-09-26 Added matbase_mat/1 to enumerate all mat objects actually in the file system pointed to by the matlab function dbroot. 2005-11-11 Now sending very long Matlab commands via a char array Progress in Prolog-side mxArray support: done: MXINFO - get size and type of array MXSUB2IND - convert multi-dim subscript to linear index MXGETFLOAT - get one element of numeric array (must be real) MXGETLOGICAL - get element of logical or 0|1 array MXGETCELL - get sub mxArray from cell array MXGETREALS - get reals part of all elements as flat Prolog list MXCREATENUMERIC - create double array MXCREATECELL - create cell array MXCREATESTRING - create char array from string or atom MXPUTFLOAT - write one element of double array MXPUTFLOATS - write list of elements to double array MXPUTCELL - put an mxArray into a cell array MXCOPYNOGC - deep copy of array, return NON-MANAGED mx ref MXNEWREFGC - return memory managed ref to array, ie will be GCed to do: Imaginary parts? Reading list of fields from a structure Getting cell array contents as a list tidy up: error checking and function names possibly reduce the amount of bounds checking to improve speed? -> need to do proper profiling! 2006-11-28 Errors generated on the matlab side (ie errors in user functions rather than the mechanisms of this library) throw exceptions of the form mlerror(Engine,Message) instead of just atomic messages. Some changes to plml.pl - see header in that file for details. 2008-11-25 Moved declaration of \ operator to ops.pl Changed interface and implementation of ml_open to use list of options. Changed build procedure to use build script and two makefiles. 2010-02-25 Replaced use of mxFree with mxDestroyArray to release resources obtained using engGetVariable - this was causing a malloc error in Matlab 7.9. Also replaced -nojvm with -noawt option when starting Matlab, as -nojvm is no longer supported. Apparently they're going to withdraw support for X11 graphics at some point. I hate them. I'm not 'upgrading' any more. 2010-03-19 Removed dependency on flists 2010-05-30 Merged hostname module into utils. 2012-01 Big overhaul of Prolog part to simplify and speed up. Removed unused Matlab functions from matlab/general. Version 1! 2012-02 Some changes to mlExec and mlWSAlloc to get around a problem that was bedevilling the triserver project, which was using a Matlab engine in a separate thread, receiving requests on a message queue, and calling this library with call_with_time_limit. Something to do with this combination (threads, signals etc) was causing the Prolog system to lock up hard on returning to Prolog system after a failing call to engGetVariable (which was getting stuck and timing out). I still don't know what causes the lock-up, but I was able to detect some signs that it was coming *before* calling engGetVariable by looking at the Matlab engine output buffer. Eventual work around is not to use engGetVariable to get uniquevar variable names (mlWSAlloc) or lasterr (mlExec) at all, but simply to scrape these out of the output buffer. This seems to be a few milliseconds faster too. other changes: removed ml_debug/1 - would rather have a flag to enable printfs in the C++ source. 2012-02-06 Yes, finally, got to the bottom of the locking up bug. The problem was mutlithreaded access to the Matlab engine even when making explicit calls only in one thread IF this is a secondary thread. The reason? Garbage collection in the main thread. Have now added a mutex to protect the Matlab engine (currently one global mutex). If garbage collector is run on a workspace variable blob while the mutex is locked, it fails immediately without blocking. The blob is not reclaimed but will be can be reclaimed the next time gc is run. 2012-02-09 Now using library(debug) for debugging messages. Added more helpful message if foreign library fails to load. ------------------------------------------------------------------------- ACKNOWLEDGMENTS This work was partially supported by UK EPSRC grants GR/S84750/01 and GR/S82213/01.