Did you know ... | Search Documentation: |

Packs (add-ons) for SWI-Prolog |

Title: | Prolog-Matlab bridge |
---|---|

Rating: | Not rated. Create the first rating! |

Latest version: | 2.0.3 |

SHA1 sum: | b1c66d575e90fff877b40b67453283869bdf7a9c |

Author: | Samer Abdallah <samer.abdallah@gmail.com> |

Download URL: | https://github.com/samer--/plml.git |

No reviews. Create the first review!.

Version | SHA1 | #Downloads | URL |
---|---|---|---|

1.0.1 | 1001794d144bb5e1f7784a72628c0eacbb08296b | 1 | https://github.com/samer--/plml.git |

1.1.0 | 2c053bc11389342aee9e811d92afc4e4a0c733f5 | 2 | https://github.com/samer--/plml.git |

62a7d1b9630f6e397069d9a5f2c5b54537094d11 | 1 | https://github.com/samer--/plml.git | |

1.1.1 | 11668402ce9e72de971a7fcfae67290da3077e8e | 2 | https://github.com/samer--/plml.git |

1ecd27fee9fcb6da792a05dbd6a0262774ceccc8 | 1 | https://github.com/samer--/plml.git | |

3b3f7a40a268cdf38dac60c7abe25ebb94f01643 | 2 | https://github.com/samer--/plml.git | |

87189c7b9c8a647d4773ca26c9878d3b52df73f0 | 1 | https://github.com/samer--/plml.git | |

1.2.0 | 2b14bac2cc28bb38f94493813887742f935e62c4 | 1 | https://github.com/samer--/plml.git |

53da6776bb4178290235c366fe9715135feea5bb | 2 | https://github.com/samer--/plml.git | |

7dff82e5989e5a143b0da6cc2300b22f3e8e0f77 | 2 | https://github.com/samer--/plml.git | |

1.3.0 | 2a9e7bb47a48e37917e9f84ab2d8d72d87619bce | 1 | https://github.com/samer--/plml.git |

1.4.0 | f3213076e6225bb897f5b20d05383e1e0928972f | 2 | https://github.com/samer--/plml.git |

1.5.0 | 0d9464b3a3e8854f258f5ceef4ce237e618374cd | 1 | https://github.com/samer--/plml.git |

2.0.0 | d7b24752163fb87f2950b45ea4788e104c005d0b | 1 | https://github.com/samer--/plml.git |

2.0.1 | cd4bf261292215f0a555f88086253bd023da72e8 | 3 | https://github.com/samer--/plml.git |

2.0.2 | ecceef0df02a91aefade9e7621f73235e4ea3bab | 1 | https://github.com/samer--/plml.git |

2.0.3 | b1c66d575e90fff877b40b67453283869bdf7a9c | 9 | https://github.com/samer--/plml.git |

Prolog-Matlab bridge for SWI Prolog

Authors (2004--2012) Samer Abdallah Centre for Digital Music, Queen Mary, University of London,

Christophe Rhodes Centre for Computational Creativity Goldsmiths College, University of London

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.

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, (since these
are equivalent to unquoted Prolog atoms),
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, if the SWI Prolog flag back_quotes
is set to symbol_char, `/1 functor, ie `hello or `q(hello)`

both evaluate to the Matlab string '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.

The results of computations can handled in several ways:

- 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 (eventually) deleted if the Prolog atom goes out of scope.

?- A===2+2, ??

`disp(A)`

. >> 4 % matlab textual outputA = ws(ml:t_2311) % Prolog blob pointing to Matlab variable t_2311

- 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.0There 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]].

- 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 default is ~/var/matbase (ie under the user's home directory). 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.

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 the system are resolved!

There are some limitations to what you can do with this Matlab interface.

The communication protocol between the Matlab Engine library and the
Matlab process is somewhat flawed. if the Matlab computation outputs the
characters `flushed_stdout`

at any point, the conversation between the
engine library and Matlab is irretrievable broken: the library gets out
of step with the stream coming from Matlab and there is no way to get back
into step. You have to close and reopen the Matlab instance and reopen.

In Matlab, you can use Ctrl-C to interrupt a stuck or long running computation. Matlab respons to the INT signal generated when you press Ctrl-C at the terminal. What happens when you press Ctrl-C during a computation when using this plml library depends on which thread the call was made. If it is the foreground thread, the INT signal interrupts BOTH the Matlab computation (because the Matlab process is in the same Unix process group) AND the current Prolog thread, which will be in the depths of a call to the Matlab Engine API. This causes the call to return an error, but the Engine API loses synchonisation with the input stream from Matlab and the conversation is irretrievably broken. I'm afraid there's nothing we can do about this without interposing a filter a filter between the Matlab process and the engine library.

If the Matlab call is made in a background thread, Ctrl-C interrupts the foreground Prolog thread, but not the engine API call. The INT signal is still sent to the Matlab process, so it is interrupted and the engine API call returns early.

The same effect can be obtained by sending an INT signal directly to the Matlab
process. You can use the Matlab function `feature`

to get Matlab's process ID.

However, there is still a problem with detecting that Matlab has been interrupted.
In some cases, there is no observable difference between completion and
interruption (try pressing Ctrl-C while running `pause(10)`

in Matlab directly).
In others, Matlab will print a message to stderr, and then stop with no other
observable effect, in particular `lasterr`

will not return anything useful.
The engine API does not observe Matlab's stderr, and so there is no way to
detect that a Matlab call has been interrupted. To get round this, plml adds
the command `disp("}")`

to the end of each Matlab execution. It then checks
to see if "}\n" appears at the end of the output. If not, we conclude that the
computation was interrupted. This is fine unless the call produces so much output
that it doesn't fit into the output buffer. In this case, the check is
skipped, and so checking for interruptions will not work.
An 'output truncated' message is also printed on stderr.

Before you start, you need a working SWI Prolog installation and
a Matlab installation. Then the `pack_install/1`

facility of SWI
Prolog should be enough to build the C++ code foreign library.

As it stands, there is a minor difficulty when attempting to load
the plml.dylib foreign library: because of the way the
Matlab application is designed, plml.dylib ends up looking for
various Matlab libraries (libeng, libmx, etc.) using *relative*
paths, not absolute paths, which means that if you simply start
SWI Prolog and load the plml module, the foreign library fails to
load. There are two solutions to this:

- Set the DYLD_FALLBACK_LIBRARY_PATH environment variable
*before*starting SWI Prolog. A shell script for doing this, called

`swiplml`

can be found in the`scripts`

directory of this package. If you copy or link it into your`PATH`, and use`swiplml`

instead of`swipl`

, it should work fine. - A minor adjustment of some the Matlab libraries can made, changing
them to use the

`@rpath`

mechanism of`dyld`

means that using the`-rpath`

option while linking plml.dylib solves the problem. Although some of Matlab's installed files are altered, this does not seem to affect the normal running of Matlab.The

`fixdylibs`

pseudo-target of this package's Makefile will do this for you, but as it may require root priviledges, it uses`sudo`

and therefore requires that you have administrator rights. The changes are made using`scripts/fixdylibs`

, which will also make backups of your original Matlab libraries if they do not yet exist.

If the installation is ok and you have followed one of the two options above, then you should be able to start SWI Prolog and do the following:

?- use_module(library(plml)). % ... Yes. ?- ml_open(ml). % ml is the name assigned to the Matlab engine instance Matlab engine (ml) open. Yes ?- float(A)===2*pi. A = 6.28319 ?- A:float===2*pi. A = 6.28319

If you have a working X-server available, then the following should result in a straight line plot.

?- ?? figure(1). % ... ?- ?? plot(1:10).

There are two configuration options in the Makefile. If you enable DEBUG mode and rebuild, then the library will print a series of cryptic characters as it aquires and releases the mutexes protecting the WS variable release queue and the Matlab engine.

If you enable NOLOCK, the mutex protecting the Matlab engine will be disabled. You might want this if you are sure that the library is going to be called in a single threaded way, but probably any performance gain will be miniscule.

This work was partially supported by UK EPSRC grants GR/S84750/01 and GR/S82213/01.

Pack contains 31 files holding a total of **199K** bytes.

- CHANGES(6.5K bytes)
- LICENSE(17.6K bytes)
- Makefile(1.5K bytes)
- README.md(10.9K bytes)
- cpp
- matlab
- contents.m(1.8K bytes)
- dbcellmap.m(207 bytes)
- dbdrop.m(615 bytes)
- dbload.m(345 bytes)
- dbpath.m(177 bytes)
- dbread.m(305 bytes)
- dbroot.m(1.3K bytes)
- dbsave.m(629 bytes)
- dbsaveas.m(342 bytes)
- dbtmp.m(363 bytes)
- nop.m(90 bytes)
- pr_uniquevars.m(65 bytes)
- typecode.m(248 bytes)
- uniquefile.m(697 bytes)
- uniquevar.m(464 bytes)
- unknown.m(27 bytes)

- pack.pl(164 bytes)
- prolog
- mlserver.pl(6.5K bytes)
- plml.pl(40.5K bytes)
- plml_core.pl(19.4K bytes)
- plml_dcg.pl(17.7K bytes)
- plml_util.pl(4.5K bytesplml_utils)

- scripts