annotate README @ 15:e395e387bd3c

FIX: now catching precursor signs of lock-up bug correctly ENHANCEMENT: As a side effect, mlWSAlloc and mlExec are faster.
author samer
date Thu, 02 Feb 2012 12:57:15 +0000
parents 173e1c48e335
children e0a1f92fcbc9
rev   line source
samer@0 1 *** Prolog Matlab interface
samer@0 2 ***
samer@0 3 *** Authors:
samer@0 4 *** Samer Abdallah
samer@0 5 *** Centre for Digital Music,
samer@0 6 *** Queen Mary, University of London
samer@0 7 ***
samer@0 8 *** Christophe Rhodes
samer@0 9 *** Centre for Computational Creativity
samer@0 10 *** Goldsmiths College, University of London
samer@0 11 ***
samer@0 12 *** Dec 2004--January 2012
samer@0 13
samer@0 14
samer@8 15 -------------------------------------------------------------------------
samer@8 16 NB: output type tagging system has changed but this documentation
samer@8 17 has not yet. See pldoc documentation of plml.pl.
samer@8 18
samer@0 19
samer@0 20
samer@0 21 -------------------------------------------------------------------------
samer@0 22 OVERVIEW
samer@0 23
samer@0 24 PLML is a foreign interface that enables Matlab to be used as a computational
samer@0 25 engine from within SWI Prolog. The basic idea is that instead of using
samer@0 26 the standard is/2 operator to evaluate a certain class of terms, we can
samer@0 27 use the ===/2 operator to get Matlab to evaluate a (much richer) class of
samer@0 28 terms, eg
samer@0 29
samer@0 30 ?- float(A)===trace(eye(3)).
samer@0 31
samer@0 32 A = 3.0
samer@0 33
samer@0 34 We can also get Matlab to perform actions with side effects, like
samer@0 35 making sounds and graphics; obviously these do not fit into the declartive
samer@0 36 semantics of Prolog and have to be dealt with under the procedural semantics.
samer@0 37 If you want to execute a Matlab command in an imperative way and see the
samer@0 38 textual output, use the ??/1 operator, eg
samer@0 39
samer@0 40 ?- ??disp(`hello).
samer@0 41 >> hello
samer@0 42
samer@0 43
samer@0 44
samer@0 45 The interface works by using the Matlab Engine API, which starts up a Matlab
samer@0 46 process on the end of a pipe. The Matlab process can be on another machine,
samer@0 47 and multiple Matlab engines can be started on the same or different machines.
samer@0 48 Matlab expressions are sent down the pipe and executed. Matlab's textual
samer@0 49 output comes back through the pipe. In addition, Matlab variables can be
samer@0 50 transferred directly between the Matlab engine's memory space and SWI's
samer@0 51 memory space.
samer@0 52
samer@0 53
samer@0 54 *** Expression language
samer@0 55
samer@0 56 Expressions to evaluate are given in a sublanguage of terms which is
samer@0 57 similar to but not exactly the same as Matlab. In particular, Prolog
samer@0 58 syntax cannot accommodate the single quoted Matlab strings,
samer@0 59 the Matlab syntax of matrices, (eg [1 2; 3 4]), and the Matlab syntax
samer@0 60 for slicing arrays (eg A(:,3:4)) if A is a Prolog variable.
samer@0 61 Strings are handled using the q/1 or `/1 functors, ie `hello and q(hello)
samer@0 62 both evaluate to 'hello'. Arrays can be given either as flat lists,
samer@0 63 which are interpreted as horizontal concatenation as in Matlab:
samer@0 64
samer@0 65 ?- ??[1,2,3].
samer@0 66 >> ans = 1 2 3
samer@0 67
samer@0 68 ?- ??[eye(2),magic(2)].
samer@0 69 >> ans =
samer@0 70 1 0 1 3
samer@0 71 0 1 4 2
samer@0 72
samer@0 73 or as nested listed for multidimensional arrays using the arr/1 functor,
samer@0 74 where the innermost nesting corresponds to the FIRST Matlab dimensions
samer@0 75
samer@0 76 ?- ??arr([1,2,3]).
samer@0 77 >> ans =
samer@0 78 1
samer@0 79 2
samer@0 80 3
samer@0 81
samer@0 82 ?- ??arr([[1,2],[3,4]]).
samer@0 83 >> ans =
samer@0 84 1 3
samer@0 85 2 4
samer@0 86
samer@0 87 Cell arrays can be specified in a similar way using braces or the cell/1 functor.
samer@0 88
samer@0 89
samer@0 90 To help with accessing array elements, see the Matlab functions general/paren,
samer@0 91 general/row, and general/col in the matlab directory.
samer@0 92
samer@0 93
samer@0 94
samer@0 95 *** Return values
samer@0 96
samer@0 97 The results of computations can handled in several ways:
samer@0 98
samer@0 99 1. Keep the result in a Matlab workspace variable in the engine's memory
samer@0 100 space. The names of these variables are allocated automatically
samer@0 101 and stored in a Prolog atom. The atoms have a garbage collection
samer@0 102 callback which means that the Matlab workspace variable is deleted
samer@0 103 if the Prolog atom goes out of scope.
samer@0 104
samer@0 105 ?- A===2+2, ??disp(A).
samer@0 106 >> 4 % matlab textual output
samer@0 107
samer@0 108 A = ws(<ml:t_2311>) % Prolog blob pointing to Matlab variable t_2311
samer@0 109
samer@0 110
samer@0 111
samer@0 112 2. Convert the result to a prolog atom or term. The type of the resulting
samer@0 113 prolog term depends on the *right hand side* of the ===/2 operator:
samer@0 114
samer@0 115 ?- int(A)===2+2.
samer@0 116 A = 4
samer@0 117
samer@0 118 ?- float(A)===2+2.
samer@0 119 A = 4.0
samer@0 120
samer@0 121
samer@0 122 There are other types for strings and atoms:
samer@0 123
samer@0 124 ?- atom(A) === q(hello). % q/1 means quote as Matlab string
samer@0 125 A = hello.
samer@0 126
samer@0 127 ?- string(A) === `hello. % `/1 is shorthand for q/1
samer@0 128 A = "hello".
samer@0 129
samer@0 130
samer@0 131 You can also get the result as a Matlab binary array on the Prolog side:
samer@0 132
samer@0 133 ?- mx(A)===eye(4). % identity matrix
samer@0 134 A = <#0239c3a0> % Prolog blob handle (with garbage collection)
samer@0 135
samer@0 136
samer@0 137 I haven't completely settled on the best way of handling arrays as
samer@0 138 self-contained Prolog terms, but you can do this:
samer@0 139
samer@0 140 ?- array(A)===magic(3).
samer@0 141 A = [[8.0, 3.0, 4.0], [1.0, 5.0, 9.0], [6.0, 7.0, 2.0]]::[[3, 3]]
samer@0 142
samer@0 143 As you can see, multidimensional arrays are returned as nested lists, and the
samer@0 144 size of the array is given after the :: as [[3,3]].
samer@0 145
samer@0 146
samer@0 147 3. Store the result to a MAT file and return a Prolog term which points to the
samer@0 148 file. The names are generated automatically. This allows for persistence
samer@0 149 of values which are referred to by stable names that can be stored, eg
samer@0 150 in a database:
samer@0 151
samer@0 152 ?- mat(A)===fft(buffer(wavread('somefile.wav'),256,128)).
samer@0 153
samer@0 154 A = mat:d0608/m48598|x % dynamically generated unique locator
samer@0 155
samer@0 156 This relies on the mechanism provided by the functions in matlab/db.
samer@0 157 A certain directory is designed the root of a 'matbase' (MAT file database).
samer@0 158 The Matlab function dbroot returns or sets this directory:
samer@0 159
samer@0 160 ?- ??dbroot.
samer@0 161 >>
samer@0 162 ans =
samer@0 163
samer@0 164 /Users/samer/matbase
samer@0 165
samer@0 166 ?- ??dbroot(q('/usr/share/lib/matbase')). % switch to shared matbase
samer@0 167 >>
samer@0 168 ans =
samer@0 169
samer@0 170 /usr/share/lib/matbase
samer@0 171
samer@0 172 In this case, the locator mat:d0608/m48598|x refers to a Matlab variable called
samer@0 173 'x' (it's always 'x') in the file /usr/share/lib/matbase/d0608/m48598.mat.
samer@0 174 A new directory is created each month, and the filenames are chosen dynamically
samer@0 175 to avoid clashes with existing files.
samer@0 176
samer@0 177
samer@0 178
samer@0 179 *** Debugging/tracing
samer@0 180
samer@0 181 To help with debugging, you can issue the command:
samer@0 182
samer@0 183 ?- utils:set_state(debug,on).
samer@0 184
samer@0 185 which will cause each Matlab expression to be printed in its Matlab form
samer@0 186 before execution.
samer@0 187 I'm afraid the best documentation is the code itself, but I do intend to
samer@0 188 produce a manual once some of the more embarrassing aspects of system
samer@0 189 are resolved!
samer@0 190
samer@0 191
samer@0 192
samer@0 193 -------------------------------------------------------------------------
samer@0 194 BUILDING/INSTALLATION
samer@0 195
samer@0 196 See INSTALL
samer@0 197
samer@0 198
samer@0 199
samer@0 200
samer@0 201 -------------------------------------------------------------------------
samer@0 202 CHANGES
samer@0 203
samer@0 204 12/04 - Using Prolog blobs with garbage collection to handle
samer@0 205 Matlab workspace temporary variables. Works but code is
samer@0 206 still a little messy. Would like to unify variable handling-
samer@0 207 the important functions are alloc, free, get, put.
samer@0 208 Also, garbage collection seems to be rather difficult to
samer@0 209 provoke.
samer@0 210
samer@0 211 2005-08-08
samer@0 212 Handle Matlab errors in mlEXEC by setting lasterr() before and
samer@0 213 checking it after engEvalString. If we do get a Matlab
samer@0 214 error, then throw a Prolog exception, because nothing
samer@0 215 else is safe in general. CSR.
samer@0 216
samer@0 217 2005-08-09
samer@0 218 Be a little more paranoid in handling workspace variables, both
samer@0 219 in terms of checking matlab engine error codes and for
samer@0 220 bounds checking of our own functions such as uniquevar.
samer@0 221
samer@0 222 2005-09-26
samer@0 223 Added matbase_mat/1 to enumerate all mat objects actually in
samer@0 224 the file system pointed to by the matlab function dbroot.
samer@0 225
samer@0 226 2005-11-11
samer@0 227 Now sending very long Matlab commands via a char array
samer@0 228 Progress in Prolog-side mxArray support:
samer@0 229 done:
samer@0 230 MXINFO - get size and type of array
samer@0 231 MXSUB2IND - convert multi-dim subscript to linear index
samer@0 232 MXGETFLOAT - get one element of numeric array (must be real)
samer@0 233 MXGETLOGICAL - get element of logical or 0|1 array
samer@0 234 MXGETCELL - get sub mxArray from cell array
samer@0 235 MXGETREALS - get reals part of all elements as flat Prolog list
samer@0 236 MXCREATENUMERIC - create double array
samer@0 237 MXCREATECELL - create cell array
samer@0 238 MXCREATESTRING - create char array from string or atom
samer@0 239 MXPUTFLOAT - write one element of double array
samer@0 240 MXPUTFLOATS - write list of elements to double array
samer@0 241 MXPUTCELL - put an mxArray into a cell array
samer@0 242 MXCOPYNOGC - deep copy of array, return NON-MANAGED mx ref
samer@0 243 MXNEWREFGC - return memory managed ref to array, ie will be GCed
samer@0 244 to do:
samer@0 245 Imaginary parts?
samer@0 246 Reading list of fields from a structure
samer@0 247 Getting cell array contents as a list
samer@0 248 tidy up: error checking and function names
samer@0 249 possibly reduce the amount of bounds checking to improve speed?
samer@0 250 -> need to do proper profiling!
samer@0 251
samer@0 252 2006-11-28
samer@0 253 Errors generated on the matlab side (ie errors in user functions
samer@0 254 rather than the mechanisms of this library) throw exceptions of
samer@0 255 the form mlerror(Engine,Message) instead of just atomic messages.
samer@0 256
samer@0 257 Some changes to plml.pl - see header in that file for details.
samer@0 258
samer@0 259 2008-11-25
samer@0 260 Moved declaration of \ operator to ops.pl
samer@0 261 Changed interface and implementation of ml_open to use list of options.
samer@0 262 Changed build procedure to use build script and two makefiles.
samer@0 263
samer@0 264 2010-02-25
samer@0 265 Replaced use of mxFree with mxDestroyArray to release resources
samer@0 266 obtained using engGetVariable - this was causing a malloc error
samer@0 267 in Matlab 7.9. Also replaced -nojvm with -noawt option when starting
samer@0 268 Matlab, as -nojvm is no longer supported. Apparently they're going
samer@0 269 to withdraw support for X11 graphics at some point. I hate them.
samer@0 270 I'm not 'upgrading' any more.
samer@0 271
samer@0 272 2010-03-19
samer@0 273 Removed dependency on flists
samer@0 274
samer@0 275 2010-05-30
samer@0 276 Merged hostname module into utils.
samer@0 277
samer@0 278 2012-01
samer@0 279 Big overhaul of Prolog part to simplify and speed up.
samer@0 280 Removed unused Matlab functions from matlab/general.
samer@0 281 Version 1!
samer@0 282
samer@15 283 2012-02
samer@15 284 Some changes to mlExec and mlWSAlloc to get around a problem that
samer@15 285 was bedevilling the triserver project, which was using a Matlab
samer@15 286 engine in a separate thread, receiving requests on a message queue,
samer@15 287 and calling this library with call_with_time_limit. Something to
samer@15 288 do with this combination (threads, signals etc) was causing the
samer@15 289 Prolog system to lock up hard on returning to Prolog system
samer@15 290 after a failing call to engGetVariable (which was getting stuck and
samer@15 291 timing out).
samer@15 292
samer@15 293 I still don't know what causes the lock-up, but I was able to detect
samer@15 294 some signs that it was coming *before* calling engGetVariable by looking
samer@15 295 at the Matlab engine output buffer.
samer@15 296
samer@15 297 Eventual work around is not to use engGetVariable to get uniquevar
samer@15 298 variable names (mlWSAlloc) or lasterr (mlExec) at all, but simply
samer@15 299 to scrape these out of the output buffer. This seems to be a few
samer@15 300 milliseconds faster too.
samer@15 301
samer@15 302 other changes: removed ml_debug/1 - would rather have a flag to
samer@15 303 enable printfs in the C++ source.
samer@15 304
samer@0 305 -------------------------------------------------------------------------
samer@0 306 ACKNOWLEDGMENTS
samer@0 307
samer@0 308 This work was partially supported by UK EPSRC grants GR/S84750/01 and
samer@0 309 GR/S82213/01.
samer@0 310