annotate README @ 37:89688ebc447f tip

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