pmm  1.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
pmm_octave.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008-2010 Robert Higgins
3  Author: Robert Higgins <robert.higgins@ucd.ie>
4 
5  This file is part of PMM.
6 
7  PMM is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  PMM is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with PMM. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /*!
21  * @file pmm_octave.cc
22  * @brief interface between octave and pmm
23  *
24  * Contains code to permit pmm to call interpolation functions written in
25  * octave
26  */
27 #if HAVE_CONFIG_H
28 #include "config.h"
29 
30 /* undefine variables that are also defined in oct.h */
31 /* TODO rearrange octave headers so we don't need this so many places */
32 #undef PACKAGE
33 #undef PACKAGE_URL
34 #undef VERSION
35 #undef PACKAGE_BUGREPORT
36 #undef PACKAGE_NAME
37 #undef PACKAGE_STRING
38 #undef PACKAGE_TARNAME
39 #undef PACKAGE_VERSION
40 #endif
41 
42 #ifdef ENABLE_OCTAVE
43 
44 #include <octave/oct.h>
45 #include <octave/octave.h>
46 #include <octave/parse.h>
47 #undef PACKAGE
48 #undef PACKAGE_URL
49 #undef VERSION
50 #undef PACKAGE_BUGREPORT
51 #undef PACKAGE_NAME
52 #undef PACKAGE_STRING
53 #undef PACKAGE_TARNAME
54 #undef PACKAGE_VERSION
55 
56 #include "pmm_octave.h"
57 
58 extern "C" {
59  #include "pmm_model.h"
60  #include "pmm_log.h"
61 }
62 
63 static int is_octave_initialised = 0; /*!< global initialization switch */
64 
65 
66 /*!
67  * Intialize octave
68  *
69  * Initialize octave and load the custom griddatan octave function file
70  *
71  */
72 extern "C"
73 void octave_init()
74 {
75  octave_value_list grid_in;
76  string_vector argv (2);
77  argv(0) = "octave_feval";
78  argv(1) = "-q";
79 
80  octave_main (2, argv.c_str_vec(), 1);
81 
82 
83  // source custom griddatan file
84  grid_in(0) = PKGDATADIR "/pmm_griddatan.m";
85  feval("source", grid_in, 1);
86 
87  is_octave_initialised = 1;
88 }
89 
90 /*!
91  * Add a benchmark to octave matrix and vector objects
92  *
93  * @param pos row in @a x and @a y to add benchmark to
94  * @param n number of elements in parameter array of benchmark and
95  * columns in @a x
96  * @param x reference to matrix containing parameter values
97  * @param y reference to column vector containing performance for
98  * parameter values in @a x
99  */
100 void add_benchmark_to_xy(int pos, int n, struct pmm_benchmark *b, Matrix &x,
101  ColumnVector &y)
102 {
103  int i;
104 
105  for(i=0; i<n; i++) {
106  x(pos, i) = b->p[i];
107  }
108  y(pos) = b->flops;
109 
110 }
111 
112 
113 /*!
114  *
115  * Populate the members of an octave data structure with a model
116  *
117  * @param m pointer to model which will populate octave data objects
118  * @param mode defines mode of operation, either adding all raw data
119  * points in model (@a mode=0) or adding only averaged
120  * data points in model (@a mode!=0)
121  *
122  * @returns a populated octave data structure
123  */
124 extern "C"
125 struct pmm_octave_data*
126 fill_octave_input_matrices(struct pmm_model *m, int mode)
127 {
128  int size;
129  struct pmm_octave_data *oct_data;
130  struct pmm_benchmark *b;
131  struct pmm_benchmark *b_add;
132 
133  oct_data = new PMM_Octave_Data;
134  if(oct_data == NULL) {
135  ERRPRINTF("Error allocating memory.\n");
136  return NULL;
137  }
138 
139  if(mode == 0) {
140  size = count_benchmarks_in_model(m);
141  } else {
143  }
144 
145  oct_data->x = Matrix(size, m->n_p);
146  oct_data->y = ColumnVector(size);
147 
148  //
149  // fill x & y
150  //
151  int c = 0;
152 
153 
154  // add points from the bench list
155  b = m->bench_list->first;
156  while(b != NULL && c <= size) {
157  if(mode == PMM_AVG) {
159 
160  if(b_add == NULL) {
161  ERRPRINTF("Error getting average of benchmark:\n");
163  return NULL;
164  }
165  }
166  else if(mode == PMM_MAX) {
167  b_add = find_max_bench_in_sorted_bench_list(b, b->p);
168 
169  if(b_add == NULL) {
170  ERRPRINTF("Error getting max of benchmark:\n");
172  return NULL;
173  }
174  }
175  else {
176  b_add = b;
177  }
178 
179  add_benchmark_to_xy(c, m->n_p, b_add, oct_data->x, oct_data->y);
180  c++;
181 
182  if(mode == PMM_AVG) {
183  free_benchmark(&b_add);
185  }
186  else if(mode == PMM_MAX) {
188  }
189  else {
190  b = b->next;
191  }
192  }
193  if(b != NULL) {
194  ERRPRINTF("size mismatch, added %d of max %d benches (last:%p)\n",
195  c, size, b);
197  return NULL;
198  }
199 
200  return oct_data;
201 
202 }
203 
204 /*!
205  * Calcuate and store the triangulation of a matrix of points stored in the
206  * pmm_octave_data structure using delaunayn octave function
207  *
208  * @param oct_data pointer to octave data structure containing matrix
209  * of points, values at points and the triangulation
210  *
211  * @pre octave is initialized and oct_data contains valid matrix x
212  * @post triangulation is stored in oct_data structure
213  *
214  * @return 0 on success, -1 on failure
215  */
216 extern "C"
217 int
218 octave_triangulate(struct pmm_octave_data *oct_data)
219 {
220  octave_value_list oct_in, oct_out;
221 
222  if(is_octave_initialised == 0) {
223  ERRPRINTF("Octave not initialised.\n");
224  return -1;
225  }
226 
227  oct_in(0) = octave_value(oct_data->x);
228  oct_in(1) = octave_value("QbB");
229 
230  oct_out = feval("delaunayn", oct_in, 1);
231 
232  if(!error_state && oct_out.length() > 0) {
233  oct_data->tri = oct_out(0).matrix_value();
234 
235  return 0;
236  }
237  else {
238  ERRPRINTF("Error calculating triangulation of data.\n");
239  return -1;
240  }
241 }
242 
243 /*!
244  * Interpolate a previously calculated triangulation at a set of points defined
245  * by the array p using triinterpn octave function
246  *
247  * @param oct_data octave data structure containing data points and the
248  * calculated triangulation of those points
249  * @param p pointer to multi-dimensional array of points, each
250  * element being an interpolation point
251  * @param n number of dimensions of a single point
252  * @param l number of points
253  *
254  * @return array of interpolated values at points described by p
255  */
256 extern "C"
257 double*
258 octave_interp_array(struct pmm_octave_data *oct_data, int **p, int n, int l)
259 {
260 
261  int i, j;
262  double *flops;
263 
264  // init octave
265  if(is_octave_initialised == 0) {
266  ERRPRINTF("Octave not initialised");
267  return NULL;
268  }
269 
270  flops = new double[l];
271  if(flops == NULL) {
272  ERRPRINTF("Error allocating memory.\n");
273  return NULL;
274  }
275 
276  // create a two row matrix for the lookup point
277  // TODO for some reason we cannot interpolate at a single point successfully
278  // interpolate at two identical points as a workaround
279  Matrix xi = Matrix(l, n);
280 
281  for(i=0; i<l; i++) {
282  for(j=0; j<n; j++) {
283  xi(i, j) = p[i][j];
284  }
285  }
286 
287  //set up input and output objects for call to griddatan octave call
288  octave_value_list oct_in, oct_out;
289 
290  oct_in(0) = octave_value(oct_data->tri);
291  oct_in(1) = octave_value(oct_data->x);
292  oct_in(2) = octave_value(oct_data->y);
293  oct_in(3) = octave_value(xi);
294  oct_in(4) = octave_value("linear");
295 
296 
297  //execute octave function
298  oct_out = feval("pmm_triinterpn", oct_in, 1);
299 
300  Matrix yi;
301  if(!error_state && oct_out.length() > 0) {
302  yi = oct_out(0).matrix_value();
303 
304  for(i=0; i<l; i++) {
305  flops[i] = yi(i);
306  }
307  }
308  else {
309  ERRPRINTF("Error calling pmm_triinterpn in octave.\n");
310  delete [] flops;
311  return NULL;
312  }
313 
314  return flops;
315 }
316 
317 /*!
318  * Interpolate a previously calculated triangulation at a single point
319  * using triinterpn octave function
320  *
321  * @param oct_data octave data structure containing data points and the
322  * calculated triangulation of those points
323  * @param p pointer to an interpolation point array
324  * @param n number of dimensions of the interpolation point
325  *
326  * @return value of interpolation at point @a p
327  */
328 extern "C"
329 double
330 octave_interp(struct pmm_octave_data *oct_data, int *p, int n)
331 {
332 
333  int i;
334  double flops;
335 
336  // init octave
337  if(is_octave_initialised == 0) {
338  ERRPRINTF("Octave not initialised");
339  return -1.0;
340  }
341 
342  // create a two row matrix for the lookup point
343  // TODO for some reason we cannot interpolate at a single point successfully
344  // interpolate at two identical points as a workaround
345  Matrix xi = Matrix(2, n);
346 
347  for(i=0; i<n; i++) {
348  xi(0, i) = p[i];
349  xi(1, i) = p[i];
350  }
351 
352  //set up input and output objects for call to griddatan octave call
353  octave_value_list oct_in, oct_out;
354 
355  oct_in(0) = octave_value(oct_data->tri);
356  oct_in(1) = octave_value(oct_data->x);
357  oct_in(2) = octave_value(oct_data->y);
358  oct_in(3) = octave_value(xi);
359  oct_in(4) = octave_value("linear");
360 
361 
362  //execute octave function
363  oct_out = feval("pmm_triinterpn", oct_in, 1);
364 
365  Matrix yi;
366  if(!error_state && oct_out.length() > 0) {
367  yi = oct_out(0).matrix_value();
368 
369  flops = yi(0);
370  DBGPRINTF("-------- INTERPOLATED FLOPS --------\n");
371  for(i=0; i<n; i++) {
372  printf("p:%d:%d ", i, p[i]);
373  }
374  printf("flops:%f (%f)\n", flops, yi(1));
375 
376  }
377  else {
378  ERRPRINTF("Error calling pmm_triinterpn in octave.\n");
379  return -1.0;
380  }
381 
382  return flops;
383 }
384 
385 /*!
386  * interpolate the data stored in octave data structure at a
387  * particular point using griddatan octave function
388  *
389  * @param oct_data pointer to data structure containing a point cloud
390  * @param p pointer to an array describing point at which to
391  * interpolate point cloud
392  * @param n number of parameters of point
393  */
394 extern "C"
395 double
396 octave_interpolate(struct pmm_octave_data *oct_data, int *p, int n)
397 {
398 
399  int i;
400  double flops;
401 
402  // init octave
403  if(is_octave_initialised == 0) {
404  octave_init();
405  }
406 
407  // create a two row matrix for the lookup point
408  // TODO for some reason we cannot interpolate at a single point successfully
409  // interpolate at two identical points as a workaround
410  Matrix xi = Matrix(2, n);
411 
412  for(i=0; i<n; i++) {
413  xi(0, i) = p[i];
414  xi(1, i) = p[i];
415  }
416 
417  //set up input and output objects for call to griddatan octave call
418  octave_value_list grid_in, grid_out;
419 
420  DBGPRINTF("Setting up grid_in(0)\n");
421  grid_in(0) = octave_value(oct_data->x);
422  DBGPRINTF("Done.\nSetting ut grid_in(1)\n");
423  grid_in(1) = octave_value(oct_data->y);
424  DBGPRINTF("Done.\nSetting up grid_in(2)\n");
425  grid_in(2) = octave_value(xi);
426  DBGPRINTF("Done.\nSetting up grid_in(3)\n");
427  grid_in(3) = octave_value("linear");
428  DBGPRINTF("Done.\nSetting up grid_in(4)\n");
429  grid_in(4) = octave_value("QbB");
430  DBGPRINTF("Done.\n");
431 
432 
433  //execute octave function
434  DBGPRINTF("feval pmm_griddatan ...\n");
435  grid_out = feval("pmm_griddatan", grid_in, 1);
436  DBGPRINTF("Done.\n");
437 
438  Matrix yi;
439  if(!error_state && grid_out.length() > 0) {
440  yi = grid_out(0).matrix_value();
441 
442  flops = yi(0);
443  DBGPRINTF("-------- INTERPOLATED FLOPS --------\n");
444  for(i=0; i<n; i++) {
445  printf("p:%d:%d ", i, p[i]);
446  }
447  printf("flops:%f (%f)\n", flops, yi(1));
448 
449  }
450  else {
451  ERRPRINTF("Error calling pmm_griddatan in octave.\n");
452  return -1.0;
453  }
454 
455  return flops;
456 }
457 
458 /*!
459  * Create octave data structures from a model, interpolate that model and
460  * look up the interpolation at a point using griddatan octave function
461  *
462  * @param m pointer to the model
463  * @param p pointer to the parameter array describing the look up point
464  *
465  * @return pointer to a newly allocated benchmark representing the value of
466  * the model at the lookup point or NULL on failure
467  */
468 extern "C"
469 struct pmm_benchmark*
470 interpolate_griddatan(struct pmm_model *m, int *p)
471 {
472  struct pmm_benchmark *ret_b;
473 
474  struct pmm_octave_data *oct_data;
475 
476  int i;
477 
478  // init octave
479  if(is_octave_initialised == 0) {
480  octave_init();
481  }
482 
483  oct_data = fill_octave_input_matrices(m, PMM_ALL);
484 
485 
486  // create a two row matrix for the lookup point
487  // TODO for some reason we cannot interpolate at a single point successfully
488  // interpolate at two identical points as a workaround
489  Matrix xi = Matrix(2, m->n_p);
490 
491  //fill xi and the return benchmark
492  ret_b = new_benchmark();
493  ret_b->n_p = m->n_p;
494  ret_b->p = (int*) malloc(ret_b->n_p * sizeof *(ret_b->p));
495 
496  for(i=0; i<m->n_p; i++) {
497  xi(0, i) = p[i];
498  xi(1, i) = p[i];
499 
500  ret_b->p[i] = p[i];
501  }
502 
503  //set up input and output objects for call to griddatan octave call
504  octave_value_list grid_in, grid_out;
505 
506  grid_in(0) = octave_value(oct_data->x);
507  grid_in(1) = octave_value(oct_data->y);
508  grid_in(2) = octave_value(xi);
509  grid_in(3) = octave_value("linear");
510  grid_in(4) = octave_value("QbB");
511 
512 
513  //execute octave function
514  grid_out = feval("pmm_griddatan", grid_in, 1);
515 
516  Matrix yi;
517  if(!error_state && grid_out.length() > 0) {
518  yi = grid_out(0).matrix_value();
519 
520  ret_b->flops = yi(0);
521  DBGPRINTF("-------- INTERPOLATED BENCH --------\n");
522  print_benchmark(PMM_DBG, ret_b);
523 
524  return ret_b;
525  }
526  else {
527  ERRPRINTF("Error calling pmm_griddatan in octave.\n");
528  free_benchmark(&ret_b);
529  return NULL;
530  }
531 }
532 #endif /* ENABLE_OCTAVE */