GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ov-fcn-inline.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2004-2017 David Bateman
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 In addition to the terms of the GPL, you are permitted to link
22 this program with any Open Source program, as defined by the
23 Open Source Initiative (www.opensource.org)
24 
25 */
26 
27 #if defined (HAVE_CONFIG_H)
28 # include "config.h"
29 #endif
30 
31 #include <istream>
32 #include <iostream>
33 #include <sstream>
34 #include <vector>
35 
36 #include "oct-locbuf.h"
37 
38 #include "call-stack.h"
39 #include "defun.h"
40 #include "error.h"
41 #include "errwarn.h"
42 #include "oct-hdf5.h"
43 #include "oct-map.h"
44 #include "ov-base.h"
45 #include "ov-fcn-inline.h"
46 #include "ov-usr-fcn.h"
47 #include "pr-output.h"
48 #include "variables.h"
49 #include "parse.h"
50 #include "interpreter.h"
51 
52 #include "byte-swap.h"
53 #include "ls-ascii-helper.h"
54 #include "ls-oct-text.h"
55 #include "ls-hdf5.h"
56 #include "ls-utils.h"
57 
58 
60  "inline function",
61  "function_handle");
62 
64  const string_vector& a,
65  const std::string& n)
66  : octave_fcn_handle (n), iftext (f), ifargs (a)
67 {
68  // Form a string representing the function.
69 
70  std::ostringstream buf;
71 
72  buf << "@(";
73 
74  for (int i = 0; i < ifargs.numel (); i++)
75  {
76  if (i > 0)
77  buf << ", ";
78 
79  buf << ifargs(i);
80  }
81 
82  buf << ") " << iftext;
83 
84  int parse_status;
85  octave_value anon_fcn_handle = eval_string (buf.str (), true, parse_status);
86 
87  if (parse_status == 0)
88  {
89  octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
90 
91  if (fh)
92  {
93  fcn = fh->fcn_val ();
94 
96 
97  if (uf)
98  {
100 
101  if (curr_fcn)
102  {
103  symbol_table::scope_id parent_scope
104  = curr_fcn->parent_fcn_scope ();
105 
106  if (parent_scope < 0)
107  parent_scope = curr_fcn->scope ();
108 
109  uf->stash_parent_fcn_scope (parent_scope);
110  }
111  }
112  }
113  }
114 
115  if (fcn.is_undefined ())
116  error ("inline: unable to define function");
117 }
118 
119 // This function is supplied to allow a Matlab style class structure
120 // to be returned..
123 {
125 
126  m.assign ("version", 1.0);
127  m.assign ("isEmpty", 0.0);
128  m.assign ("expr", fcn_text ());
129 
131 
132  m.assign ("numArgs", args.numel ());
133  m.assign ("args", args);
134 
135  std::ostringstream buf;
136 
137  for (int i = 0; i < args.numel (); i++)
138  buf << args(i) << " = INLINE_INPUTS_{" << i + 1 << "}; ";
139 
140  m.assign ("inputExpr", buf.str ());
141 
142  return m;
143 }
144 
145 bool
147 {
148  os << "# nargs: " << ifargs.numel () << "\n";
149  for (int i = 0; i < ifargs.numel (); i++)
150  os << ifargs(i) << "\n";
151  if (nm.length () < 1)
152  // Write an invalid value to flag empty fcn handle name.
153  os << "0\n";
154  else
155  os << nm << "\n";
156  os << iftext << "\n";
157  return true;
158 }
159 
160 bool
162 {
163  int nargs;
164  if (extract_keyword (is, "nargs", nargs, true))
165  {
166  ifargs.resize (nargs);
167  for (int i = 0; i < nargs; i++)
168  is >> ifargs(i);
169  is >> nm;
170  if (nm == "0")
171  nm = "";
172 
174 
175  std::string buf;
176 
177  if (is)
178  {
179 
180  // Get a line of text whitespace characters included,
181  // leaving newline in the stream.
182  buf = read_until_newline (is, true);
183  }
184 
185  iftext = buf;
186 
188  fcn = tmp.fcn;
189 
190  return true;
191  }
192  else
193  return false;
194 }
195 
196 bool
197 octave_fcn_inline::save_binary (std::ostream& os, bool&)
198 {
199  int32_t tmp = ifargs.numel ();
200  os.write (reinterpret_cast<char *> (&tmp), 4);
201  for (int i = 0; i < ifargs.numel (); i++)
202  {
203  tmp = ifargs(i).length ();
204  os.write (reinterpret_cast<char *> (&tmp), 4);
205  os.write (ifargs(i).c_str (), ifargs(i).length ());
206  }
207  tmp = nm.length ();
208  os.write (reinterpret_cast<char *> (&tmp), 4);
209  os.write (nm.c_str (), nm.length ());
210  tmp = iftext.length ();
211  os.write (reinterpret_cast<char *> (&tmp), 4);
212  os.write (iftext.c_str (), iftext.length ());
213  return true;
214 }
215 
216 bool
219 {
220  int32_t nargs;
221  if (! is.read (reinterpret_cast<char *> (&nargs), 4))
222  return false;
223  if (swap)
224  swap_bytes<4> (&nargs);
225 
226  if (nargs < 1)
227  return false;
228  else
229  {
230  int32_t tmp;
231  ifargs.resize (nargs);
232  for (int i = 0; i < nargs; i++)
233  {
234  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
235  return false;
236  if (swap)
237  swap_bytes<4> (&tmp);
238 
239  OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
240  is.read (ctmp, tmp);
241  ifargs(i) = std::string (ctmp);
242 
243  if (! is)
244  return false;
245  }
246 
247  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
248  return false;
249  if (swap)
250  swap_bytes<4> (&tmp);
251 
252  OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
253  is.read (ctmp1, tmp);
254  nm = std::string (ctmp1);
255 
256  if (! is)
257  return false;
258 
259  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
260  return false;
261  if (swap)
262  swap_bytes<4> (&tmp);
263 
264  OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
265  is.read (ctmp2, tmp);
266  iftext = std::string (ctmp2);
267 
268  if (! is)
269  return false;
270 
272  fcn = ftmp.fcn;
273  }
274  return true;
275 }
276 
277 bool
279  bool /* save_as_floats */)
280 {
281  bool retval = false;
282 
283 #if defined (HAVE_HDF5)
284 
285  hid_t group_hid = -1;
286 
287 #if defined (HAVE_HDF5_18)
288  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
290 #else
291  group_hid = H5Gcreate (loc_id, name, 0);
292 #endif
293  if (group_hid < 0) return false;
294 
295  size_t len = 0;
296  for (int i = 0; i < ifargs.numel (); i++)
297  if (len < ifargs(i).length ())
298  len = ifargs(i).length ();
299 
300  hid_t space_hid, data_hid, type_hid;
301  space_hid = data_hid = type_hid = -1;
302 
303  // FIXME: Is there a better way of saving string vectors,
304  // than a null padded matrix?
305 
306  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
307 
308  // Octave uses column-major, while HDF5 uses row-major ordering
309  hdims[1] = ifargs.numel ();
310  hdims[0] = len + 1;
311 
312  space_hid = H5Screate_simple (2, hdims, 0);
313  if (space_hid < 0)
314  {
315  H5Gclose (group_hid);
316  return false;
317  }
318 #if defined (HAVE_HDF5_18)
319  data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
321 #else
322  data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
324 #endif
325  if (data_hid < 0)
326  {
327  H5Sclose (space_hid);
328  H5Gclose (group_hid);
329  return false;
330  }
331 
332  OCTAVE_LOCAL_BUFFER (char, s, ifargs.numel () * (len + 1));
333 
334  // Save the args as a null teminated list
335  for (int i = 0; i < ifargs.numel (); i++)
336  {
337  const char * cptr = ifargs(i).c_str ();
338  for (size_t j = 0; j < ifargs(i).length (); j++)
339  s[i*(len+1)+j] = *cptr++;
340  s[ifargs(i).length ()] = '\0';
341  }
342 
343  retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, octave_H5S_ALL, octave_H5S_ALL,
344  octave_H5P_DEFAULT, s) >= 0;
345 
346  H5Dclose (data_hid);
347  H5Sclose (space_hid);
348 
349  if (! retval)
350  {
351  H5Gclose (group_hid);
352  return false;
353  }
354 
355  // attach the type of the variable
356  type_hid = H5Tcopy (H5T_C_S1);
357  H5Tset_size (type_hid, nm.length () + 1);
358  if (type_hid < 0)
359  {
360  H5Gclose (group_hid);
361  return false;
362  }
363 
364  hdims[0] = 0;
365  space_hid = H5Screate_simple (0 , hdims, 0);
366  if (space_hid < 0)
367  {
368  H5Tclose (type_hid);
369  H5Gclose (group_hid);
370  return false;
371  }
372 #if defined (HAVE_HDF5_18)
373  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
375 #else
376  data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid,
378 #endif
379  if (data_hid < 0
380  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
381  octave_H5P_DEFAULT, nm.c_str ()) < 0)
382  {
383  H5Sclose (space_hid);
384  H5Tclose (type_hid);
385  H5Gclose (group_hid);
386  return false;
387  }
388  H5Dclose (data_hid);
389 
390  // attach the type of the variable
391  H5Tset_size (type_hid, iftext.length () + 1);
392  if (type_hid < 0)
393  {
394  H5Gclose (group_hid);
395  return false;
396  }
397 
398 #if defined (HAVE_HDF5_18)
399  data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid,
401 #else
402  data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid,
404 #endif
405  if (data_hid < 0
406  || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
407  octave_H5P_DEFAULT, iftext.c_str ()) < 0)
408  {
409  H5Sclose (space_hid);
410  H5Tclose (type_hid);
411  H5Gclose (group_hid);
412  return false;
413  }
414 
415  H5Dclose (data_hid);
416  H5Sclose (space_hid);
417  H5Tclose (type_hid);
418  H5Gclose (group_hid);
419 
420 #else
421  octave_unused_parameter (loc_id);
422  octave_unused_parameter (name);
423 
424  warn_save ("hdf5");
425 #endif
426 
427  return retval;
428 }
429 
430 bool
432 {
433 #if defined (HAVE_HDF5)
434 
435  hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
436  hsize_t rank;
437  int slen;
438 
439 #if defined (HAVE_HDF5_18)
440  group_hid = H5Gopen (loc_id, name, octave_H5P_DEFAULT);
441 #else
442  group_hid = H5Gopen (loc_id, name);
443 #endif
444  if (group_hid < 0) return false;
445 
446 #if defined (HAVE_HDF5_18)
447  data_hid = H5Dopen (group_hid, "args", octave_H5P_DEFAULT);
448 #else
449  data_hid = H5Dopen (group_hid, "args");
450 #endif
451  space_hid = H5Dget_space (data_hid);
452  rank = H5Sget_simple_extent_ndims (space_hid);
453 
454  if (rank != 2)
455  {
456  H5Dclose (data_hid);
457  H5Sclose (space_hid);
458  H5Gclose (group_hid);
459  return false;
460  }
461 
462  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
463  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
464 
465  H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
466 
467  ifargs.resize (hdims[1]);
468 
469  OCTAVE_LOCAL_BUFFER (char, s1, hdims[0] * hdims[1]);
470 
471  if (H5Dread (data_hid, H5T_NATIVE_UCHAR, octave_H5S_ALL, octave_H5S_ALL,
472  octave_H5P_DEFAULT, s1) < 0)
473  {
474  H5Dclose (data_hid);
475  H5Sclose (space_hid);
476  H5Gclose (group_hid);
477  return false;
478  }
479 
480  H5Dclose (data_hid);
481  H5Sclose (space_hid);
482 
483  for (size_t i = 0; i < hdims[1]; i++)
484  ifargs(i) = std::string (s1 + i*hdims[0]);
485 
486 #if defined (HAVE_HDF5_18)
487  data_hid = H5Dopen (group_hid, "nm", octave_H5P_DEFAULT);
488 #else
489  data_hid = H5Dopen (group_hid, "nm");
490 #endif
491 
492  if (data_hid < 0)
493  {
494  H5Gclose (group_hid);
495  return false;
496  }
497 
498  type_hid = H5Dget_type (data_hid);
499  type_class_hid = H5Tget_class (type_hid);
500 
501  if (type_class_hid != H5T_STRING)
502  {
503  H5Tclose (type_hid);
504  H5Dclose (data_hid);
505  H5Gclose (group_hid);
506  return false;
507  }
508 
509  space_hid = H5Dget_space (data_hid);
510  rank = H5Sget_simple_extent_ndims (space_hid);
511 
512  if (rank != 0)
513  {
514  H5Sclose (space_hid);
515  H5Tclose (type_hid);
516  H5Dclose (data_hid);
517  H5Gclose (group_hid);
518  return false;
519  }
520 
521  slen = H5Tget_size (type_hid);
522  if (slen < 0)
523  {
524  H5Sclose (space_hid);
525  H5Tclose (type_hid);
526  H5Dclose (data_hid);
527  H5Gclose (group_hid);
528  return false;
529  }
530 
531  OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
532 
533  // create datatype for (null-terminated) string to read into:
534  st_id = H5Tcopy (H5T_C_S1);
535  H5Tset_size (st_id, slen);
536 
537  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
538  octave_H5P_DEFAULT, nm_tmp) < 0)
539  {
540  H5Sclose (space_hid);
541  H5Tclose (type_hid);
542  H5Gclose (group_hid);
543  return false;
544  }
545  H5Tclose (st_id);
546  H5Dclose (data_hid);
547  nm = nm_tmp;
548 
549 #if defined (HAVE_HDF5_18)
550  data_hid = H5Dopen (group_hid, "iftext", octave_H5P_DEFAULT);
551 #else
552  data_hid = H5Dopen (group_hid, "iftext");
553 #endif
554 
555  if (data_hid < 0)
556  {
557  H5Gclose (group_hid);
558  return false;
559  }
560 
561  type_hid = H5Dget_type (data_hid);
562  type_class_hid = H5Tget_class (type_hid);
563 
564  if (type_class_hid != H5T_STRING)
565  {
566  H5Tclose (type_hid);
567  H5Dclose (data_hid);
568  H5Gclose (group_hid);
569  return false;
570  }
571 
572  space_hid = H5Dget_space (data_hid);
573  rank = H5Sget_simple_extent_ndims (space_hid);
574 
575  if (rank != 0)
576  {
577  H5Sclose (space_hid);
578  H5Tclose (type_hid);
579  H5Dclose (data_hid);
580  H5Gclose (group_hid);
581  return false;
582  }
583 
584  slen = H5Tget_size (type_hid);
585  if (slen < 0)
586  {
587  H5Sclose (space_hid);
588  H5Tclose (type_hid);
589  H5Dclose (data_hid);
590  H5Gclose (group_hid);
591  return false;
592  }
593 
594  OCTAVE_LOCAL_BUFFER (char, iftext_tmp, slen);
595 
596  // create datatype for (null-terminated) string to read into:
597  st_id = H5Tcopy (H5T_C_S1);
598  H5Tset_size (st_id, slen);
599 
600  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
601  octave_H5P_DEFAULT, iftext_tmp) < 0)
602  {
603  H5Sclose (space_hid);
604  H5Tclose (type_hid);
605  H5Gclose (group_hid);
606  return false;
607  }
608  H5Tclose (st_id);
609  H5Dclose (data_hid);
610  iftext = iftext_tmp;
611 
613  fcn = ftmp.fcn;
614 
615  return true;
616 
617 #else
618  octave_unused_parameter (loc_id);
619  octave_unused_parameter (name);
620 
621  warn_load ("hdf5");
622 
623  return false;
624 #endif
625 }
626 
627 void
628 octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax)
629 {
630  print_raw (os, pr_as_read_syntax);
631  newline (os);
632 }
633 
634 void
635 octave_fcn_inline::print_raw (std::ostream& os, bool pr_as_read_syntax) const
636 {
637  std::ostringstream buf;
638 
639  if (nm.empty ())
640  buf << "f(";
641  else
642  buf << nm << "(";
643 
644  for (int i = 0; i < ifargs.numel (); i++)
645  {
646  if (i)
647  buf << ", ";
648 
649  buf << ifargs(i);
650  }
651 
652  buf << ") = " << iftext;
653 
654  octave_print_internal (os, buf.str (), pr_as_read_syntax,
656 }
657 
660 {
661  return octave_value (fcn_text (), type);
662 }
663 
664 DEFUNX ("inline", Finline, args, ,
665  doc: /* -*- texinfo -*-
666 @deftypefn {} {} inline (@var{str})
667 @deftypefnx {} {} inline (@var{str}, @var{arg1}, @dots{})
668 @deftypefnx {} {} inline (@var{str}, @var{n})
669 Create an inline function from the character string @var{str}.
670 
671 If called with a single argument, the arguments of the generated function
672 are extracted from the function itself. The generated function arguments
673 will then be in alphabetical order. It should be noted that i and j are
674 ignored as arguments due to the ambiguity between their use as a variable or
675 their use as an built-in constant. All arguments followed by a parenthesis
676 are considered to be functions. If no arguments are found, a function
677 taking a single argument named @code{x} will be created.
678 
679 If the second and subsequent arguments are character strings, they are the
680 names of the arguments of the function.
681 
682 If the second argument is an integer @var{n}, the arguments are
683 @qcode{"x"}, @qcode{"P1"}, @dots{}, @qcode{"P@var{N}"}.
684 
685 Programming Note: The use of @code{inline} is discouraged and it may be
686 removed from a future version of Octave. The preferred way to create
687 functions from strings is through the use of anonymous functions
688 (@pxref{Anonymous Functions}) or @code{str2func}.
689 @seealso{argnames, formula, vectorize, str2func}
690 @end deftypefn */)
691 {
692  int nargin = args.length ();
693 
694  if (nargin == 0)
695  print_usage ();
696 
697  std::string fun = args(0).xstring_value ("inline: STR argument must be a string");
698 
699  string_vector fargs;
700 
701  if (nargin == 1)
702  {
703  bool is_arg = false;
704  bool in_string = false;
705  std::string tmp_arg;
706  size_t i = 0;
707  size_t fun_length = fun.length ();
708 
709  while (i < fun_length)
710  {
711  bool terminate_arg = false;
712  char c = fun[i++];
713 
714  if (in_string)
715  {
716  if (c == '\'' || c == '\"')
717  in_string = false;
718  }
719  else if (c == '\'' || c == '\"')
720  {
721  in_string = true;
722  if (is_arg)
723  terminate_arg = true;
724  }
725  else if (! isalpha (c) && c != '_')
726  if (! is_arg)
727  continue;
728  else if (isdigit (c))
729  tmp_arg.append (1, c);
730  else
731  {
732  // Before we do anything remove trailing whitespaces.
733  while (i < fun_length && isspace (c))
734  c = fun[i++];
735 
736  // Do we have a variable or a function?
737  if (c != '(')
738  terminate_arg = true;
739  else
740  {
741  tmp_arg = "";
742  is_arg = false;
743  }
744  }
745  else if (! is_arg)
746  {
747  if (c == 'e' || c == 'E')
748  {
749  // possible number in exponent form, not arg
750  if (isdigit (fun[i]) || fun[i] == '-' || fun[i] == '+')
751  continue;
752  }
753  is_arg = true;
754  tmp_arg.append (1, c);
755  }
756  else
757  {
758  tmp_arg.append (1, c);
759  }
760 
761  if (terminate_arg || (i == fun_length && is_arg))
762  {
763  bool have_arg = false;
764 
765  for (int j = 0; j < fargs.numel (); j++)
766  if (tmp_arg == fargs (j))
767  {
768  have_arg = true;
769  break;
770  }
771 
772  if (! have_arg && tmp_arg != "i" && tmp_arg != "j"
773  && tmp_arg != "NaN" && tmp_arg != "nan"
774  && tmp_arg != "Inf" && tmp_arg != "inf"
775  && tmp_arg != "NA" && tmp_arg != "pi"
776  && tmp_arg != "e" && tmp_arg != "eps")
777  fargs.append (tmp_arg);
778 
779  tmp_arg = "";
780  is_arg = false;
781  }
782  }
783 
784  // Sort the arguments into ascii order.
785  fargs.sort ();
786 
787  if (fargs.is_empty ())
788  fargs.append (std::string ("x"));
789 
790  }
791  else if (nargin == 2 && args(1).is_numeric_type ())
792  {
793  if (! args(1).is_scalar_type ())
794  error ("inline: N must be an integer");
795 
796  int n = args(1).int_value ("inline: N must be an integer");
797 
798  if (n < 0)
799  error ("inline: N must be a positive integer or zero");
800 
801  fargs.resize (n+1);
802 
803  fargs(0) = "x";
804 
805  for (int i = 1; i < n+1; i++)
806  {
807  std::ostringstream buf;
808  buf << "P" << i;
809  fargs(i) = buf.str ();
810  }
811  }
812  else
813  {
814  fargs.resize (nargin - 1);
815 
816  for (int i = 1; i < nargin; i++)
817  {
818  std::string s = args(i).xstring_value ("inline: additional arguments must be strings");
819  fargs(i-1) = s;
820  }
821  }
822 
823  return ovl (new octave_fcn_inline (fun, fargs));
824 }
825 
826 /*
827 %!shared fn
828 %! fn = inline ("x.^2 + 1");
829 %!assert (feval (fn, 6), 37)
830 %!assert (fn (6), 37)
831 %!assert (feval (inline ("sum (x(:))"), [1 2; 3 4]), 10)
832 %!assert (feval (inline ("sqrt (x^2 + y^2)", "x", "y"), 3, 4), 5)
833 %!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp(3*4) + 5)
834 
835 ## Test input validation
836 %!error inline ()
837 %!error <STR argument must be a string> inline (1)
838 %!error <N must be an integer> inline ("2", ones (2,2))
839 %!error <N must be a positive integer> inline ("2", -1)
840 %!error <additional arguments must be strings> inline ("2", "x", -1, "y")
841 */
842 
843 DEFUN (formula, args, ,
844  doc: /* -*- texinfo -*-
845 @deftypefn {} {} formula (@var{fun})
846 Return a character string representing the inline function @var{fun}.
847 
848 Note that @code{char (@var{fun})} is equivalent to
849 @code{formula (@var{fun})}.
850 @seealso{char, argnames, inline, vectorize}
851 @end deftypefn */)
852 {
853  if (args.length () != 1)
854  print_usage ();
855 
856  octave_fcn_inline* fn = args(0).fcn_inline_value (true);
857 
858  if (! fn)
859  error ("formula: FUN must be an inline function");
860 
861  return ovl (fn->fcn_text ());
862 }
863 
864 /*
865 %!assert (formula (fn), "x.^2 + 1")
866 %!assert (formula (fn), char (fn))
867 
868 ## Test input validation
869 %!error formula ()
870 %!error formula (1, 2)
871 %!error <FUN must be an inline function> formula (1)
872 */
873 
874 DEFUN (argnames, args, ,
875  doc: /* -*- texinfo -*-
876 @deftypefn {} {} argnames (@var{fun})
877 Return a cell array of character strings containing the names of the
878 arguments of the inline function @var{fun}.
879 @seealso{inline, formula, vectorize}
880 @end deftypefn */)
881 {
882  if (args.length () != 1)
883  print_usage ();
884 
885  octave_fcn_inline *fn = args(0).fcn_inline_value (true);
886 
887  if (! fn)
888  error ("argnames: FUN must be an inline function");
889 
890  string_vector t1 = fn->fcn_arg_names ();
891 
892  Cell t2 (dim_vector (t1.numel (), 1));
893 
894  for (int i = 0; i < t1.numel (); i++)
895  t2(i) = t1(i);
896 
897  return ovl (t2);
898 }
899 
900 /*
901 %!assert (argnames (fn), {"x"})
902 %!assert (argnames (inline ("1e-3*y + 2e4*z")), {"y"; "z"})
903 %!assert (argnames (inline ("2", 2)), {"x"; "P1"; "P2"})
904 
905 ## Test input validation
906 %!error argnames ()
907 %!error argnames (1, 2)
908 %!error <FUN must be an inline function> argnames (1)
909 */
910 
911 DEFUN (vectorize, args, ,
912  doc: /* -*- texinfo -*-
913 @deftypefn {} {} vectorize (@var{fun})
914 Create a vectorized version of the inline function @var{fun} by replacing
915 all occurrences of @code{*}, @code{/}, etc., with @code{.*}, @code{./}, etc.
916 
917 This may be useful, for example, when using inline functions with numerical
918 integration or optimization where a vector-valued function is expected.
919 
920 @example
921 @group
922 fcn = vectorize (inline ("x^2 - 1"))
923  @result{} fcn = f(x) = x.^2 - 1
924 quadv (fcn, 0, 3)
925  @result{} 6
926 @end group
927 @end example
928 @seealso{inline, formula, argnames}
929 @end deftypefn */)
930 {
931  if (args.length () != 1)
932  print_usage ();
933 
934  std::string old_func;
935  octave_fcn_inline* old = 0;
936  bool func_is_string = true;
937 
938  if (args(0).is_string ())
939  old_func = args(0).string_value ();
940  else
941  {
942  old = args(0).fcn_inline_value (true);
943  func_is_string = false;
944 
945  if (old)
946  old_func = old->fcn_text ();
947  else
948  error ("vectorize: FUN must be a string or inline function");
949  }
950 
951  std::string new_func;
952  size_t i = 0;
953 
954  while (i < old_func.length ())
955  {
956  std::string t1 = old_func.substr (i, 1);
957 
958  if (t1 == "*" || t1 == "/" || t1 == "\\" || t1 == "^")
959  {
960  if (i && old_func.substr (i-1, 1) != ".")
961  new_func.append (".");
962 
963  // Special case for ** operator.
964  if (t1 == "*" && i < (old_func.length () - 1)
965  && old_func.substr (i+1, 1) == "*")
966  {
967  new_func.append ("*");
968  i++;
969  }
970  }
971  new_func.append (t1);
972  i++;
973  }
974 
975  if (func_is_string)
976  return ovl (new_func);
977  else
978  return ovl (new octave_fcn_inline (new_func, old->fcn_arg_names ()));
979 }
980 
981 /*
982 %!assert (char (vectorize (fn)), "x.^2 + 1")
983 %!assert (char (vectorize (inline ("1e-3*y + 2e4*z"))), "1e-3.*y + 2e4.*z")
984 %!assert (char (vectorize (inline ("2**x^5"))), "2.**x.^5")
985 %!assert (vectorize ("x.^2 + 1"), "x.^2 + 1")
986 %!assert (vectorize ("1e-3*y + 2e4*z"), "1e-3.*y + 2e4.*z")
987 %!assert (vectorize ("2**x^5"), "2.**x.^5")
988 
989 ## Test input validation
990 %!error vectorize ()
991 %!error vectorize (1, 2)
992 %!error <FUN must be a string or inline function> vectorize (1)
993 */
std::string read_until_newline(std::istream &is, bool keep_newline)
bool is_empty(void) const
Definition: Array.h:575
Definition: Cell.h:37
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
const octave_hdf5_id octave_H5S_ALL
octave_map map_value(void) const
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
bool save_binary(std::ostream &os, bool &save_as_floats)
static octave_function * current(void)
Definition: call-stack.h:108
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:169
void skip_preceeding_newline(std::istream &is)
octave_value fcn_val(void) const
octave_fcn_handle * fcn_handle_value(bool silent=false) const
Definition: ov.cc:1729
OCTAVE_EXPORT octave_value_list Finline(const octave_value_list &args, int) the arguments of the generated function are extracted from the function itself.The generated function arguments will then be in alphabetical order.It should be noted that i and j are ignored as arguments due to the ambiguity between their use as a variable or their use as an built-in const ant.All arguments followed by a parenthesis are considered to be functions.If no arguments are found
s
Definition: file-io.cc:2682
bool load_ascii(std::istream &is)
void newline(std::ostream &os) const
Definition: ov-base.cc:1381
void resize(octave_idx_type n, const std::string &rfv="")
Definition: str-vec.h:97
std::string fcn_text(void) const
Definition: ov-fcn-inline.h:66
void print(std::ostream &os, bool pr_as_read_syntax=false)
virtual symbol_table::scope_id scope(void)
Definition: ov-fcn.h:77
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
bool swap
Definition: load-save.cc:725
JNIEnv void * args
Definition: ov-java.cc:67
void warn_load(const char *type) const
Definition: ov-base.cc:1151
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:60
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:80
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
int nargin
Definition: graphics.cc:10115
octave_user_function * user_function_value(bool silent=false) const
Definition: ov.cc:1711
string_vector ifargs
Definition: ov-fcn-inline.h:99
string_vector & append(const std::string &s)
Definition: str-vec.cc:107
void stash_parent_fcn_scope(symbol_table::scope_id ps)
Definition: ov-usr-fcn.h:227
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
#define DEFUNX(name, fname, args_name, nargout_name, doc)
Definition: defun.h:54
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
virtual symbol_table::scope_id parent_fcn_scope(void) const
Definition: ov-fcn.h:73
int64_t octave_hdf5_id
string_vector & sort(bool make_uniq=false)
Definition: str-vec.cc:74
idx type
Definition: ov.cc:3129
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
void warn_save(const char *type) const
Definition: ov-base.cc:1160
octave_value convert_to_str_internal(bool, bool, char) const
std::string iftext
Definition: ov-fcn-inline.h:96
friend class octave_value
Definition: ov-base.h:211
bool save_ascii(std::ostream &os)
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:354
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
int current_print_indent_level(void) const
Definition: ov-base.h:830
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:223
octave_value fcn
void octave_print_internal(std::ostream &, char, bool)
Definition: pr-output.cc:1722
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
bool is_undefined(void) const
Definition: ov.h:539
const octave_hdf5_id octave_H5P_DEFAULT
string_vector fcn_arg_names(void) const
Definition: ov-fcn-inline.h:68
OCTINTERP_API octave_value_list eval_string(const std::string &, bool silent, int &parse_status, int nargout)
write the output to stdout if nargout is
Definition: load-save.cc:1576
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854