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@0
|
82 #include "engine.h"
|
samer@0
|
83
|
samer@0
|
84 /* The maximum number of simultaneous connections to Matlab from one
|
samer@0
|
85 Prolog process. */
|
samer@0
|
86 #define MAXENGINES 4
|
samer@0
|
87 #define BUFSIZE 32768 // buffer for matlab output
|
samer@0
|
88 #define MAXCMDLEN 256
|
samer@0
|
89 // #define EVALFMT "t__ex=[];\ntry\n%s\ncatch t__ex\ndisp(getReport(t__ex))\nend"
|
samer@0
|
90 #define EVALFMT "lasterr(''); %s\nt__ex=lasterr;"
|
samer@0
|
91
|
samer@0
|
92 using namespace std;
|
samer@0
|
93
|
samer@0
|
94 // This is for a SWI Prolog BLOB type to manage mxArray pointers. It
|
samer@0
|
95 // means that the Prolog garbage collector can deal with freeing
|
samer@0
|
96 // unreferenced mxArrays automatically.
|
samer@0
|
97
|
samer@0
|
98
|
samer@0
|
99 #ifdef MX_API_VER
|
samer@0
|
100 #if MX_API_VER >= 0x07030000
|
samer@0
|
101 #else
|
samer@0
|
102 typedef int mwSize;
|
samer@0
|
103 typedef int mwIndex;
|
samer@0
|
104 #endif
|
samer@0
|
105 #else
|
samer@0
|
106 typedef int mwSize;
|
samer@0
|
107 typedef int mwIndex;
|
samer@0
|
108 #endif
|
samer@0
|
109
|
samer@0
|
110 static PL_blob_t mx_blob;
|
samer@0
|
111 static PL_blob_t mxnogc_blob;
|
samer@0
|
112 static functor_t mlerror;
|
samer@0
|
113
|
samer@0
|
114 // Extract an mxArray * from a BLOB atom
|
samer@0
|
115 static mxArray *term_to_mx(term_t t) {
|
samer@0
|
116 PL_blob_t *type;
|
samer@0
|
117 size_t len;
|
samer@0
|
118 void *p;
|
samer@0
|
119
|
samer@0
|
120 PL_get_blob(t, &p, &len, &type);
|
samer@0
|
121 if (type != &mx_blob && type != &mxnogc_blob) {
|
samer@0
|
122 throw PlException("Not an mx variable");
|
samer@0
|
123 }
|
samer@0
|
124 return *(mxArray **) p;
|
samer@0
|
125 }
|
samer@0
|
126
|
samer@0
|
127 static mxArray *ablob_to_mx(atom_t a) {
|
samer@0
|
128 return term_to_mx(PlTerm(PlAtom(a)));
|
samer@0
|
129 }
|
samer@0
|
130
|
samer@0
|
131 // This is for a SWI Prolog BLOB type to manage Matlab workspace
|
samer@0
|
132 // variables. The variable is cleared and the name reclaimed
|
samer@0
|
133 // when the blob is garbage collected. This kind of blob has no data
|
samer@0
|
134 // apart from the atom's name (ie the variable's name)
|
samer@0
|
135
|
samer@0
|
136 static PL_blob_t ws_blob;
|
samer@0
|
137
|
samer@0
|
138 // structure for keeping track of workspace variables
|
samer@0
|
139 struct wsvar {
|
samer@0
|
140 char name[8]; // designed for short machine generated names
|
samer@0
|
141 Engine *engine; // the matlab engine which owns this variable
|
samer@0
|
142 atom_t id; // the id of this engine
|
samer@0
|
143 };
|
samer@0
|
144
|
samer@0
|
145 // extract wsvar from blob term
|
samer@0
|
146 static struct wsvar *term_to_wsvar(term_t t) {
|
samer@0
|
147 PL_blob_t *type;
|
samer@0
|
148 size_t len;
|
samer@0
|
149 void *p;
|
samer@0
|
150
|
samer@0
|
151 PL_get_blob(t, &p, &len, &type);
|
samer@0
|
152 if (type != &ws_blob) {
|
samer@0
|
153 throw PlException("Not a ws variable");
|
samer@0
|
154 }
|
samer@0
|
155 return (struct wsvar *) p;
|
samer@0
|
156 }
|
samer@0
|
157
|
samer@0
|
158 // extract wsvar from atom by converting to term first
|
samer@0
|
159 static struct wsvar *atom_to_wsvar(atom_t a) {
|
samer@0
|
160 return term_to_wsvar(PlTerm(PlAtom(a)));
|
samer@0
|
161 }
|
samer@0
|
162
|
samer@0
|
163
|
samer@0
|
164 /* MATLAB engine wrapper class */
|
samer@0
|
165 class eng {
|
samer@0
|
166 public:
|
samer@0
|
167 Engine *ep; // MATLAB API engine pointer
|
samer@0
|
168 atom_t id; // atom associated with this engine
|
samer@0
|
169 char *outbuf; // buffer for textual output from MATLAB
|
samer@0
|
170
|
samer@0
|
171 eng(): ep(NULL), id(PL_new_atom("")), outbuf(NULL) {}
|
samer@0
|
172
|
samer@0
|
173 void open(const char *cmd, atom_t id) {
|
samer@0
|
174 ep=engOpen(cmd);
|
samer@0
|
175
|
samer@0
|
176 if (ep) {
|
samer@0
|
177 this->id=id;
|
samer@0
|
178 outbuf=new char[BUFSIZE];
|
samer@0
|
179 outbuf[BUFSIZE-1]=0;
|
samer@0
|
180 engOutputBuffer(ep,outbuf,BUFSIZE-1);
|
samer@0
|
181 printf("Matlab engine (%s) open.\n",PL_atom_chars(id));
|
samer@0
|
182 } else {
|
samer@0
|
183 throw PlException("open engine failed");
|
samer@0
|
184 }
|
samer@0
|
185 }
|
samer@0
|
186 void close() {
|
samer@0
|
187 engClose(ep);
|
samer@0
|
188 id = PL_new_atom("");
|
samer@0
|
189 delete [] outbuf;
|
samer@0
|
190 ep=0;
|
samer@0
|
191 }
|
samer@0
|
192
|
samer@0
|
193 bool matches(atom_t id) const { return id==this->id; }
|
samer@0
|
194 bool isOpen() const { return ep!=NULL; }
|
samer@0
|
195 };
|
samer@0
|
196
|
samer@0
|
197 // pool of engines, all initially closed
|
samer@0
|
198 static eng engines[MAXENGINES];
|
samer@0
|
199 // functor to be used to wrap array pointers
|
samer@0
|
200
|
samer@0
|
201 extern "C" {
|
samer@0
|
202 // Functions for mx array atom type
|
samer@0
|
203 int mx_release(atom_t a);
|
samer@0
|
204 int mx_compare(atom_t a, atom_t b);
|
samer@0
|
205 // int mx_write(IOSTREAM *s, atom_t a, int flags);
|
samer@0
|
206 int mxnogc_release(atom_t a);
|
samer@0
|
207
|
samer@0
|
208 // Functions for WS variable atom type
|
samer@0
|
209 int ws_release(atom_t a);
|
samer@0
|
210 // int ws_write(IOSTREAM *s, atom_t a, int flags);
|
samer@0
|
211 }
|
samer@0
|
212
|
samer@0
|
213 extern "C" {
|
samer@0
|
214 install_t install();
|
samer@0
|
215 foreign_t mlOpen(term_t servercmd, term_t engine);
|
samer@0
|
216 foreign_t mlClose(term_t engine);
|
samer@0
|
217 foreign_t mlExec(term_t engine, term_t cmd);
|
samer@0
|
218 foreign_t mlWSGet(term_t var, term_t val);
|
samer@0
|
219 foreign_t mlWSPut(term_t var, term_t val);
|
samer@0
|
220 foreign_t mlWSName(term_t engine, term_t var, term_t id);
|
samer@0
|
221 foreign_t mlWSAlloc(term_t engine, term_t var);
|
samer@0
|
222 foreign_t mlMx2Atom(term_t mx, term_t atom);
|
samer@0
|
223 foreign_t mlMx2Float(term_t mx, term_t num);
|
samer@0
|
224 foreign_t mlMx2Logical(term_t mx, term_t num);
|
samer@0
|
225 foreign_t mlMx2String(term_t mx, term_t num);
|
samer@0
|
226 foreign_t mlMxInfo(term_t mx, term_t size, term_t type);
|
samer@0
|
227 foreign_t mlMxSub2Ind(term_t mx, term_t subs, term_t ind);
|
samer@0
|
228 foreign_t mlMxGetFloat(term_t mx, term_t index, term_t value);
|
samer@0
|
229 foreign_t mlMxGetLogical(term_t mx, term_t index, term_t value);
|
samer@0
|
230 foreign_t mlMxGetCell(term_t mx, term_t index, term_t value);
|
samer@0
|
231 foreign_t mlMxGetField(term_t mx, term_t index, term_t field, term_t value);
|
samer@0
|
232 foreign_t mlMxGetReals(term_t mx, term_t values);
|
samer@0
|
233 foreign_t mlMxCreateNumeric(term_t size, term_t mx);
|
samer@0
|
234 foreign_t mlMxCreateCell(term_t size, term_t mx);
|
samer@0
|
235 foreign_t mlMxCreateString(term_t string, term_t mx);
|
samer@0
|
236 foreign_t mlMxPutFloat(term_t mx, term_t index, term_t value);
|
samer@0
|
237 foreign_t mlMxPutFloats(term_t mx, term_t index, term_t values);
|
samer@0
|
238 foreign_t mlMxPutCell(term_t mx, term_t index, term_t value);
|
samer@0
|
239 foreign_t mlMxCopyNoGC(term_t src, term_t dst);
|
samer@0
|
240 foreign_t mlMxNewRefGC(term_t src, term_t dst);
|
samer@0
|
241 }
|
samer@0
|
242
|
samer@0
|
243 install_t install() {
|
samer@0
|
244 PL_register_foreign("mlOPEN", 2, (void *)mlOpen, 0);
|
samer@0
|
245 PL_register_foreign("mlCLOSE", 1, (void *)mlClose, 0);
|
samer@0
|
246 PL_register_foreign("mlEXEC", 2, (void *)mlExec, 0);
|
samer@0
|
247 PL_register_foreign("mlWSNAME", 3, (void *)mlWSName, 0);
|
samer@0
|
248 PL_register_foreign("mlWSALLOC", 2, (void *)mlWSAlloc, 0);
|
samer@0
|
249 PL_register_foreign("mlWSGET", 2, (void *)mlWSGet,0);
|
samer@0
|
250 PL_register_foreign("mlWSPUT", 2, (void *)mlWSPut, 0);
|
samer@0
|
251 PL_register_foreign("mlMX2ATOM", 2, (void *)mlMx2Atom, 0);
|
samer@0
|
252 PL_register_foreign("mlMX2FLOAT", 2, (void *)mlMx2Float, 0);
|
samer@0
|
253 PL_register_foreign("mlMX2LOGICAL", 2, (void *)mlMx2Logical, 0);
|
samer@0
|
254 PL_register_foreign("mlMX2STRING", 2, (void *)mlMx2String, 0);
|
samer@0
|
255 PL_register_foreign("mlMXINFO", 3, (void *)mlMxInfo, 0);
|
samer@0
|
256 PL_register_foreign("mlSUB2IND", 3, (void *)mlMxSub2Ind, 0);
|
samer@0
|
257 PL_register_foreign("mlGETFLOAT", 3, (void *)mlMxGetFloat, 0);
|
samer@0
|
258 PL_register_foreign("mlGETLOGICAL", 3, (void *)mlMxGetLogical, 0);
|
samer@0
|
259 PL_register_foreign("mlGETCELL", 3, (void *)mlMxGetCell, 0);
|
samer@0
|
260 PL_register_foreign("mlGETFIELD", 4, (void *)mlMxGetField, 0);
|
samer@0
|
261 PL_register_foreign("mlGETREALS", 2, (void *)mlMxGetReals, 0);
|
samer@0
|
262 PL_register_foreign("mlCREATENUMERIC", 2, (void *)mlMxCreateNumeric, 0);
|
samer@0
|
263 PL_register_foreign("mlCREATECELL", 2, (void *)mlMxCreateCell, 0);
|
samer@0
|
264 PL_register_foreign("mlCREATESTRING", 2, (void *)mlMxCreateString, 0);
|
samer@0
|
265 PL_register_foreign("mlPUTFLOAT", 3, (void *)mlMxPutFloat, 0);
|
samer@0
|
266 PL_register_foreign("mlPUTFLOATS", 3, (void *)mlMxPutFloats, 0);
|
samer@0
|
267 PL_register_foreign("mlPUTCELL", 3, (void *)mlMxPutCell, 0);
|
samer@0
|
268 PL_register_foreign("mlCOPYNOGC", 2, (void *)mlMxCopyNoGC, 0);
|
samer@0
|
269 PL_register_foreign("mlNEWREFGC", 2, (void *)mlMxNewRefGC, 0);
|
samer@0
|
270
|
samer@0
|
271 mx_blob.magic = PL_BLOB_MAGIC;
|
samer@0
|
272 mx_blob.flags = PL_BLOB_UNIQUE;
|
samer@0
|
273 mx_blob.name = (char *)"mx";
|
samer@0
|
274 mx_blob.acquire = 0;
|
samer@0
|
275 mx_blob.release = mx_release;
|
samer@0
|
276 mx_blob.compare = mx_compare;
|
samer@0
|
277 mx_blob.write = 0; // mx_write;
|
samer@0
|
278
|
samer@0
|
279 mxnogc_blob.magic = PL_BLOB_MAGIC;
|
samer@0
|
280 mxnogc_blob.flags = PL_BLOB_UNIQUE;
|
samer@0
|
281 mxnogc_blob.name = (char *)"mxnogc";
|
samer@0
|
282 mxnogc_blob.acquire = 0;
|
samer@0
|
283 mxnogc_blob.release = mxnogc_release;
|
samer@0
|
284 mxnogc_blob.compare = mx_compare;
|
samer@0
|
285 mxnogc_blob.write = 0; // mx_write;
|
samer@0
|
286
|
samer@0
|
287 ws_blob.magic = PL_BLOB_MAGIC;
|
samer@0
|
288 ws_blob.flags = PL_BLOB_UNIQUE;
|
samer@0
|
289 ws_blob.name = (char *)"ws";
|
samer@0
|
290 ws_blob.acquire = 0;
|
samer@0
|
291 ws_blob.release = ws_release;
|
samer@0
|
292 ws_blob.compare = 0;
|
samer@0
|
293 ws_blob.write = 0;
|
samer@0
|
294
|
samer@0
|
295 mlerror=PL_new_functor(PL_new_atom("mlerror"),3);
|
samer@0
|
296 }
|
samer@0
|
297
|
samer@0
|
298 void check(int rc) { if (!rc) printf("*** plml: Something failed.\n");}
|
samer@0
|
299
|
samer@0
|
300 void check_array_index(mxArray *mx, long i)
|
samer@0
|
301 {
|
samer@0
|
302 long n = mxGetNumberOfElements(mx);
|
samer@0
|
303 if (i<=0 || i>n) throw PlException("Index out of bounds");
|
samer@0
|
304 }
|
samer@0
|
305
|
samer@0
|
306 int unify_list_sizes(term_t list, const mwSize *ints, int num)
|
samer@0
|
307 {
|
samer@0
|
308 list=PL_copy_term_ref(list);
|
samer@0
|
309
|
samer@0
|
310 for (int i=0; i<num; i++) {
|
samer@0
|
311 term_t head=PL_new_term_ref();
|
samer@0
|
312 term_t tail=PL_new_term_ref();
|
samer@0
|
313 if (!PL_unify_list(list,head,tail)) PL_fail;
|
samer@0
|
314 if (!PL_unify_integer(head,ints[i])) PL_fail;
|
samer@0
|
315 list=tail;
|
samer@0
|
316 }
|
samer@0
|
317 return PL_unify_nil(list);
|
samer@0
|
318 }
|
samer@0
|
319
|
samer@0
|
320 int unify_list_doubles(term_t list, double *x, int n)
|
samer@0
|
321 {
|
samer@0
|
322 list=PL_copy_term_ref(list);
|
samer@0
|
323
|
samer@0
|
324 for (int i=0; i<n; i++) {
|
samer@0
|
325 term_t head=PL_new_term_ref();
|
samer@0
|
326 term_t tail=PL_new_term_ref();
|
samer@0
|
327 if (!PL_unify_list(list,head,tail)) PL_fail;
|
samer@0
|
328 if (!PL_unify_float(head,x[i])) PL_fail;
|
samer@0
|
329 list=tail;
|
samer@0
|
330 }
|
samer@0
|
331 return PL_unify_nil(list);
|
samer@0
|
332 }
|
samer@0
|
333
|
samer@0
|
334 // read list of integers from term and write to int array
|
samer@0
|
335 int get_list_integers(term_t list, long *len, int *vals)
|
samer@0
|
336 {
|
samer@0
|
337 term_t head=PL_new_term_ref();
|
samer@0
|
338 long n;
|
samer@0
|
339
|
samer@0
|
340 // copy term ref so as not to modify original
|
samer@0
|
341 list=PL_copy_term_ref(list);
|
samer@0
|
342 for (n=0;PL_get_list(list,head,list);n++) {
|
samer@0
|
343 if (!PL_get_integer(head,&vals[n])) return false;
|
samer@0
|
344 }
|
samer@0
|
345 if (!PL_get_nil(list)) return false;
|
samer@0
|
346 *len=n;
|
samer@0
|
347 return true;
|
samer@0
|
348 }
|
samer@0
|
349
|
samer@0
|
350 // read list of floats from term and write to double array
|
samer@0
|
351 int get_list_doubles(term_t list, long *len, double *vals)
|
samer@0
|
352 {
|
samer@0
|
353 term_t head=PL_new_term_ref();
|
samer@0
|
354 long n;
|
samer@0
|
355
|
samer@0
|
356 // copy term ref so as not to modify original
|
samer@0
|
357 list=PL_copy_term_ref(list);
|
samer@0
|
358 for (n=0;PL_get_list(list,head,list);n++) {
|
samer@0
|
359 if (!PL_get_float(head,&vals[n])) return false;
|
samer@0
|
360 }
|
samer@0
|
361 if (!PL_get_nil(list)) return false;
|
samer@0
|
362 *len=n;
|
samer@0
|
363 return true;
|
samer@0
|
364 }
|
samer@0
|
365
|
samer@0
|
366
|
samer@0
|
367
|
samer@0
|
368 /*
|
samer@0
|
369 * Member functions for SWIs blob atoms, which allow SWI to manage
|
samer@0
|
370 * garbage collection for user-defined data types.
|
samer@0
|
371 */
|
samer@0
|
372 int mx_release(atom_t a) {
|
samer@0
|
373 mxArray *p=ablob_to_mx(a);
|
samer@0
|
374 mxDestroyArray(p);
|
samer@0
|
375 return TRUE;
|
samer@0
|
376 }
|
samer@0
|
377
|
samer@0
|
378 int mx_compare(atom_t a, atom_t b) {
|
samer@0
|
379 mxArray *pa=ablob_to_mx(a);
|
samer@0
|
380 mxArray *pb=ablob_to_mx(b);
|
samer@0
|
381 if (pa<pb) return -1;
|
samer@0
|
382 else if (pa>pb) return 1;
|
samer@0
|
383 else return 0;
|
samer@0
|
384 }
|
samer@0
|
385
|
samer@0
|
386 int mxnogc_release(atom_t a) { return TRUE; }
|
samer@0
|
387
|
samer@0
|
388 /*
|
samer@0
|
389 // this requires some jiggery pokery to handle IOSTREAMS.
|
samer@0
|
390 int mx_write(IOSTREAM *s, atom_t a, int flags) {
|
samer@0
|
391 mxArray *p=ablob_to_mx(a);
|
samer@0
|
392 fprintf(s,"<mx:%p>",p);
|
samer@0
|
393 }
|
samer@0
|
394 */
|
samer@0
|
395
|
samer@0
|
396
|
samer@0
|
397 int ws_release(atom_t a) {
|
samer@0
|
398 struct wsvar *x=atom_to_wsvar(a);
|
samer@0
|
399 // printf("."); fflush(stdout); // sweet brevity
|
samer@0
|
400
|
samer@0
|
401 char buf[16];
|
samer@0
|
402 sprintf(buf,"clear %s",x->name);
|
samer@0
|
403 engEvalString(x->engine,buf);
|
samer@0
|
404 x->name[0]=0;
|
samer@0
|
405 x->engine=0;
|
samer@0
|
406
|
samer@0
|
407 return TRUE;
|
samer@0
|
408 }
|
samer@0
|
409
|
samer@0
|
410 /* see mx_write */
|
samer@0
|
411 //int ws_write(IOSTREAM *s, atom_t a, int flags) {
|
samer@0
|
412 // struct wsvar *p=atom_to_wsvar(a);
|
samer@0
|
413 // mxArray *p=ablob_to_mx(a);
|
samer@0
|
414 // fprintf(s,"%s",p->name);
|
samer@0
|
415 //}
|
samer@0
|
416
|
samer@0
|
417
|
samer@0
|
418 /* Finds the engine associated with the given term
|
samer@0
|
419 * (which should just be an atom). Throws an exception
|
samer@0
|
420 * if the engine is not found.
|
samer@0
|
421 */
|
samer@0
|
422 static eng *findEngine(term_t id_term)
|
samer@0
|
423 {
|
samer@0
|
424 atom_t id;
|
samer@0
|
425 if(!PL_get_atom(id_term, &id)) {
|
samer@0
|
426 throw PlException("id is not an atom");
|
samer@0
|
427 }
|
samer@0
|
428 for (int i=0; i<MAXENGINES; i++) {
|
samer@0
|
429 if (engines[i].matches(id)) return &engines[i];
|
samer@0
|
430 }
|
samer@0
|
431 throw PlException("engine not found");
|
samer@0
|
432 }
|
samer@0
|
433
|
samer@0
|
434
|
samer@0
|
435 /*
|
samer@0
|
436 * Open a matlab engine using the given command and associate
|
samer@0
|
437 * it with the second term, which should be an atom.
|
samer@0
|
438 */
|
samer@0
|
439
|
samer@0
|
440 foreign_t mlOpen(term_t servercmd, term_t id_term)
|
samer@0
|
441 {
|
samer@0
|
442 try {
|
samer@0
|
443 findEngine(id_term);
|
samer@0
|
444 printf("mlOPEN/2: Engine %s already open\n",(const char *)PlTerm(id_term));
|
samer@0
|
445 PL_succeed;
|
samer@0
|
446 } catch (...) {}
|
samer@0
|
447
|
samer@0
|
448 try {
|
samer@0
|
449 // look for an unused engine structure
|
samer@0
|
450 for (int i=0; i<MAXENGINES; i++) {
|
samer@0
|
451 if (!engines[i].isOpen()) {
|
samer@0
|
452 atom_t id;
|
samer@0
|
453 check(PL_get_atom(id_term,&id));
|
samer@0
|
454 engines[i].open(PlTerm(servercmd), id);
|
samer@0
|
455 fputs(engines[i].outbuf,stdout);
|
samer@0
|
456 PL_succeed;
|
samer@0
|
457 }
|
samer@0
|
458 }
|
samer@0
|
459 return PL_warning("mlOPEN/2: no more engines available.");
|
samer@0
|
460 } catch (PlException &e) {
|
samer@0
|
461 return e.plThrow();
|
samer@0
|
462 }
|
samer@0
|
463 }
|
samer@0
|
464
|
samer@0
|
465 // Close a previously opened Matlab engine
|
samer@0
|
466 foreign_t mlClose(term_t engine) {
|
samer@0
|
467 try {
|
samer@0
|
468 findEngine(engine)->close();
|
samer@0
|
469 PL_succeed;
|
samer@0
|
470 } catch (PlException &e) {
|
samer@0
|
471 return e.plThrow();
|
samer@0
|
472 }
|
samer@0
|
473 }
|
samer@0
|
474
|
samer@0
|
475 /*
|
samer@0
|
476 * Workspace variable handling
|
samer@0
|
477 */
|
samer@0
|
478
|
samer@0
|
479 // This will create a new workspace variable with an unused name,
|
samer@0
|
480 // initialise it to an empty array (to reserve the name) and unify
|
samer@0
|
481 // the term (which must be a prolog variable) with a blob representing
|
samer@0
|
482 // the variable. This in turn points back to this engine so that
|
samer@0
|
483 // if garbage collected, the workspace variable is cleared.
|
samer@0
|
484 foreign_t mlWSAlloc(term_t eng, term_t blob) {
|
samer@0
|
485 // if varname is already bound, we should check
|
samer@0
|
486 // that the name has not been used in the workspace
|
samer@0
|
487 try {
|
samer@0
|
488 class eng *engine=findEngine(eng);
|
samer@0
|
489 struct wsvar x;
|
samer@0
|
490 int rc;
|
samer@0
|
491
|
samer@0
|
492 // in a threaded world, there would either need to be precisely
|
samer@0
|
493 // one engine per thread (so that there are no race conditions on
|
samer@0
|
494 // the Matlab side) or else these lines (down to PL_unify_blob)
|
samer@0
|
495 // need to be atomic.
|
samer@0
|
496 x.engine = engine->ep;
|
samer@0
|
497 x.id = engine->id;
|
samer@0
|
498
|
samer@0
|
499 if (engEvalString(x.engine, "t__0=uniquevar([]);"))
|
samer@0
|
500 throw PlException("Cannot execute uniquevar");
|
samer@0
|
501
|
samer@0
|
502 memset(x.name,sizeof(x.name),0);
|
samer@0
|
503 mxArray *newname=engGetVariable(x.engine, "t__0");
|
samer@0
|
504 if (newname==NULL) {
|
samer@0
|
505 engEvalString(x.engine,"clear(t__0)"); // half arsed attempt to fix variable leak
|
samer@0
|
506 throw PlException("Cannot get new variable name.");
|
samer@0
|
507 }
|
samer@0
|
508 rc = mxGetString(newname,x.name, sizeof(x.name));
|
samer@0
|
509 mxDestroyArray(newname);
|
samer@0
|
510 if (rc) throw PlException("Cannot read new variable name.");
|
samer@0
|
511
|
samer@0
|
512 return PL_unify_blob(blob,&x,sizeof(x),&ws_blob);
|
samer@0
|
513 } catch (PlException &e) {
|
samer@0
|
514 return e.plThrow();
|
samer@0
|
515 }
|
samer@0
|
516 }
|
samer@0
|
517
|
samer@0
|
518 foreign_t mlWSName(term_t blob, term_t name, term_t engine) {
|
samer@0
|
519 // if varname is already bound, we should check
|
samer@0
|
520 // that the name has not been used in the workspace
|
samer@0
|
521 try {
|
samer@0
|
522 struct wsvar *x = term_to_wsvar(blob);
|
samer@0
|
523 return ( PL_unify_atom_chars(name, x->name)
|
samer@0
|
524 && PL_unify_atom(engine, x->id));
|
samer@0
|
525 } catch (PlException &e) {
|
samer@0
|
526 PL_fail; // return e.plThrow();
|
samer@0
|
527 }
|
samer@0
|
528 }
|
samer@0
|
529
|
samer@0
|
530 // Get a named variable from the MATLAB workspace and return a term
|
samer@0
|
531 // containing a pointer to an mxArray (in Prolog's memory space).
|
samer@0
|
532 foreign_t mlWSGet(term_t var, term_t val) {
|
samer@0
|
533 try {
|
samer@0
|
534 struct wsvar *x = term_to_wsvar(var);
|
samer@0
|
535 mxArray *p = engGetVariable(x->engine, x->name);
|
samer@0
|
536 return PL_unify_blob(val, (void **)&p, sizeof(p), &mx_blob);
|
samer@0
|
537 } catch (PlException &e) {
|
samer@0
|
538 return e.plThrow();
|
samer@0
|
539 }
|
samer@0
|
540 }
|
samer@0
|
541
|
samer@0
|
542 // Put an array back in Matlab workspace under given variable name
|
samer@0
|
543 foreign_t mlWSPut(term_t var, term_t val) {
|
samer@0
|
544 try {
|
samer@0
|
545 struct wsvar *x=term_to_wsvar(var);
|
samer@0
|
546 engPutVariable(x->engine, x->name, term_to_mx(val));
|
samer@0
|
547 PL_succeed;
|
samer@0
|
548 } catch (PlException &e) {
|
samer@0
|
549 return e.plThrow();
|
samer@0
|
550 }
|
samer@0
|
551 }
|
samer@0
|
552
|
samer@0
|
553 /*
|
samer@0
|
554 * Executing MATLAB code
|
samer@0
|
555 */
|
samer@0
|
556
|
samer@0
|
557 // Call a Matlab engine to execute the given command
|
samer@0
|
558 foreign_t mlExec(term_t engine, term_t cmd)
|
samer@0
|
559 {
|
samer@0
|
560 // printf(">>> Entering mlEXEC\n");
|
samer@0
|
561 try {
|
samer@0
|
562 eng *eng=findEngine(engine);
|
samer@0
|
563 const char *cmdstr=PlTerm(cmd);
|
samer@0
|
564 char *eval_cmd;
|
samer@0
|
565 int cmdlen=strlen(cmdstr);
|
samer@0
|
566 int rc;
|
samer@0
|
567
|
samer@0
|
568 // if string is very long, send it via local mxArray
|
samer@0
|
569 if (cmdlen>MAXCMDLEN) {
|
samer@0
|
570 mxArray *mxcmd=mxCreateString(cmdstr);
|
samer@0
|
571 // printf(" >>> Putting command\n");
|
samer@0
|
572 engPutVariable(eng->ep,"t__cmd",mxcmd);
|
samer@0
|
573 // printf(" <<< Put command ok\n");
|
samer@0
|
574 mxDestroyArray(mxcmd);
|
samer@0
|
575 cmdstr="eval(t__cmd)";
|
samer@0
|
576 cmdlen=strlen(cmdstr);
|
samer@0
|
577 }
|
samer@0
|
578
|
samer@0
|
579 eval_cmd = new char[cmdlen+strlen(EVALFMT)-1];
|
samer@0
|
580 if (eval_cmd==NULL) throw PlException("Failed to allocate memory for command");
|
samer@0
|
581 sprintf(eval_cmd, EVALFMT, cmdstr);
|
samer@0
|
582 // printf(" >>> Calling Matlab engine...\n"),
|
samer@0
|
583 rc=engEvalString(eng->ep,eval_cmd);
|
samer@0
|
584 // printf(" <<< Returned from Matlab engine...\n"),
|
samer@0
|
585 delete [] eval_cmd;
|
samer@0
|
586
|
samer@0
|
587 if (rc) {
|
samer@0
|
588 // printf("*** MATLAB evaluation error. Output buffer contains:\n"),
|
samer@0
|
589 // fputs(eng->outbuf,stdout);
|
samer@0
|
590 // printf("*** throwing exception.\n");
|
samer@0
|
591 // throw PlException("MATLAB evaluation error");
|
samer@0
|
592 }
|
samer@0
|
593
|
samer@0
|
594
|
samer@0
|
595 // write whatever is in the output buffer now.
|
samer@0
|
596 fputs(eng->outbuf,stdout);
|
samer@0
|
597
|
samer@0
|
598 // SA 2010. Giving up any pretence of being thread-safe -
|
samer@0
|
599 // each engine is to be used by one Prolog thread ONLY.
|
samer@0
|
600 // If you want fancy threading stuff, do it in Prolog.
|
samer@0
|
601
|
samer@0
|
602 // printf(" >>> Getting variable\n");
|
samer@0
|
603 mxArray *lasterr = engGetVariable(eng->ep, "t__ex");
|
samer@0
|
604 // printf(" <<< Got variable\n");
|
samer@0
|
605 // if (!lasterr) throw PlException("Failed to get status information.");
|
samer@0
|
606
|
samer@0
|
607 if (mxGetNumberOfElements(lasterr)>0) {
|
samer@0
|
608 //char *string=mxArrayToString(mxGetField(lasterr,0,"message"));
|
samer@0
|
609 char *string=mxArrayToString(lasterr);
|
samer@0
|
610 mxDestroyArray(lasterr);
|
samer@0
|
611
|
samer@0
|
612 term_t desc=PL_new_term_ref();
|
samer@0
|
613 term_t cmd=PL_new_term_ref();
|
samer@0
|
614 term_t ex=PL_new_term_ref();
|
samer@0
|
615
|
samer@0
|
616 PL_put_atom_chars(desc,string);
|
samer@0
|
617 PL_put_atom_chars(cmd,cmdstr);
|
samer@0
|
618 mxFree(string);
|
samer@0
|
619 check(PL_cons_functor(ex,mlerror,engine,desc,cmd));
|
samer@0
|
620 throw PlException(ex);
|
samer@0
|
621
|
samer@0
|
622 } else mxDestroyArray(lasterr);
|
samer@0
|
623
|
samer@0
|
624 // if we've got this far, then everything went well, so
|
samer@0
|
625 // printf("<<< Returning from mlEXEC\n");
|
samer@0
|
626 PL_succeed;
|
samer@0
|
627 } catch (PlException &e) {
|
samer@0
|
628 return e.plThrow();
|
samer@0
|
629 }
|
samer@0
|
630 }
|
samer@0
|
631
|
samer@0
|
632 // Get a Prolog string out of a matlab char array
|
samer@0
|
633 foreign_t mlMx2String(term_t mx, term_t a)
|
samer@0
|
634 {
|
samer@0
|
635 try {
|
samer@0
|
636 char *str = mxArrayToString(term_to_mx(mx));
|
samer@0
|
637 if (!str) {
|
samer@0
|
638 return PL_warning("array is not a character array");
|
samer@0
|
639 }
|
samer@0
|
640 int rc = PL_unify_string_chars(a, str);
|
samer@0
|
641 mxFree(str);
|
samer@0
|
642 return rc;
|
samer@0
|
643 } catch (PlException &e) {
|
samer@0
|
644 return e.plThrow();
|
samer@0
|
645 }
|
samer@0
|
646 }
|
samer@0
|
647
|
samer@0
|
648 // Convert Matlab char array to a Prolog atom
|
samer@0
|
649 foreign_t mlMx2Atom(term_t mx, term_t a)
|
samer@0
|
650 {
|
samer@0
|
651 try {
|
samer@0
|
652 char *str = mxArrayToString(term_to_mx(mx));
|
samer@0
|
653 if (!str) {
|
samer@0
|
654 return PL_warning("array is not a character array");
|
samer@0
|
655 }
|
samer@0
|
656 int rc = PL_unify_atom_chars(a, str);
|
samer@0
|
657 mxFree(str);
|
samer@0
|
658 return rc;
|
samer@0
|
659 } catch (PlException &e) {
|
samer@0
|
660 return e.plThrow();
|
samer@0
|
661 }
|
samer@0
|
662 }
|
samer@0
|
663
|
samer@0
|
664 // Convert Matlab numerical array with one element to Prolog float
|
samer@0
|
665 foreign_t mlMx2Float(term_t mxterm, term_t a)
|
samer@0
|
666 {
|
samer@0
|
667 try {
|
samer@0
|
668 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
669 if (!mxIsDouble(mx)) {
|
samer@0
|
670 return PL_warning("not numeric");
|
samer@0
|
671 }
|
samer@0
|
672 if (mxGetNumberOfElements(mx)!=1) {
|
samer@0
|
673 return PL_warning("Not a scalar");
|
samer@0
|
674 }
|
samer@0
|
675 double x = mxGetScalar(mx);
|
samer@0
|
676
|
samer@0
|
677 return PL_unify_float(a, x);
|
samer@0
|
678 } catch (PlException &e) {
|
samer@0
|
679 return e.plThrow();
|
samer@0
|
680 }
|
samer@0
|
681 }
|
samer@0
|
682
|
samer@0
|
683 // Convert Matlab numerical (REAL) array to list
|
samer@0
|
684 foreign_t mlMxGetReals(term_t mxterm, term_t a)
|
samer@0
|
685 {
|
samer@0
|
686 try {
|
samer@0
|
687 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
688 int n = mxGetNumberOfElements(mx);
|
samer@0
|
689
|
samer@0
|
690 if (!mxIsDouble(mx)) return PL_warning("not numeric");
|
samer@0
|
691 return unify_list_doubles(a,mxGetPr(mx),n);
|
samer@0
|
692 } catch (PlException &e) {
|
samer@0
|
693 return e.plThrow();
|
samer@0
|
694 }
|
samer@0
|
695 }
|
samer@0
|
696
|
samer@0
|
697 // Convert Matlab logical or numeric array with one element to
|
samer@0
|
698 // Prolog integer 0 or 1 (does not fail or succeed depending on
|
samer@0
|
699 // logical value - this is can be done by prolog code).
|
samer@0
|
700 foreign_t mlMx2Logical(term_t mxterm, term_t a)
|
samer@0
|
701 {
|
samer@0
|
702 try {
|
samer@0
|
703 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
704 if (mxGetNumberOfElements(mx) != 1) return PL_warning("Not a scalar");
|
samer@0
|
705
|
samer@0
|
706 int f;
|
samer@0
|
707 if (mxIsLogical(mx)) {
|
samer@0
|
708 f = mxIsLogicalScalarTrue(mx) ? 1 : 0;
|
samer@0
|
709 } else if (mxIsDouble(mx)) {
|
samer@0
|
710 f = (mxGetScalar(mx) > 0) ? 1 : 0;
|
samer@0
|
711 } else {
|
samer@0
|
712 return PL_warning("neither numeric nor logical (captain)");
|
samer@0
|
713 }
|
samer@0
|
714
|
samer@0
|
715 return PL_unify_integer(a,f);
|
samer@0
|
716 } catch (PlException &e) {
|
samer@0
|
717 return e.plThrow();
|
samer@0
|
718 }
|
samer@0
|
719 }
|
samer@0
|
720
|
samer@0
|
721 // Get array information (size and type of elements)
|
samer@0
|
722 foreign_t mlMxInfo(term_t mxterm, term_t size, term_t type)
|
samer@0
|
723 {
|
samer@0
|
724 try {
|
samer@0
|
725 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
726 long ndims = mxGetNumberOfDimensions(mx);
|
samer@0
|
727 const mwSize *dims = mxGetDimensions(mx);
|
samer@0
|
728 const char *cnm = mxGetClassName(mx);
|
samer@0
|
729
|
samer@0
|
730 if (PL_unify_atom_chars(type, cnm)) {
|
samer@0
|
731 if (dims[ndims-1]==1) ndims--; // remove trailing singletons
|
samer@0
|
732 return unify_list_sizes(size,dims,ndims);
|
samer@0
|
733 }
|
samer@0
|
734 PL_fail;
|
samer@0
|
735 } catch (PlException &e) {
|
samer@0
|
736 return e.plThrow();
|
samer@0
|
737 }
|
samer@0
|
738 }
|
samer@0
|
739
|
samer@0
|
740 // Convert multidimensional subscript to linear index
|
samer@0
|
741 foreign_t mlMxSub2Ind(term_t mxterm, term_t substerm, term_t indterm)
|
samer@0
|
742 {
|
samer@0
|
743 try {
|
samer@0
|
744 mxArray *mx=term_to_mx(mxterm);
|
samer@0
|
745 mwIndex subs[64]; // 64 dimensional should be enough!
|
samer@0
|
746 long nsubs;
|
samer@0
|
747
|
samer@0
|
748 // get substerm as int array
|
samer@0
|
749 if (!get_list_integers(substerm,&nsubs,(int *)subs)) // !!
|
samer@0
|
750 return PL_warning("Bad subscript list");
|
samer@0
|
751
|
samer@0
|
752 // switch to zero-based subscripts
|
samer@0
|
753 for (int i=0; i<nsubs; i++) subs[i]--;
|
samer@0
|
754
|
samer@0
|
755 int ind = mxCalcSingleSubscript(mx,nsubs,subs);
|
samer@0
|
756 check_array_index(mx,ind);
|
samer@0
|
757
|
samer@0
|
758 return PL_unify_integer(indterm, ind);
|
samer@0
|
759 } catch (PlException &e) {
|
samer@0
|
760 return e.plThrow();
|
samer@0
|
761 }
|
samer@0
|
762 }
|
samer@0
|
763
|
samer@0
|
764 // Dereference double from mx array
|
samer@0
|
765 foreign_t mlMxGetFloat(term_t mxterm, term_t index, term_t value)
|
samer@0
|
766 {
|
samer@0
|
767 try {
|
samer@0
|
768 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
769 long i;
|
samer@0
|
770
|
samer@0
|
771 check(PL_get_long(index,&i));
|
samer@0
|
772 check_array_index(mx,i);
|
samer@0
|
773 if (!mxIsDouble(mx)) { return PL_warning("not numeric"); }
|
samer@0
|
774
|
samer@0
|
775 double *p = (double *)mxGetData(mx);
|
samer@0
|
776 return PL_unify_float(value, p[i-1]);
|
samer@0
|
777 } catch (PlException &e) {
|
samer@0
|
778 return e.plThrow();
|
samer@0
|
779 }
|
samer@0
|
780 }
|
samer@0
|
781
|
samer@0
|
782 // Dereference logical from mx array
|
samer@0
|
783 foreign_t mlMxGetLogical(term_t mxterm, term_t index, term_t value)
|
samer@0
|
784 {
|
samer@0
|
785 try {
|
samer@0
|
786 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
787 long i;
|
samer@0
|
788
|
samer@0
|
789 check(PL_get_long(index,&i));
|
samer@0
|
790 check_array_index(mx,i);
|
samer@0
|
791
|
samer@0
|
792 if (mxIsLogical(mx)) {
|
samer@0
|
793 mxLogical *p = mxGetLogicals(mx);
|
samer@0
|
794 return PL_unify_integer(value,(p[i-1]) ? 1 : 0);
|
samer@0
|
795 } else if (mxIsDouble(mx)) {
|
samer@0
|
796 double *p = (double *)mxGetData(mx);
|
samer@0
|
797 return PL_unify_integer(value, (p[i-1]>0) ? 1 : 0);
|
samer@0
|
798 } else {
|
samer@0
|
799 return PL_warning("neither logical nor numeric");
|
samer@0
|
800 }
|
samer@0
|
801
|
samer@0
|
802 } catch (PlException &e) {
|
samer@0
|
803 return e.plThrow();
|
samer@0
|
804 }
|
samer@0
|
805 }
|
samer@0
|
806
|
samer@0
|
807 // Dereference mxArray from cell array
|
samer@0
|
808 // Note that we return a non-gargage collected atom, otherwise,
|
samer@0
|
809 // the parent cell array would be spoiled when one of its elements
|
samer@0
|
810 // is released and destroyed. However, if the parent cell is
|
samer@0
|
811 // released and destroyed, any remaining references to elements
|
samer@0
|
812 // will be prematurely invalidated.
|
samer@0
|
813 // FIXME: This is almost certain to confuse the garbage collector
|
samer@0
|
814 foreign_t mlMxGetCell(term_t mxterm, term_t index, term_t value)
|
samer@0
|
815 {
|
samer@0
|
816 try {
|
samer@0
|
817 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
818 long i;
|
samer@0
|
819
|
samer@0
|
820 check(PL_get_long(index,&i));
|
samer@0
|
821 check_array_index(mx,i);
|
samer@0
|
822 if (!mxIsCell(mx)) { return PL_warning("not numeric"); }
|
samer@0
|
823
|
samer@0
|
824 mxArray *p = mxGetCell(mx,i-1);
|
samer@0
|
825 return PL_unify_blob(value, (void **)&p, sizeof(p), &mxnogc_blob);
|
samer@0
|
826 } catch (PlException &e) {
|
samer@0
|
827 return e.plThrow();
|
samer@0
|
828 }
|
samer@0
|
829 }
|
samer@0
|
830
|
samer@0
|
831 foreign_t mlMxGetField(term_t mxterm, term_t index, term_t field, term_t value)
|
samer@0
|
832 {
|
samer@0
|
833 try {
|
samer@0
|
834 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
835 long i;
|
samer@0
|
836 char *fname;
|
samer@0
|
837
|
samer@0
|
838 check(PL_get_long(index,&i));
|
samer@0
|
839 check(PL_get_atom_chars(field,&fname));
|
samer@0
|
840 check_array_index(mx,i);
|
samer@0
|
841 if (!mxIsStruct(mx)) { return PL_warning("not a structure"); }
|
samer@0
|
842
|
samer@0
|
843 mxArray *p = mxGetField(mx,i-1,fname);
|
samer@0
|
844 if (!p) return PL_warning("Field not present");
|
samer@0
|
845 return PL_unify_blob(value, (void **)&p, sizeof(p), &mxnogc_blob);
|
samer@0
|
846 } catch (PlException &e) {
|
samer@0
|
847 return e.plThrow();
|
samer@0
|
848 }
|
samer@0
|
849 }
|
samer@0
|
850
|
samer@0
|
851 // Create numeric array. Currently only real double arrays created
|
samer@0
|
852 foreign_t mlMxCreateNumeric(term_t size, term_t mx) {
|
samer@0
|
853 try {
|
samer@0
|
854 mwSize dims[64];
|
samer@0
|
855 long ndims;
|
samer@0
|
856
|
samer@0
|
857 // get size as int array
|
samer@0
|
858 if (!get_list_integers(size,&ndims,(int *)dims))
|
samer@0
|
859 return PL_warning("Bad size list");
|
samer@0
|
860
|
samer@0
|
861 mxArray *p = mxCreateNumericArray(ndims,dims,mxDOUBLE_CLASS,mxREAL);
|
samer@0
|
862 return PL_unify_blob(mx, (void **)&p, sizeof(p), &mxnogc_blob);
|
samer@0
|
863 } catch (PlException &e) {
|
samer@0
|
864 return e.plThrow();
|
samer@0
|
865 }
|
samer@0
|
866 }
|
samer@0
|
867
|
samer@0
|
868 // Create cell array.
|
samer@0
|
869 foreign_t mlMxCreateCell(term_t size, term_t mx) {
|
samer@0
|
870 try {
|
samer@0
|
871 mwSize dims[64];
|
samer@0
|
872 long ndims;
|
samer@0
|
873
|
samer@0
|
874 // get size as int array
|
samer@0
|
875 if (!get_list_integers(size,&ndims,(int *)dims))
|
samer@0
|
876 return PL_warning("Bad size list");
|
samer@0
|
877
|
samer@0
|
878 mxArray *p = mxCreateCellArray(ndims,dims);
|
samer@0
|
879 return PL_unify_blob(mx, (void **)&p, sizeof(p), &mxnogc_blob);
|
samer@0
|
880 } catch (PlException &e) {
|
samer@0
|
881 return e.plThrow();
|
samer@0
|
882 }
|
samer@0
|
883 }
|
samer@0
|
884
|
samer@0
|
885 // Create numeric array. Currently only real double arrays created
|
samer@0
|
886 foreign_t mlMxCreateString(term_t string, term_t mx) {
|
samer@0
|
887 try {
|
samer@0
|
888 mxArray *p = mxCreateString(PlTerm(string));
|
samer@0
|
889 return PL_unify_blob(mx, (void **)&p, sizeof(p), &mxnogc_blob);
|
samer@0
|
890 } catch (PlException &e) {
|
samer@0
|
891 return e.plThrow();
|
samer@0
|
892 }
|
samer@0
|
893 }
|
samer@0
|
894
|
samer@0
|
895
|
samer@0
|
896 // Write float into double array
|
samer@0
|
897 foreign_t mlMxPutFloat(term_t mxterm, term_t index, term_t value)
|
samer@0
|
898 {
|
samer@0
|
899 try {
|
samer@0
|
900 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
901 long i;
|
samer@0
|
902 double val;
|
samer@0
|
903
|
samer@0
|
904 if (!mxIsDouble(mx)) { return PL_warning("not numeric"); }
|
samer@0
|
905 check(PL_get_long(index,&i));
|
samer@0
|
906 check(PL_get_float(value,&val));
|
samer@0
|
907 check_array_index(mx,i);
|
samer@0
|
908 *(mxGetPr(mx)+i-1)=val;
|
samer@0
|
909 return true;
|
samer@0
|
910 } catch (PlException &e) {
|
samer@0
|
911 return e.plThrow();
|
samer@0
|
912 }
|
samer@0
|
913 }
|
samer@0
|
914
|
samer@0
|
915 // Write list of floats into double array starting at given index
|
samer@0
|
916 foreign_t mlMxPutFloats(term_t mxterm, term_t index, term_t values)
|
samer@0
|
917 {
|
samer@0
|
918 try {
|
samer@0
|
919 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
920 long i, len;
|
samer@0
|
921
|
samer@0
|
922 if (!mxIsDouble(mx)) { return PL_warning("not numeric"); }
|
samer@0
|
923 check(PL_get_long(index,&i));
|
samer@0
|
924 check_array_index(mx,i);
|
samer@0
|
925 get_list_doubles(values,&len,mxGetPr(mx)+i-1);
|
samer@0
|
926 return true;
|
samer@0
|
927 } catch (PlException &e) {
|
samer@0
|
928 return e.plThrow();
|
samer@0
|
929 }
|
samer@0
|
930 }
|
samer@0
|
931
|
samer@0
|
932 // Put an mxArray into a cell array
|
samer@0
|
933 // IMPORTANT: the object being put must in a non-memory managed atom
|
samer@0
|
934 foreign_t mlMxPutCell(term_t mxterm, term_t index, term_t element)
|
samer@0
|
935 {
|
samer@0
|
936 try {
|
samer@0
|
937 mxArray *mx = term_to_mx(mxterm);
|
samer@0
|
938 mxArray *el = term_to_mx(element);
|
samer@0
|
939 long i;
|
samer@0
|
940
|
samer@0
|
941 if (!mxIsCell(mx)) { return PL_warning("not a cell array"); }
|
samer@0
|
942 check(PL_get_long(index,&i));
|
samer@0
|
943 check_array_index(mx,i);
|
samer@0
|
944 mxSetCell(mx,i-1,el);
|
samer@0
|
945 return true;
|
samer@0
|
946 } catch (PlException &e) {
|
samer@0
|
947 return e.plThrow();
|
samer@0
|
948 }
|
samer@0
|
949 }
|
samer@0
|
950
|
samer@0
|
951 foreign_t mlMxCopyNoGC(term_t in, term_t out)
|
samer@0
|
952 {
|
samer@0
|
953 try {
|
samer@0
|
954 mxArray *mx = term_to_mx(in);
|
samer@0
|
955 mxArray *p = mxDuplicateArray(mx);
|
samer@0
|
956 return PL_unify_blob(out, (void **)&p, sizeof(p), &mxnogc_blob);
|
samer@0
|
957 } catch (PlException &e) {
|
samer@0
|
958 return e.plThrow();
|
samer@0
|
959 }
|
samer@0
|
960 }
|
samer@0
|
961
|
samer@0
|
962 foreign_t mlMxNewRefGC(term_t in, term_t out)
|
samer@0
|
963 {
|
samer@0
|
964 try {
|
samer@0
|
965 mxArray *p = term_to_mx(in);
|
samer@0
|
966 return PL_unify_blob(out, (void **)&p, sizeof(p), &mx_blob);
|
samer@0
|
967 } catch (PlException &e) {
|
samer@0
|
968 return e.plThrow();
|
samer@0
|
969 }
|
samer@0
|
970 }
|
samer@0
|
971
|
samer@0
|
972
|
samer@0
|
973 /*
|
samer@0
|
974 * Local Variables:
|
samer@0
|
975 * c-basic-offset: 2
|
samer@0
|
976 * indent-tabs-mode: nil
|
samer@0
|
977 * End:
|
samer@0
|
978 */
|
samer@0
|
979
|