annotate cpp/plml.cpp @ 37:89688ebc447f tip

Deprecating this repository.
author samer
date Mon, 05 Jan 2015 17:42:03 +0000
parents 4269030c3f55
children
rev   line source
samer@0 1 /*
samer@0 2 * Prolog-MATLAB interface
samer@0 3 * Samer Abdallah (2004)
samer@0 4 * Christophe Rhodes (2005)
samer@0 5 *
samer@0 6 * These are some foreign for procedures to enable SWI Prolog to run
samer@0 7 * and communicate with a MATLAB computational engine, which is
samer@0 8 * started as a separate process on the local or a remote machine.
samer@0 9 *
samer@0 10 * Communication is handled by the MATLAB engine API (engFoo
samer@0 11 * functions) which in turn use a pair of pipes connected to the
samer@0 12 * standard input and output of the MATLAB process.
samer@0 13 *
samer@0 14 * Computations are carried out in the workspace of the MATLAB
samer@0 15 * process, but results can be transported in and out of Prolog's
samer@0 16 * memory space using the {Get,Put}Variable APIs.
samer@0 17 *
samer@0 18 * mxArrays can be created and manipulated on the Prolog side.
samer@0 19 * For example, a large numeric array can be created and send to
samer@0 20 * the engine instead of building a huge expression to evaluate.
samer@0 21 *
samer@0 22 * NOTE: memory management of mxArrays on the Prolog side is complicated
samer@0 23 * by the use of cell arrays. Currently, there are two kinds of
samer@0 24 * mxArray reference atom: garbage collected ones and non-garbage
samer@0 25 * collected ones. You should generally use GCed atoms, but mxArrays
samer@0 26 * going in or out of cell arrays should not be GCed because the
samer@0 27 * parent cell array should manage them. Hence, newly created arrays
samer@0 28 * (using CREATENUMERIC, CREATECELL and CREATESTRING) are NOT
samer@0 29 * marked for GC because you might want to put them straight into a
samer@0 30 * cell array. Also, mx atoms returned from GETCELL are not GCed.
samer@0 31 * If a new array is not going into a cell array, you should use
samer@0 32 * NEWREFGC to obtain a managed atom as soon as possible.
samer@0 33 *
samer@0 34 * If you have a managed array you want to put into a cell array,
samer@0 35 * you should use COPYNOGC to make an unmanaged DEEP COPY of the
samer@0 36 * original which can safely be put in the cell array using PUTCELL
samer@0 37 *
samer@0 38 * A better solution would be to flip the management status of a given
samer@0 39 * mx_blob atom as necessary.
samer@0 40 *
samer@0 41 * TODO
samer@0 42 *
samer@0 43 * - (See plmatlab.pl for comments about the syntax for Prolog-side
samer@0 44 * users)
samer@0 45 *
samer@0 46 * - There is a problem if the Matlab script decides to pause - there
samer@0 47 * is apparently no way to communicate a keypress to the engine.
samer@0 48 *
samer@0 49 * - Similarly, there is no way to interrupt a long computation.
samer@0 50 * Pressing Ctrl-C to interrupt Prolog seems to have some effect but
samer@0 51 * it seems to confuse the Matlab engine. Empirically, matlab
samer@0 52 * processes handle some signals (try kill -SEGV `pidof MATLAB`) but
samer@0 53 * not in a useful way.
samer@0 54 *
samer@0 55 * - There is no established protocol for freeing variables from
samer@0 56 * engGetVariable: they are likely to persist for ever, or at least
samer@0 57 * for a long time, except for those handled by the finalization of
samer@0 58 * prolog terms.
samer@0 59 *
samer@0 60 * - Memory management of mxArray references (see above notes)
samer@0 61 *
samer@0 62 * Changes
samer@0 63 * 3/10/04: Added code to retrieve logical variables.
samer@0 64 * Added error checking - eval predicates should fail on error.
samer@0 65 *
samer@0 66 * 5/10/04: Added eng::fp which points to input and output streams
samer@0 67 * of matlab process. This will enable asynchronous evals
samer@0 68 *
samer@0 69 * 22/10/04: Blob handling for mxArray corrected by liberal sprinkling
samer@0 70 * of asterisks.
samer@0 71 *
samer@0 72 * 12/12/04: Removed non-blob mxArray code and added blobs for Matlab
samer@0 73 * workspace variables.
samer@0 74 *
samer@0 75 * 13/12/04: Removed all traces of old ws var handling code.
samer@0 76 *
samer@0 77 * (Later changes may be found in the README file)
samer@0 78 */
samer@0 79
samer@0 80 #include <SWI-cpp.h>
samer@0 81 #include <stdio.h>
samer@12 82 #include <unistd.h>
samer@18 83 #include <pthread.h>
samer@0 84 #include "engine.h"
samer@0 85
samer@15 86
samer@15 87 #define ALT_LASTERR 1
samer@15 88
samer@0 89 /* The maximum number of simultaneous connections to Matlab from one
samer@0 90 Prolog process. */
samer@0 91 #define MAXENGINES 4
samer@0 92 #define BUFSIZE 32768 // buffer for matlab output
samer@0 93 #define MAXCMDLEN 256
samer@15 94
samer@15 95 #ifdef ALT_LASTERR
samer@15 96 # define EVALFMT "lasterr('');disp('#');%s"
samer@15 97 #else
samer@15 98 # define EVALFMT "lasterr('');disp('#');%s\nt__ex=lasterr;"
samer@15 99 #endif
samer@0 100
samer@0 101 using namespace std;
samer@0 102
samer@0 103 // This is for a SWI Prolog BLOB type to manage mxArray pointers. It
samer@0 104 // means that the Prolog garbage collector can deal with freeing
samer@0 105 // unreferenced mxArrays automatically.
samer@0 106
samer@0 107
samer@0 108 #ifdef MX_API_VER
samer@0 109 #if MX_API_VER >= 0x07030000
samer@0 110 #else
samer@0 111 typedef int mwSize;
samer@0 112 typedef int mwIndex;
samer@0 113 #endif
samer@0 114 #else
samer@0 115 typedef int mwSize;
samer@0 116 typedef int mwIndex;
samer@0 117 #endif
samer@0 118
samer@0 119 static PL_blob_t mx_blob;
samer@0 120 static PL_blob_t mxnogc_blob;
samer@0 121 static functor_t mlerror;
samer@0 122
samer@0 123 // Extract an mxArray * from a BLOB atom
samer@0 124 static mxArray *term_to_mx(term_t t) {
samer@0 125 PL_blob_t *type;
samer@0 126 size_t len;
samer@0 127 void *p;
samer@0 128
samer@0 129 PL_get_blob(t, &p, &len, &type);
samer@0 130 if (type != &mx_blob && type != &mxnogc_blob) {
samer@0 131 throw PlException("Not an mx variable");
samer@0 132 }
samer@0 133 return *(mxArray **) p;
samer@0 134 }
samer@0 135
samer@0 136 static mxArray *ablob_to_mx(atom_t a) {
samer@0 137 return term_to_mx(PlTerm(PlAtom(a)));
samer@0 138 }
samer@0 139
samer@0 140 // This is for a SWI Prolog BLOB type to manage Matlab workspace
samer@0 141 // variables. The variable is cleared and the name reclaimed
samer@0 142 // when the blob is garbage collected. This kind of blob has no data
samer@0 143 // apart from the atom's name (ie the variable's name)
samer@0 144
samer@0 145 static PL_blob_t ws_blob;
samer@0 146
samer@0 147 // structure for keeping track of workspace variables
samer@0 148 struct wsvar {
samer@0 149 char name[8]; // designed for short machine generated names
samer@0 150 Engine *engine; // the matlab engine which owns this variable
samer@0 151 atom_t id; // the id of this engine
samer@0 152 };
samer@0 153
samer@0 154 // extract wsvar from blob term
samer@0 155 static struct wsvar *term_to_wsvar(term_t t) {
samer@0 156 PL_blob_t *type;
samer@0 157 size_t len;
samer@0 158 void *p;
samer@0 159
samer@0 160 PL_get_blob(t, &p, &len, &type);
samer@0 161 if (type != &ws_blob) {
samer@0 162 throw PlException("Not a ws variable");
samer@0 163 }
samer@0 164 return (struct wsvar *) p;
samer@0 165 }
samer@0 166
samer@0 167 // extract wsvar from atom by converting to term first
samer@0 168 static struct wsvar *atom_to_wsvar(atom_t a) {
samer@0 169 return term_to_wsvar(PlTerm(PlAtom(a)));
samer@0 170 }
samer@0 171
samer@0 172
samer@0 173 /* MATLAB engine wrapper class */
samer@0 174 class eng {
samer@0 175 public:
samer@18 176 const char *magic;
samer@0 177 Engine *ep; // MATLAB API engine pointer
samer@0 178 atom_t id; // atom associated with this engine
samer@0 179 char *outbuf; // buffer for textual output from MATLAB
samer@0 180
samer@18 181 eng(): ep(NULL), id(PL_new_atom("")), outbuf(NULL) { magic="mleng"; }
samer@0 182
samer@0 183 void open(const char *cmd, atom_t id) {
samer@0 184 ep=engOpen(cmd);
samer@0 185
samer@0 186 if (ep) {
samer@0 187 this->id=id;
samer@0 188 outbuf=new char[BUFSIZE];
samer@0 189 outbuf[BUFSIZE-1]=0;
samer@0 190 engOutputBuffer(ep,outbuf,BUFSIZE-1);
samer@0 191 printf("Matlab engine (%s) open.\n",PL_atom_chars(id));
samer@0 192 } else {
samer@0 193 throw PlException("open engine failed");
samer@0 194 }
samer@0 195 }
samer@0 196 void close() {
samer@0 197 engClose(ep);
samer@0 198 id = PL_new_atom("");
samer@0 199 delete [] outbuf;
samer@0 200 ep=0;
samer@0 201 }
samer@0 202
samer@0 203 bool matches(atom_t id) const { return id==this->id; }
samer@0 204 bool isOpen() const { return ep!=NULL; }
samer@0 205 };
samer@0 206
samer@0 207 // pool of engines, all initially closed
samer@0 208 static eng engines[MAXENGINES];
samer@0 209 // functor to be used to wrap array pointers
samer@0 210
samer@18 211 static pthread_mutex_t EngMutex;
samer@18 212
samer@18 213 class lock {
samer@18 214 public:
samer@18 215 lock() { pthread_mutex_lock(&EngMutex); }
samer@18 216 ~lock() { pthread_mutex_unlock(&EngMutex); }
samer@18 217 };
samer@18 218
samer@18 219
samer@0 220 extern "C" {
samer@0 221 // Functions for mx array atom type
samer@0 222 int mx_release(atom_t a);
samer@0 223 int mx_compare(atom_t a, atom_t b);
samer@0 224 // int mx_write(IOSTREAM *s, atom_t a, int flags);
samer@0 225 int mxnogc_release(atom_t a);
samer@0 226
samer@0 227 // Functions for WS variable atom type
samer@0 228 int ws_release(atom_t a);
samer@0 229 // int ws_write(IOSTREAM *s, atom_t a, int flags);
samer@0 230 }
samer@0 231
samer@0 232 extern "C" {
samer@0 233 install_t install();
samer@0 234 foreign_t mlOpen(term_t servercmd, term_t engine);
samer@0 235 foreign_t mlClose(term_t engine);
samer@0 236 foreign_t mlExec(term_t engine, term_t cmd);
samer@0 237 foreign_t mlWSGet(term_t var, term_t val);
samer@0 238 foreign_t mlWSPut(term_t var, term_t val);
samer@0 239 foreign_t mlWSName(term_t engine, term_t var, term_t id);
samer@0 240 foreign_t mlWSAlloc(term_t engine, term_t var);
samer@0 241 foreign_t mlMx2Atom(term_t mx, term_t atom);
samer@0 242 foreign_t mlMx2Float(term_t mx, term_t num);
samer@0 243 foreign_t mlMx2Logical(term_t mx, term_t num);
samer@0 244 foreign_t mlMx2String(term_t mx, term_t num);
samer@0 245 foreign_t mlMxInfo(term_t mx, term_t size, term_t type);
samer@0 246 foreign_t mlMxSub2Ind(term_t mx, term_t subs, term_t ind);
samer@0 247 foreign_t mlMxGetFloat(term_t mx, term_t index, term_t value);
samer@0 248 foreign_t mlMxGetLogical(term_t mx, term_t index, term_t value);
samer@0 249 foreign_t mlMxGetCell(term_t mx, term_t index, term_t value);
samer@0 250 foreign_t mlMxGetField(term_t mx, term_t index, term_t field, term_t value);
samer@0 251 foreign_t mlMxGetReals(term_t mx, term_t values);
samer@0 252 foreign_t mlMxCreateNumeric(term_t size, term_t mx);
samer@0 253 foreign_t mlMxCreateCell(term_t size, term_t mx);
samer@0 254 foreign_t mlMxCreateString(term_t string, term_t mx);
samer@0 255 foreign_t mlMxPutFloat(term_t mx, term_t index, term_t value);
samer@0 256 foreign_t mlMxPutFloats(term_t mx, term_t index, term_t values);
samer@0 257 foreign_t mlMxPutCell(term_t mx, term_t index, term_t value);
samer@0 258 foreign_t mlMxCopyNoGC(term_t src, term_t dst);
samer@0 259 foreign_t mlMxNewRefGC(term_t src, term_t dst);
samer@0 260 }
samer@0 261
samer@0 262 install_t install() {
samer@37 263 PL_register_foreign("mlOPEN", 2, (void (*)())mlOpen, 0);
samer@37 264 PL_register_foreign("mlCLOSE", 1, (void (*)())mlClose, 0);
samer@37 265 PL_register_foreign("mlEXEC", 2, (void (*)())mlExec, 0);
samer@37 266 PL_register_foreign("mlWSNAME", 3, (void (*)())mlWSName, 0);
samer@37 267 PL_register_foreign("mlWSALLOC", 2, (void (*)())mlWSAlloc, 0);
samer@37 268 PL_register_foreign("mlWSGET", 2, (void (*)())mlWSGet,0);
samer@37 269 PL_register_foreign("mlWSPUT", 2, (void (*)())mlWSPut, 0);
samer@37 270 PL_register_foreign("mlMX2ATOM", 2, (void (*)())mlMx2Atom, 0);
samer@37 271 PL_register_foreign("mlMX2FLOAT", 2, (void (*)())mlMx2Float, 0);
samer@37 272 PL_register_foreign("mlMX2LOGICAL", 2, (void (*)())mlMx2Logical, 0);
samer@37 273 PL_register_foreign("mlMX2STRING", 2, (void (*)())mlMx2String, 0);
samer@37 274 PL_register_foreign("mlMXINFO", 3, (void (*)())mlMxInfo, 0);
samer@37 275 PL_register_foreign("mlSUB2IND", 3, (void (*)())mlMxSub2Ind, 0);
samer@37 276 PL_register_foreign("mlGETFLOAT", 3, (void (*)())mlMxGetFloat, 0);
samer@37 277 PL_register_foreign("mlGETLOGICAL", 3, (void (*)())mlMxGetLogical, 0);
samer@37 278 PL_register_foreign("mlGETCELL", 3, (void (*)())mlMxGetCell, 0);
samer@37 279 PL_register_foreign("mlGETFIELD", 4, (void (*)())mlMxGetField, 0);
samer@37 280 PL_register_foreign("mlGETREALS", 2, (void (*)())mlMxGetReals, 0);
samer@37 281 PL_register_foreign("mlCREATENUMERIC", 2, (void (*)())mlMxCreateNumeric, 0);
samer@37 282 PL_register_foreign("mlCREATECELL", 2, (void (*)())mlMxCreateCell, 0);
samer@37 283 PL_register_foreign("mlCREATESTRING", 2, (void (*)())mlMxCreateString, 0);
samer@37 284 PL_register_foreign("mlPUTFLOAT", 3, (void (*)())mlMxPutFloat, 0);
samer@37 285 PL_register_foreign("mlPUTFLOATS", 3, (void (*)())mlMxPutFloats, 0);
samer@37 286 PL_register_foreign("mlPUTCELL", 3, (void (*)())mlMxPutCell, 0);
samer@37 287 PL_register_foreign("mlCOPYNOGC", 2, (void (*)())mlMxCopyNoGC, 0);
samer@37 288 PL_register_foreign("mlNEWREFGC", 2, (void (*)())mlMxNewRefGC, 0);
samer@0 289
samer@0 290 mx_blob.magic = PL_BLOB_MAGIC;
samer@0 291 mx_blob.flags = PL_BLOB_UNIQUE;
samer@0 292 mx_blob.name = (char *)"mx";
samer@0 293 mx_blob.acquire = 0;
samer@0 294 mx_blob.release = mx_release;
samer@0 295 mx_blob.compare = mx_compare;
samer@0 296 mx_blob.write = 0; // mx_write;
samer@0 297
samer@0 298 mxnogc_blob.magic = PL_BLOB_MAGIC;
samer@0 299 mxnogc_blob.flags = PL_BLOB_UNIQUE;
samer@0 300 mxnogc_blob.name = (char *)"mxnogc";
samer@0 301 mxnogc_blob.acquire = 0;
samer@0 302 mxnogc_blob.release = mxnogc_release;
samer@0 303 mxnogc_blob.compare = mx_compare;
samer@0 304 mxnogc_blob.write = 0; // mx_write;
samer@0 305
samer@0 306 ws_blob.magic = PL_BLOB_MAGIC;
samer@0 307 ws_blob.flags = PL_BLOB_UNIQUE;
samer@0 308 ws_blob.name = (char *)"ws";
samer@0 309 ws_blob.acquire = 0;
samer@0 310 ws_blob.release = ws_release;
samer@0 311 ws_blob.compare = 0;
samer@0 312 ws_blob.write = 0;
samer@0 313
samer@0 314 mlerror=PL_new_functor(PL_new_atom("mlerror"),3);
samer@18 315 pthread_mutex_init(&EngMutex,NULL);
samer@0 316 }
samer@0 317
samer@0 318 void check(int rc) { if (!rc) printf("*** plml: Something failed.\n");}
samer@0 319
samer@0 320 void check_array_index(mxArray *mx, long i)
samer@0 321 {
samer@0 322 long n = mxGetNumberOfElements(mx);
samer@0 323 if (i<=0 || i>n) throw PlException("Index out of bounds");
samer@0 324 }
samer@0 325
samer@0 326 int unify_list_sizes(term_t list, const mwSize *ints, int num)
samer@0 327 {
samer@0 328 list=PL_copy_term_ref(list);
samer@0 329
samer@0 330 for (int i=0; i<num; i++) {
samer@0 331 term_t head=PL_new_term_ref();
samer@0 332 term_t tail=PL_new_term_ref();
samer@0 333 if (!PL_unify_list(list,head,tail)) PL_fail;
samer@0 334 if (!PL_unify_integer(head,ints[i])) PL_fail;
samer@0 335 list=tail;
samer@0 336 }
samer@0 337 return PL_unify_nil(list);
samer@0 338 }
samer@0 339
samer@0 340 int unify_list_doubles(term_t list, double *x, int n)
samer@0 341 {
samer@0 342 list=PL_copy_term_ref(list);
samer@0 343
samer@0 344 for (int i=0; i<n; i++) {
samer@0 345 term_t head=PL_new_term_ref();
samer@0 346 term_t tail=PL_new_term_ref();
samer@0 347 if (!PL_unify_list(list,head,tail)) PL_fail;
samer@0 348 if (!PL_unify_float(head,x[i])) PL_fail;
samer@0 349 list=tail;
samer@0 350 }
samer@0 351 return PL_unify_nil(list);
samer@0 352 }
samer@0 353
samer@0 354 // read list of integers from term and write to int array
samer@0 355 int get_list_integers(term_t list, long *len, int *vals)
samer@0 356 {
samer@0 357 term_t head=PL_new_term_ref();
samer@0 358 long n;
samer@0 359
samer@0 360 // copy term ref so as not to modify original
samer@0 361 list=PL_copy_term_ref(list);
samer@0 362 for (n=0;PL_get_list(list,head,list);n++) {
samer@0 363 if (!PL_get_integer(head,&vals[n])) return false;
samer@0 364 }
samer@0 365 if (!PL_get_nil(list)) return false;
samer@0 366 *len=n;
samer@0 367 return true;
samer@0 368 }
samer@0 369
samer@0 370 // read list of floats from term and write to double array
samer@0 371 int get_list_doubles(term_t list, long *len, double *vals)
samer@0 372 {
samer@0 373 term_t head=PL_new_term_ref();
samer@0 374 long n;
samer@0 375
samer@0 376 // copy term ref so as not to modify original
samer@0 377 list=PL_copy_term_ref(list);
samer@0 378 for (n=0;PL_get_list(list,head,list);n++) {
samer@0 379 if (!PL_get_float(head,&vals[n])) return false;
samer@0 380 }
samer@0 381 if (!PL_get_nil(list)) return false;
samer@0 382 *len=n;
samer@0 383 return true;
samer@0 384 }
samer@0 385
samer@0 386
samer@0 387
samer@0 388 /*
samer@0 389 * Member functions for SWIs blob atoms, which allow SWI to manage
samer@0 390 * garbage collection for user-defined data types.
samer@0 391 */
samer@0 392 int mx_release(atom_t a) {
samer@0 393 mxArray *p=ablob_to_mx(a);
samer@0 394 mxDestroyArray(p);
samer@0 395 return TRUE;
samer@0 396 }
samer@0 397
samer@0 398 int mx_compare(atom_t a, atom_t b) {
samer@0 399 mxArray *pa=ablob_to_mx(a);
samer@0 400 mxArray *pb=ablob_to_mx(b);
samer@0 401 if (pa<pb) return -1;
samer@0 402 else if (pa>pb) return 1;
samer@0 403 else return 0;
samer@0 404 }
samer@0 405
samer@0 406 int mxnogc_release(atom_t a) { return TRUE; }
samer@0 407
samer@0 408 /*
samer@0 409 // this requires some jiggery pokery to handle IOSTREAMS.
samer@0 410 int mx_write(IOSTREAM *s, atom_t a, int flags) {
samer@0 411 mxArray *p=ablob_to_mx(a);
samer@0 412 fprintf(s,"<mx:%p>",p);
samer@0 413 }
samer@0 414 */
samer@0 415
samer@0 416
samer@0 417 int ws_release(atom_t a) {
samer@0 418 struct wsvar *x=atom_to_wsvar(a);
samer@18 419 int rc;
samer@0 420 // printf("."); fflush(stdout); // sweet brevity
samer@0 421
samer@0 422 char buf[16];
samer@0 423 sprintf(buf,"clear %s",x->name);
samer@18 424 if (pthread_mutex_trylock(&EngMutex)==0) {
samer@18 425 rc=engEvalString(x->engine,buf) ? FALSE : TRUE;
samer@18 426 pthread_mutex_unlock(&EngMutex);
samer@18 427 } else {
samer@18 428 // printf("\n *** cannot release %s while engine locked ***\n",x->name);
samer@18 429 rc=FALSE;
samer@18 430 }
samer@18 431
samer@18 432 if (rc) {
samer@18 433 x->name[0]=0;
samer@18 434 x->engine=0;
samer@18 435 }
samer@0 436
samer@18 437 return rc;
samer@0 438 }
samer@0 439
samer@0 440 /* see mx_write */
samer@0 441 //int ws_write(IOSTREAM *s, atom_t a, int flags) {
samer@0 442 // struct wsvar *p=atom_to_wsvar(a);
samer@0 443 // mxArray *p=ablob_to_mx(a);
samer@0 444 // fprintf(s,"%s",p->name);
samer@0 445 //}
samer@0 446
samer@0 447
samer@0 448 /* Finds the engine associated with the given term
samer@0 449 * (which should just be an atom). Throws an exception
samer@0 450 * if the engine is not found.
samer@0 451 */
samer@0 452 static eng *findEngine(term_t id_term)
samer@0 453 {
samer@0 454 atom_t id;
samer@0 455 if(!PL_get_atom(id_term, &id)) {
samer@0 456 throw PlException("id is not an atom");
samer@0 457 }
samer@0 458 for (int i=0; i<MAXENGINES; i++) {
samer@0 459 if (engines[i].matches(id)) return &engines[i];
samer@0 460 }
samer@0 461 throw PlException("engine not found");
samer@0 462 }
samer@0 463
samer@0 464
samer@26 465 static void displayOutput(const char *prefix,const char *p)
samer@24 466 {
samer@24 467 while (*p) {
samer@24 468 fputs(prefix,stdout);
samer@24 469 while (*p && *p!='\n') putchar(*p++);
samer@24 470 putchar('\n'); if (*p) p++;
samer@24 471 }
samer@24 472 }
samer@24 473
samer@0 474 /*
samer@0 475 * Open a matlab engine using the given command and associate
samer@0 476 * it with the second term, which should be an atom.
samer@0 477 */
samer@0 478
samer@0 479 foreign_t mlOpen(term_t servercmd, term_t id_term)
samer@0 480 {
samer@0 481 try {
samer@0 482 findEngine(id_term);
samer@0 483 printf("mlOPEN/2: Engine %s already open\n",(const char *)PlTerm(id_term));
samer@0 484 PL_succeed;
samer@0 485 } catch (...) {}
samer@0 486
samer@0 487 try {
samer@0 488 // look for an unused engine structure
samer@0 489 for (int i=0; i<MAXENGINES; i++) {
samer@0 490 if (!engines[i].isOpen()) {
samer@0 491 atom_t id;
samer@0 492 check(PL_get_atom(id_term,&id));
samer@0 493 engines[i].open(PlTerm(servercmd), id);
samer@24 494 displayOutput("| ",engines[i].outbuf);
samer@0 495 PL_succeed;
samer@0 496 }
samer@0 497 }
samer@0 498 return PL_warning("mlOPEN/2: no more engines available.");
samer@0 499 } catch (PlException &e) {
samer@0 500 return e.plThrow();
samer@0 501 }
samer@0 502 }
samer@0 503
samer@0 504 // Close a previously opened Matlab engine
samer@0 505 foreign_t mlClose(term_t engine) {
samer@0 506 try {
samer@0 507 findEngine(engine)->close();
samer@0 508 PL_succeed;
samer@0 509 } catch (PlException &e) {
samer@0 510 return e.plThrow();
samer@0 511 }
samer@0 512 }
samer@0 513
samer@13 514
samer@18 515 static int raise_exception(const char *msg, const char *loc, const char *info) {
samer@14 516 // printf("\n!! raising exception: %s\n",msg);
samer@13 517 // return FALSE;
samer@13 518
samer@13 519 term_t ex = PL_new_term_ref();
samer@18 520 return PL_unify_term(ex, PL_FUNCTOR_CHARS, "error", 2,
samer@18 521 PL_FUNCTOR_CHARS, "plml_error", 3, PL_CHARS, msg, PL_CHARS, loc, PL_CHARS, info,
samer@18 522 PL_VARIABLE)
samer@13 523
samer@18 524 && PL_raise_exception(ex);
samer@13 525 }
samer@13 526
samer@0 527 /*
samer@0 528 * Workspace variable handling
samer@0 529 */
samer@0 530
samer@0 531 // This will create a new workspace variable with an unused name,
samer@0 532 // initialise it to an empty array (to reserve the name) and unify
samer@0 533 // the term (which must be a prolog variable) with a blob representing
samer@0 534 // the variable. This in turn points back to this engine so that
samer@0 535 // if garbage collected, the workspace variable is cleared.
samer@0 536 foreign_t mlWSAlloc(term_t eng, term_t blob) {
samer@0 537 // if varname is already bound, we should check
samer@0 538 // that the name has not been used in the workspace
samer@13 539 class eng *engine;
samer@13 540 try { engine=findEngine(eng); }
samer@18 541 catch (PlException &ex) { return ex.plThrow(); }
samer@0 542
samer@13 543 //printf("-- Entering mlWSALLOC \r"); fflush(stdout);
samer@13 544 struct wsvar x;
samer@0 545
samer@13 546 x.engine = engine->ep;
samer@13 547 x.id = engine->id;
samer@0 548
samer@15 549 // printf("-- mlWSAlloc: Calling uniquevar... \r"); fflush(stdout);
samer@18 550 { lock l;
samer@18 551 if (engEvalString(x.engine, "uniquevar([])"))
samer@18 552 return raise_exception("eval_failed","uniquevar","none");
samer@15 553 }
samer@15 554
samer@15 555 if (strncmp(engine->outbuf,">> \nans =\n\nt_",13)!=0) {
samer@15 556 //printf("\n** mlWSAlloc: output buffer looks bad: '%s'\n",engine->outbuf);
samer@18 557 return raise_exception("bad_output_buffer","uniquevar",engine->outbuf);
samer@15 558 }
samer@15 559
samer@16 560 unsigned int len=strlen(engine->outbuf+11)-2;
samer@15 561 if (len+1>sizeof(x.name)) {
samer@18 562 return raise_exception("name_too_long","uniquevar",engine->outbuf);
samer@15 563 }
samer@15 564 memcpy(x.name,engine->outbuf+11,len);
samer@15 565 x.name[len]=0;
samer@13 566
samer@13 567 return PL_unify_blob(blob,&x,sizeof(x),&ws_blob);
samer@0 568 }
samer@0 569
samer@0 570 foreign_t mlWSName(term_t blob, term_t name, term_t engine) {
samer@0 571 // if varname is already bound, we should check
samer@0 572 // that the name has not been used in the workspace
samer@0 573 try {
samer@0 574 struct wsvar *x = term_to_wsvar(blob);
samer@0 575 return ( PL_unify_atom_chars(name, x->name)
samer@0 576 && PL_unify_atom(engine, x->id));
samer@0 577 } catch (PlException &e) {
samer@0 578 PL_fail; // return e.plThrow();
samer@0 579 }
samer@0 580 }
samer@0 581
samer@0 582 // Get a named variable from the MATLAB workspace and return a term
samer@0 583 // containing a pointer to an mxArray (in Prolog's memory space).
samer@0 584 foreign_t mlWSGet(term_t var, term_t val) {
samer@0 585 try {
samer@0 586 struct wsvar *x = term_to_wsvar(var);
samer@18 587 lock l;
samer@18 588 // class eng *engine=findEngine(PlTerm(PlAtom(x->id)));
samer@18 589 // char *before=strdup(engine->outbuf);
samer@18 590 //printf("-- mlWSGET: calling get variable...\n");
samer@0 591 mxArray *p = engGetVariable(x->engine, x->name);
samer@18 592 //printf("-- mlWSGET: returned from get variable.\n");
samer@17 593 if (p) return PL_unify_blob(val, (void **)&p, sizeof(p), &mx_blob);
samer@17 594 else {
samer@18 595 //printf("\n!! mlWSGet: failed to get %s.\n",x->name);
samer@18 596 //printf("\n!! mlWSGet: before buffer: %s.\n",before);
samer@18 597 //printf("\n!! mlWSGet: before after: %s.\n",engine->outbuf);
samer@18 598 //return raise_exception("get_variable_failed",before,engine->outbuf);
samer@18 599 return raise_exception("get_variable_failed","mlWSGET",x->name);
samer@17 600 }
samer@0 601 } catch (PlException &e) {
samer@0 602 return e.plThrow();
samer@0 603 }
samer@0 604 }
samer@0 605
samer@18 606
samer@0 607 // Put an array back in Matlab workspace under given variable name
samer@0 608 foreign_t mlWSPut(term_t var, term_t val) {
samer@0 609 try {
samer@0 610 struct wsvar *x=term_to_wsvar(var);
samer@18 611 lock l;
samer@18 612 return engPutVariable(x->engine, x->name, term_to_mx(val)) ? FALSE : TRUE;
samer@0 613 } catch (PlException &e) {
samer@0 614 return e.plThrow();
samer@0 615 }
samer@0 616 }
samer@0 617
samer@0 618 /*
samer@0 619 * Executing MATLAB code
samer@0 620 */
samer@0 621
samer@0 622 // Call a Matlab engine to execute the given command
samer@0 623 foreign_t mlExec(term_t engine, term_t cmd)
samer@0 624 {
samer@13 625 // printf(" - mlExec: Entering \r"); fflush(stdout);
samer@0 626 try {
samer@0 627 eng *eng=findEngine(engine);
samer@0 628 const char *cmdstr=PlTerm(cmd);
samer@0 629 int cmdlen=strlen(cmdstr);
samer@0 630 int rc;
samer@18 631 lock l;
samer@0 632
samer@0 633 // if string is very long, send it via local mxArray
samer@0 634 if (cmdlen>MAXCMDLEN) {
samer@0 635 mxArray *mxcmd=mxCreateString(cmdstr);
samer@0 636 engPutVariable(eng->ep,"t__cmd",mxcmd);
samer@0 637 mxDestroyArray(mxcmd);
samer@0 638 cmdstr="eval(t__cmd)";
samer@0 639 cmdlen=strlen(cmdstr);
samer@0 640 }
samer@0 641
samer@15 642 { // scope for eval_cmd
samer@15 643 char *eval_cmd = new char[cmdlen+strlen(EVALFMT)-1];
samer@15 644 if (eval_cmd==NULL) throw PlException("Failed to allocate memory for command");
samer@15 645 sprintf(eval_cmd, EVALFMT, cmdstr);
samer@15 646 //printf("-- Calling Matlab engine... \r"); fflush(stdout);
samer@18 647 rc=engEvalString(eng->ep,eval_cmd);
samer@15 648 //printf("-- Returned from Matlab engine... \r"); fflush(stdout);
samer@15 649 delete [] eval_cmd;
samer@15 650 }
samer@15 651
samer@15 652 if (rc) { throw PlException("mlExec: engEvalString failed."); }
samer@0 653
samer@14 654 // EVALFMT starts with disp('#'). This means that the output buffer should
samer@15 655 // contain at least the 5 characters: ">> #\n". If they are not there,
samer@13 656 // something is terribly wrong and we must throw an exeption to avoid
samer@15 657 // locking up in triserver.
samer@14 658 if (strncmp(eng->outbuf,">> #\n",5)!=0) {
samer@18 659 throw PlException(PlCompound("bad_output_buffer",PlTermv("exec",eng->outbuf)));
samer@13 660 }
samer@23 661
samer@15 662 // write whatever is in the output buffer now, starting after the "#\n"
samer@24 663 displayOutput("| ", eng->outbuf+5);
samer@12 664
samer@15 665 #ifdef ALT_LASTERR
samer@15 666
samer@15 667 // --------------- ALTERNATIVE LASTERR SCHEME ------------------
samer@23 668 // call engine to eval lasterr, then scrape from output buffer: it's faster and easier.
samer@0 669
samer@14 670 rc=engEvalString(eng->ep,"lasterr");
samer@15 671 if (rc) { throw PlException("mlExec: unable to execute lasterr"); }
samer@14 672 if (strncmp(eng->outbuf,">> \nans =",9)!=0) {
samer@18 673 throw PlException(PlCompound("bad_output_buffer",PlTermv("lasterr",eng->outbuf)));
samer@14 674 }
samer@14 675
samer@14 676 if (strncmp(eng->outbuf+11," ''",7)!=0) {
samer@14 677 int len=strlen(eng->outbuf+11)-2;
samer@15 678 char *lasterr= new char[len+1];
samer@14 679 term_t desc=PL_new_term_ref();
samer@14 680 term_t cmd=PL_new_term_ref();
samer@14 681 term_t ex=PL_new_term_ref();
samer@15 682
samer@14 683 memcpy(lasterr,eng->outbuf+11,len);
samer@14 684 lasterr[len]=0;
samer@14 685
samer@14 686 PL_put_atom_chars(desc,lasterr);
samer@14 687 PL_put_atom_chars(cmd,cmdstr);
samer@15 688 delete [] lasterr;
samer@15 689
samer@14 690 check(PL_cons_functor(ex,mlerror,engine,desc,cmd));
samer@14 691 throw PlException(ex);
samer@14 692 }
samer@14 693
samer@15 694 #else
samer@14 695
samer@15 696 // --------------- ORIGINAL LASTERR SCHEME ------------------
samer@15 697 // Execution puts lasterr into t__ex, then we use engGetVariable to
samer@15 698 // retrieve it.
samer@15 699
samer@14 700 //printf(" - mlExec: output buffer: '%s'\n",eng->outbuf);
samer@0 701 mxArray *lasterr = engGetVariable(eng->ep, "t__ex");
samer@14 702 //printf(" - mlExec: output buffer after: ++%s++\n",eng->outbuf);
samer@13 703 //printf(" - mlExec: Got last error (%p) \r",lasterr); fflush(stdout);
samer@12 704
samer@12 705 if (!lasterr) {
samer@13 706 printf("\n** mlExec: unable to get lasterr.\n");
samer@14 707 printf("** mlExec: Output buffer contains: '%s'.\n",eng->outbuf);
samer@13 708 throw PlException("mlExec: unable to get lasterr");
samer@14 709 }
samer@0 710
samer@15 711 if (mxGetNumberOfElements(lasterr)==0) mxDestroyArray(lasterr);
samer@15 712 else {
samer@0 713 char *string=mxArrayToString(lasterr);
samer@0 714 mxDestroyArray(lasterr);
samer@0 715
samer@0 716 term_t desc=PL_new_term_ref();
samer@0 717 term_t cmd=PL_new_term_ref();
samer@0 718 term_t ex=PL_new_term_ref();
samer@0 719
samer@0 720 PL_put_atom_chars(desc,string);
samer@0 721 PL_put_atom_chars(cmd,cmdstr);
samer@0 722 mxFree(string);
samer@0 723 check(PL_cons_functor(ex,mlerror,engine,desc,cmd));
samer@0 724 throw PlException(ex);
samer@0 725
samer@15 726 }
samer@15 727 #endif
samer@23 728
samer@12 729 return TRUE;
samer@0 730 } catch (PlException &e) {
samer@0 731 return e.plThrow();
samer@0 732 }
samer@0 733 }
samer@0 734
samer@0 735 // Get a Prolog string out of a matlab char array
samer@0 736 foreign_t mlMx2String(term_t mx, term_t a)
samer@0 737 {
samer@0 738 try {
samer@0 739 char *str = mxArrayToString(term_to_mx(mx));
samer@0 740 if (!str) {
samer@0 741 return PL_warning("array is not a character array");
samer@0 742 }
samer@0 743 int rc = PL_unify_string_chars(a, str);
samer@0 744 mxFree(str);
samer@0 745 return rc;
samer@0 746 } catch (PlException &e) {
samer@0 747 return e.plThrow();
samer@0 748 }
samer@0 749 }
samer@0 750
samer@0 751 // Convert Matlab char array to a Prolog atom
samer@0 752 foreign_t mlMx2Atom(term_t mx, term_t a)
samer@0 753 {
samer@0 754 try {
samer@0 755 char *str = mxArrayToString(term_to_mx(mx));
samer@0 756 if (!str) {
samer@0 757 return PL_warning("array is not a character array");
samer@0 758 }
samer@0 759 int rc = PL_unify_atom_chars(a, str);
samer@0 760 mxFree(str);
samer@0 761 return rc;
samer@0 762 } catch (PlException &e) {
samer@0 763 return e.plThrow();
samer@0 764 }
samer@0 765 }
samer@0 766
samer@0 767 // Convert Matlab numerical array with one element to Prolog float
samer@0 768 foreign_t mlMx2Float(term_t mxterm, term_t a)
samer@0 769 {
samer@0 770 try {
samer@0 771 mxArray *mx = term_to_mx(mxterm);
samer@0 772 if (!mxIsDouble(mx)) {
samer@0 773 return PL_warning("not numeric");
samer@0 774 }
samer@0 775 if (mxGetNumberOfElements(mx)!=1) {
samer@0 776 return PL_warning("Not a scalar");
samer@0 777 }
samer@0 778 double x = mxGetScalar(mx);
samer@0 779
samer@0 780 return PL_unify_float(a, x);
samer@0 781 } catch (PlException &e) {
samer@0 782 return e.plThrow();
samer@0 783 }
samer@0 784 }
samer@0 785
samer@0 786 // Convert Matlab numerical (REAL) array to list
samer@0 787 foreign_t mlMxGetReals(term_t mxterm, term_t a)
samer@0 788 {
samer@0 789 try {
samer@0 790 mxArray *mx = term_to_mx(mxterm);
samer@0 791 int n = mxGetNumberOfElements(mx);
samer@0 792
samer@0 793 if (!mxIsDouble(mx)) return PL_warning("not numeric");
samer@0 794 return unify_list_doubles(a,mxGetPr(mx),n);
samer@0 795 } catch (PlException &e) {
samer@0 796 return e.plThrow();
samer@0 797 }
samer@0 798 }
samer@0 799
samer@0 800 // Convert Matlab logical or numeric array with one element to
samer@0 801 // Prolog integer 0 or 1 (does not fail or succeed depending on
samer@0 802 // logical value - this is can be done by prolog code).
samer@0 803 foreign_t mlMx2Logical(term_t mxterm, term_t a)
samer@0 804 {
samer@0 805 try {
samer@0 806 mxArray *mx = term_to_mx(mxterm);
samer@0 807 if (mxGetNumberOfElements(mx) != 1) return PL_warning("Not a scalar");
samer@0 808
samer@0 809 int f;
samer@0 810 if (mxIsLogical(mx)) {
samer@0 811 f = mxIsLogicalScalarTrue(mx) ? 1 : 0;
samer@0 812 } else if (mxIsDouble(mx)) {
samer@0 813 f = (mxGetScalar(mx) > 0) ? 1 : 0;
samer@0 814 } else {
samer@0 815 return PL_warning("neither numeric nor logical (captain)");
samer@0 816 }
samer@0 817
samer@0 818 return PL_unify_integer(a,f);
samer@0 819 } catch (PlException &e) {
samer@0 820 return e.plThrow();
samer@0 821 }
samer@0 822 }
samer@0 823
samer@0 824 // Get array information (size and type of elements)
samer@0 825 foreign_t mlMxInfo(term_t mxterm, term_t size, term_t type)
samer@0 826 {
samer@0 827 try {
samer@0 828 mxArray *mx = term_to_mx(mxterm);
samer@0 829 long ndims = mxGetNumberOfDimensions(mx);
samer@0 830 const mwSize *dims = mxGetDimensions(mx);
samer@0 831 const char *cnm = mxGetClassName(mx);
samer@0 832
samer@0 833 if (PL_unify_atom_chars(type, cnm)) {
samer@0 834 if (dims[ndims-1]==1) ndims--; // remove trailing singletons
samer@0 835 return unify_list_sizes(size,dims,ndims);
samer@0 836 }
samer@0 837 PL_fail;
samer@0 838 } catch (PlException &e) {
samer@0 839 return e.plThrow();
samer@0 840 }
samer@0 841 }
samer@0 842
samer@0 843 // Convert multidimensional subscript to linear index
samer@0 844 foreign_t mlMxSub2Ind(term_t mxterm, term_t substerm, term_t indterm)
samer@0 845 {
samer@0 846 try {
samer@0 847 mxArray *mx=term_to_mx(mxterm);
samer@0 848 mwIndex subs[64]; // 64 dimensional should be enough!
samer@0 849 long nsubs;
samer@0 850
samer@0 851 // get substerm as int array
samer@0 852 if (!get_list_integers(substerm,&nsubs,(int *)subs)) // !!
samer@0 853 return PL_warning("Bad subscript list");
samer@0 854
samer@0 855 // switch to zero-based subscripts
samer@0 856 for (int i=0; i<nsubs; i++) subs[i]--;
samer@0 857
samer@0 858 int ind = mxCalcSingleSubscript(mx,nsubs,subs);
samer@0 859 check_array_index(mx,ind);
samer@0 860
samer@0 861 return PL_unify_integer(indterm, ind);
samer@0 862 } catch (PlException &e) {
samer@0 863 return e.plThrow();
samer@0 864 }
samer@0 865 }
samer@0 866
samer@0 867 // Dereference double from mx array
samer@0 868 foreign_t mlMxGetFloat(term_t mxterm, term_t index, term_t value)
samer@0 869 {
samer@0 870 try {
samer@0 871 mxArray *mx = term_to_mx(mxterm);
samer@0 872 long i;
samer@0 873
samer@0 874 check(PL_get_long(index,&i));
samer@0 875 check_array_index(mx,i);
samer@0 876 if (!mxIsDouble(mx)) { return PL_warning("not numeric"); }
samer@0 877
samer@0 878 double *p = (double *)mxGetData(mx);
samer@0 879 return PL_unify_float(value, p[i-1]);
samer@0 880 } catch (PlException &e) {
samer@0 881 return e.plThrow();
samer@0 882 }
samer@0 883 }
samer@0 884
samer@0 885 // Dereference logical from mx array
samer@0 886 foreign_t mlMxGetLogical(term_t mxterm, term_t index, term_t value)
samer@0 887 {
samer@0 888 try {
samer@0 889 mxArray *mx = term_to_mx(mxterm);
samer@0 890 long i;
samer@0 891
samer@0 892 check(PL_get_long(index,&i));
samer@0 893 check_array_index(mx,i);
samer@0 894
samer@0 895 if (mxIsLogical(mx)) {
samer@0 896 mxLogical *p = mxGetLogicals(mx);
samer@0 897 return PL_unify_integer(value,(p[i-1]) ? 1 : 0);
samer@0 898 } else if (mxIsDouble(mx)) {
samer@0 899 double *p = (double *)mxGetData(mx);
samer@0 900 return PL_unify_integer(value, (p[i-1]>0) ? 1 : 0);
samer@0 901 } else {
samer@0 902 return PL_warning("neither logical nor numeric");
samer@0 903 }
samer@0 904
samer@0 905 } catch (PlException &e) {
samer@0 906 return e.plThrow();
samer@0 907 }
samer@0 908 }
samer@0 909
samer@0 910 // Dereference mxArray from cell array
samer@0 911 // Note that we return a non-gargage collected atom, otherwise,
samer@0 912 // the parent cell array would be spoiled when one of its elements
samer@0 913 // is released and destroyed. However, if the parent cell is
samer@0 914 // released and destroyed, any remaining references to elements
samer@0 915 // will be prematurely invalidated.
samer@0 916 // FIXME: This is almost certain to confuse the garbage collector
samer@0 917 foreign_t mlMxGetCell(term_t mxterm, term_t index, term_t value)
samer@0 918 {
samer@0 919 try {
samer@0 920 mxArray *mx = term_to_mx(mxterm);
samer@0 921 long i;
samer@0 922
samer@0 923 check(PL_get_long(index,&i));
samer@0 924 check_array_index(mx,i);
samer@0 925 if (!mxIsCell(mx)) { return PL_warning("not numeric"); }
samer@0 926
samer@0 927 mxArray *p = mxGetCell(mx,i-1);
samer@0 928 return PL_unify_blob(value, (void **)&p, sizeof(p), &mxnogc_blob);
samer@0 929 } catch (PlException &e) {
samer@0 930 return e.plThrow();
samer@0 931 }
samer@0 932 }
samer@0 933
samer@0 934 foreign_t mlMxGetField(term_t mxterm, term_t index, term_t field, term_t value)
samer@0 935 {
samer@0 936 try {
samer@0 937 mxArray *mx = term_to_mx(mxterm);
samer@0 938 long i;
samer@0 939 char *fname;
samer@0 940
samer@0 941 check(PL_get_long(index,&i));
samer@0 942 check(PL_get_atom_chars(field,&fname));
samer@0 943 check_array_index(mx,i);
samer@0 944 if (!mxIsStruct(mx)) { return PL_warning("not a structure"); }
samer@0 945
samer@0 946 mxArray *p = mxGetField(mx,i-1,fname);
samer@0 947 if (!p) return PL_warning("Field not present");
samer@0 948 return PL_unify_blob(value, (void **)&p, sizeof(p), &mxnogc_blob);
samer@0 949 } catch (PlException &e) {
samer@0 950 return e.plThrow();
samer@0 951 }
samer@0 952 }
samer@0 953
samer@0 954 // Create numeric array. Currently only real double arrays created
samer@0 955 foreign_t mlMxCreateNumeric(term_t size, term_t mx) {
samer@0 956 try {
samer@0 957 mwSize dims[64];
samer@0 958 long ndims;
samer@0 959
samer@0 960 // get size as int array
samer@0 961 if (!get_list_integers(size,&ndims,(int *)dims))
samer@0 962 return PL_warning("Bad size list");
samer@0 963
samer@0 964 mxArray *p = mxCreateNumericArray(ndims,dims,mxDOUBLE_CLASS,mxREAL);
samer@0 965 return PL_unify_blob(mx, (void **)&p, sizeof(p), &mxnogc_blob);
samer@0 966 } catch (PlException &e) {
samer@0 967 return e.plThrow();
samer@0 968 }
samer@0 969 }
samer@0 970
samer@0 971 // Create cell array.
samer@0 972 foreign_t mlMxCreateCell(term_t size, term_t mx) {
samer@0 973 try {
samer@0 974 mwSize dims[64];
samer@0 975 long ndims;
samer@0 976
samer@0 977 // get size as int array
samer@0 978 if (!get_list_integers(size,&ndims,(int *)dims))
samer@0 979 return PL_warning("Bad size list");
samer@0 980
samer@0 981 mxArray *p = mxCreateCellArray(ndims,dims);
samer@0 982 return PL_unify_blob(mx, (void **)&p, sizeof(p), &mxnogc_blob);
samer@0 983 } catch (PlException &e) {
samer@0 984 return e.plThrow();
samer@0 985 }
samer@0 986 }
samer@0 987
samer@0 988 // Create numeric array. Currently only real double arrays created
samer@0 989 foreign_t mlMxCreateString(term_t string, term_t mx) {
samer@0 990 try {
samer@0 991 mxArray *p = mxCreateString(PlTerm(string));
samer@0 992 return PL_unify_blob(mx, (void **)&p, sizeof(p), &mxnogc_blob);
samer@0 993 } catch (PlException &e) {
samer@0 994 return e.plThrow();
samer@0 995 }
samer@0 996 }
samer@0 997
samer@0 998
samer@0 999 // Write float into double array
samer@0 1000 foreign_t mlMxPutFloat(term_t mxterm, term_t index, term_t value)
samer@0 1001 {
samer@0 1002 try {
samer@0 1003 mxArray *mx = term_to_mx(mxterm);
samer@0 1004 long i;
samer@0 1005 double val;
samer@0 1006
samer@0 1007 if (!mxIsDouble(mx)) { return PL_warning("not numeric"); }
samer@0 1008 check(PL_get_long(index,&i));
samer@0 1009 check(PL_get_float(value,&val));
samer@0 1010 check_array_index(mx,i);
samer@0 1011 *(mxGetPr(mx)+i-1)=val;
samer@0 1012 return true;
samer@0 1013 } catch (PlException &e) {
samer@0 1014 return e.plThrow();
samer@0 1015 }
samer@0 1016 }
samer@0 1017
samer@0 1018 // Write list of floats into double array starting at given index
samer@0 1019 foreign_t mlMxPutFloats(term_t mxterm, term_t index, term_t values)
samer@0 1020 {
samer@0 1021 try {
samer@0 1022 mxArray *mx = term_to_mx(mxterm);
samer@0 1023 long i, len;
samer@0 1024
samer@0 1025 if (!mxIsDouble(mx)) { return PL_warning("not numeric"); }
samer@0 1026 check(PL_get_long(index,&i));
samer@0 1027 check_array_index(mx,i);
samer@0 1028 get_list_doubles(values,&len,mxGetPr(mx)+i-1);
samer@0 1029 return true;
samer@0 1030 } catch (PlException &e) {
samer@0 1031 return e.plThrow();
samer@0 1032 }
samer@0 1033 }
samer@0 1034
samer@0 1035 // Put an mxArray into a cell array
samer@0 1036 // IMPORTANT: the object being put must in a non-memory managed atom
samer@0 1037 foreign_t mlMxPutCell(term_t mxterm, term_t index, term_t element)
samer@0 1038 {
samer@0 1039 try {
samer@0 1040 mxArray *mx = term_to_mx(mxterm);
samer@0 1041 mxArray *el = term_to_mx(element);
samer@0 1042 long i;
samer@0 1043
samer@0 1044 if (!mxIsCell(mx)) { return PL_warning("not a cell array"); }
samer@0 1045 check(PL_get_long(index,&i));
samer@0 1046 check_array_index(mx,i);
samer@0 1047 mxSetCell(mx,i-1,el);
samer@0 1048 return true;
samer@0 1049 } catch (PlException &e) {
samer@0 1050 return e.plThrow();
samer@0 1051 }
samer@0 1052 }
samer@0 1053
samer@0 1054 foreign_t mlMxCopyNoGC(term_t in, term_t out)
samer@0 1055 {
samer@0 1056 try {
samer@0 1057 mxArray *mx = term_to_mx(in);
samer@0 1058 mxArray *p = mxDuplicateArray(mx);
samer@0 1059 return PL_unify_blob(out, (void **)&p, sizeof(p), &mxnogc_blob);
samer@0 1060 } catch (PlException &e) {
samer@0 1061 return e.plThrow();
samer@0 1062 }
samer@0 1063 }
samer@0 1064
samer@0 1065 foreign_t mlMxNewRefGC(term_t in, term_t out)
samer@0 1066 {
samer@0 1067 try {
samer@0 1068 mxArray *p = term_to_mx(in);
samer@0 1069 return PL_unify_blob(out, (void **)&p, sizeof(p), &mx_blob);
samer@0 1070 } catch (PlException &e) {
samer@0 1071 return e.plThrow();
samer@0 1072 }
samer@0 1073 }
samer@0 1074
samer@0 1075
samer@0 1076 /*
samer@0 1077 * Local Variables:
samer@0 1078 * c-basic-offset: 2
samer@0 1079 * indent-tabs-mode: nil
samer@0 1080 * End:
samer@0 1081 */
samer@0 1082