1## Copyright (C) 2011 Juan Pablo Carbajal <carbajal@ifi.uzh.ch> 2## 3## This program is free software: you can redistribute it and/or modify 4## it under the terms of the GNU General Public License as published by 5## the Free Software Foundation, either version 3 of the License, or 6## (at your option) any later version. 7## 8## This program is distributed in the hope that it will be useful, 9## but WITHOUT ANY WARRANTY; without even the implied warranty of 10## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11## GNU General Public License for more details. 12## 13## You should have received a copy of the GNU General Public License 14## along with this program; see the file COPYING. If not, see 15## <https://www.gnu.org/licenses/>. 16 17## -*- texinfo -*- 18## @deftypefn {Function File} {[@var{fhandle}, @var{fullname}] =} data2fun (@var{ti}, @var{yi}) 19## @deftypefnx {Function File} {[@dots{}] =} data2fun (@dots{}, @var{property}, @var{value}) 20## Create a vectorized function based on data samples using interpolation. 21## 22## The values given in @var{yi} (N-by-k matrix) correspond to evaluations of the 23## function y(t) at the points @var{ti} (N-by-1 matrix). 24## The data is interpolated and the function handle to the generated interpolant 25## is returned. 26## 27## The function accepts @var{property}-@var{value} pairs described below. 28## 29## @table @samp 30## @item file 31## Code is generated and .m file is created. The @var{value} contains the name 32## of the function. The returned function handle is a handle to that file. If 33## @var{value} is empty, then a name is automatically generated using 34## @code{tempname} and the file is created in the current directory. @var{value} 35## must not have an extension, since .m will be appended. 36## Numerical values used in the function are stored in a .mat file with the same 37## name as the function. 38## 39## @item interp 40## Type of interpolation. See @code{interp1}. 41## @end table 42## 43## @seealso{interp1} 44## @end deftypefn 45 46function [fhandle, fullfname] = data2fun (t, y, varargin) 47 48 if (nargin < 2 || mod (nargin, 2) != 0) 49 print_usage (); 50 endif 51 52 ## Check input arguments 53 interp_args = {"spline"}; 54 given = struct ("file", false); 55 56 if (! isempty (varargin)) 57 ## Arguments 58 interp_args = varargin; 59 60 opt_args = fieldnames (given); 61 [tf, idx] = ismember (opt_args, varargin); 62 for i=1:numel (opt_args) 63 given.(opt_args{i}) = tf(i); 64 endfor 65 66 if (given.file) 67 ## FIXME: check that file will be in the path. Otherwise fhandle(0) fails. 68 69 if (! isempty (varargin{idx(1)+1})) 70 [dir, fname] = fileparts (varargin{idx(1)+1}); 71 else 72 [dir, fname] = fileparts (tempname (pwd (), "agen_")); 73 endif 74 75 interp_args(idx(1) + [0, 1]) = []; 76 endif 77 78 if (isempty (interp_args)) 79 interp_args = {"spline"}; 80 endif 81 82 endif 83 84 pp = interp1 (t, y, interp_args{end}, "pp"); 85 86 if (given.file) 87 fullfname = fullfile (dir, [fname, ".m"]); 88 save ("-binary", [fullfname(1:end-2), ".mat"], "pp"); 89 90 bodystr = [" persistent pp\n" ... 91 " if (isempty (pp))\n" ... 92 " pp = load ([mfilename(), \".mat\"]).pp;\n" ... 93 " endif\n\n" ... 94 " z = ppval (pp, x);"]; 95 96 strfunc = generate_function_str (fname, {"z"}, {"x"}, bodystr); 97 98 fid = fopen (fullfile (dir, [fname, ".m"]), "w"); 99 fprintf (fid, "%s", strfunc); 100 fclose (fid); 101 102 fhandle = eval (["@", fname]); 103 else 104 fullfname = ""; 105 fhandle = @(t_) ppval (pp, t_); 106 endif 107 108endfunction 109 110function str = generate_function_str (name, oargs, iargs, bodystr) 111 112 striargs = cell2mat (cellfun (@(x) [x ", "], iargs, "UniformOutput", false)); 113 striargs = striargs(1:end-2); 114 115 stroargs = cell2mat (cellfun (@(x) [x ", "], oargs, "UniformOutput", false)); 116 stroargs = stroargs(1:end-2); 117 118 if (! isempty (stroargs)) 119 str = ["function [" stroargs "] = " name " (" striargs ")\n\n" ... 120 bodystr "\n\nendfunction"]; 121 else 122 str = ["function " name " (" striargs ")\n\n" ... 123 bodystr "\n\nendfunction"]; 124 endif 125 126endfunction 127 128%!shared t, y 129%! t = linspace (0, 1, 10); 130%! y = t.^2 - 2*t + 1; 131 132%!test 133%! fhandle = data2fun (t, y); 134%! assert (y, fhandle (t)); 135 136%!test 137%! unwind_protect 138%! [fhandle fname] = data2fun (t, y, "file", "testdata2fun"); 139%! yt = testdata2fun (t); 140%! assert (y, yt); 141%! assert (y, fhandle (t)); 142%! unwind_protect_cleanup 143%! unlink (fname); 144%! unlink ([fname(1:end-2) ".mat"]); 145%! end_unwind_protect 146 147%!test 148%! unwind_protect 149%! [fhandle fname] = data2fun (t, y, "file", ""); 150%! yt = testdata2fun (t); 151%! assert (y, yt); 152%! assert (y, fhandle (t)); 153%! unwind_protect_cleanup 154%! unlink (fname); 155%! unlink ([fname(1:end-2) ".mat"]); 156%! end_unwind_protect 157 158%!test 159%! unwind_protect 160%! [fhandle fname] = data2fun (t, y, "file", "testdata2fun", "interp", "linear"); 161%! yt = testdata2fun (t); 162%! assert (y, yt); 163%! assert (y, fhandle (t)); 164%! unwind_protect_cleanup 165%! unlink (fname); 166%! unlink ([fname(1:end-2) ".mat"]); 167%! end_unwind_protect 168 169## Test input validation 170%!error data2fun () 171%!error data2fun (1) 172%!error data2fun (1, 2, "file") 173