Mercurial > octave
changeset 22663:9a939479308f
maint: Periodic merge of stable to default.
author | Rik <rik@octave.org> |
---|---|
date | Mon, 24 Oct 2016 09:04:30 -0700 |
parents | a93887d7f0da (current diff) 655157b34a9f (diff) |
children | f1bb2f0bcfec |
files | |
diffstat | 9 files changed, 173 insertions(+), 130 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/fft.cc Sun Oct 23 13:57:00 2016 -0700 +++ b/libinterp/corefcn/fft.cc Mon Oct 24 09:04:30 2016 -0700 @@ -49,8 +49,9 @@ octave_value retval; octave_value arg = args(0); + octave_idx_type n_points = -1; dim_vector dims = arg.dims (); - octave_idx_type n_points = -1; + int ndims = dims.ndims (); int dim = -1; if (nargin > 1) @@ -72,7 +73,7 @@ double dval = args(2).double_value (); if (octave::math::isnan (dval)) error ("%s: DIM cannot be NaN", fcn); - else if (dval < 1 || dval > dims.ndims ()) + else if (dval < 1 || dval > ndims) error ("%s: DIM must be a valid dimension along which to perform FFT", fcn); else @@ -80,21 +81,19 @@ dim = octave::math::nint (dval) - 1; } - for (octave_idx_type i = 0; i < dims.ndims (); i++) + // FIXME: This seems strange and unnecessary (10/21/16). + // How would you ever arrive at an octave_value object without correct dims? + // We certainly don't make this check every other place in Octave. + for (octave_idx_type i = 0; i < ndims; i++) if (dims(i) < 0) return retval; if (dim < 0) { - for (octave_idx_type i = 0; i < dims.ndims (); i++) - if (dims(i) > 1) - { - dim = i; - break; - } + dim = dims.first_non_singleton (); // And if the first argument is scalar? - if (dim < 0) + if (dim == ndims) dim = 1; } @@ -103,7 +102,7 @@ else dims(dim) = n_points; - if (dims.any_zero () || n_points == 0) + if (n_points == 0 || dims.any_zero ()) { if (arg.is_single_type ()) return octave_value (FloatNDArray (dims)); @@ -111,6 +110,16 @@ return octave_value (NDArray (dims)); } + if (n_points == 1) + { + octave_value_list idx (ndims); + for (octave_idx_type i = 0; i < ndims; i++) + idx(i) = idx_vector::colon; + idx(dim) = idx_vector (0); + + return arg.do_index_op (idx); + } + if (arg.is_single_type ()) { if (arg.is_real_type ()) @@ -230,9 +239,9 @@ } /* -%% Author: David Billinghurst (David.Billinghurst@riotinto.com.au) -%% Comalco Research and Technology -%% 02 May 2000 +## Author: David Billinghurst (David.Billinghurst@riotinto.com.au) +## Comalco Research and Technology +## 02 May 2000 %!test %! N = 64; %! n = 4; @@ -246,9 +255,9 @@ %! %! assert (S, answer, 4*N*eps); -%% Author: David Billinghurst (David.Billinghurst@riotinto.com.au) -%% Comalco Research and Technology -%% 02 May 2000 +## Author: David Billinghurst (David.Billinghurst@riotinto.com.au) +## Comalco Research and Technology +## 02 May 2000 %!test %! N = 64; %! n = 7; @@ -261,9 +270,9 @@ %! %! assert (ifft (S), s, 4*N*eps); -%% Author: David Billinghurst (David.Billinghurst@riotinto.com.au) -%% Comalco Research and Technology -%% 02 May 2000 +## Author: David Billinghurst (David.Billinghurst@riotinto.com.au) +## Comalco Research and Technology +## 02 May 2000 %!test %! N = 64; %! n = 4; @@ -277,9 +286,9 @@ %! %! assert (S, answer, 4*N*eps ("single")); -%% Author: David Billinghurst (David.Billinghurst@riotinto.com.au) -%% Comalco Research and Technology -%% 02 May 2000 +## Author: David Billinghurst (David.Billinghurst@riotinto.com.au) +## Comalco Research and Technology +## 02 May 2000 %!test %! N = 64; %! n = 7;
--- a/scripts/ode/ode23.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/ode23.m Mon Oct 24 09:04:30 2016 -0700 @@ -60,8 +60,9 @@ ## unknown of the problem and each row corresponds to a time in @var{t}. ## ## The output can also be returned as a structure @var{solution} which -## has field @var{x} containing the time where the solution was evaluated and -## field @var{y} containing the solution matrix for the times in @var{x}. +## has a field @var{x} containing a row vector of times where the solution +## was evaluated and a field @var{y} containing the solution matrix such +## that each column corresponds to a time in @var{x}. ## Use @code{fieldnames (@var{solution})} to see the other fields and ## additional information returned. ## @@ -155,15 +156,13 @@ [defaults, classes, attributes] = odedefaults (numel (init), trange(1), trange(end)); - defaults = rmfield (defaults, {"Jacobian", "JPattern", "Vectorized", ... - "MvPattern", "MassSingular", ... - "InitialSlope", "MaxOrder", "BDF"}); - classes = rmfield (classes, {"Jacobian", "JPattern", "Vectorized", ... - "MvPattern", "MassSingular", ... - "InitialSlope", "MaxOrder", "BDF"}); - attributes = rmfield (attributes, {"Jacobian", "JPattern", "Vectorized", ... - "MvPattern", "MassSingular", ... - "InitialSlope", "MaxOrder", "BDF"}); + persistent ode23_ignore_options = ... + {"BDF", "InitialSlope", "Jacobian", "JPattern", + "MassSingular", "MaxOrder", "MvPattern", "Vectorized"}; + + defaults = rmfield (defaults, ode23_ignore_options); + classes = rmfield (classes, ode23_ignore_options); + attributes = rmfield (attributes, ode23_ignore_options); odeopts = odemergeopts ("ode23", odeopts, defaults, classes, attributes); @@ -211,8 +210,7 @@ if (havemasshandle) # Handle only the dynamic mass matrix, if (! strcmp (odeopts.MStateDependence, "none")) - ## FIXME: How is this comment supposed to end? - ## constant mass matrices have already + ## constant mass matrices have already been handled mass = @(t,x) odeopts.Mass (t, x, odeopts.funarguments{:}); fun = @(t,x) mass (t, x, odeopts.funarguments{:}) ... \ fun (t, x, odeopts.funarguments{:}); @@ -223,6 +221,15 @@ endif endif + if (nargout == 1) + ## Single output requires auto-selected intermediate times, + ## which is obtained by NOT specifying specific solution times. + trange = [trange(1); trange(end)]; + odeopts.Refine = []; # disable Refine when single output requested + elseif (numel (trange) > 2) + odeopts.Refine = []; # disable Refine when specific times requested + endif + solution = integrate_adaptive (@runge_kutta_23, order, fun, trange, init, odeopts); @@ -232,7 +239,7 @@ endif if (! isempty (odeopts.Events)) # Cleanup event function handling ode_event_handler (odeopts.Events, solution.t(end), - solution.x(end,:)', "done", odeopts.funarguments{:}); + solution.x(end,:).', "done", odeopts.funarguments{:}); endif ## Print additional information if option Stats is set @@ -255,8 +262,8 @@ varargout{1} = solution.t; # Time stamps are first output argument varargout{2} = solution.x; # Results are second output argument elseif (nargout == 1) - varargout{1}.x = solution.t; # Time stamps are saved in field x - varargout{1}.y = solution.x; # Results are saved in field y + varargout{1}.x = solution.t.'; # Time stamps are saved in field x (row vector) + varargout{1}.y = solution.x.'; # Results are saved in field y (row vector) varargout{1}.solver = solver; # Solver name is saved in field solver if (! isempty (odeopts.Events)) varargout{1}.ie = solution.event{2}; # Index info which event occurred @@ -321,12 +328,6 @@ %!function ref = fref () # The computed reference sol %! ref = [0.32331666704577, -1.83297456798624]; %!endfunction -%!function jac = fjac (t, y, varargin) # its Jacobian -%! jac = [0, 1; -1 - 2 * y(1) * y(2), 1 - y(1)^2]; -%!endfunction -%!function jac = fjcc (t, y, varargin) # sparse type -%! jac = sparse ([0, 1; -1 - 2 * y(1) * y(2), 1 - y(1)^2]); -%!endfunction %!function [val, trm, dir] = feve (t, y, varargin) %! val = fpol (t, y, varargin); # We use the derivatives %! trm = zeros (2,1); # that's why component 2 @@ -391,41 +392,41 @@ %!test # Solve in backward direction starting at t=0 %! ref = [-1.205364552835178, 0.951542399860817]; %! sol = ode23 (@fpol, [0 -2], [2 0]); -%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 5e-3); +%! assert ([sol.x(end); sol.y(:,end)], [-2; ref'], 5e-3); %!test # Solve in backward direction starting at t=2 %! ref = [-1.205364552835178, 0.951542399860817]; %! sol = ode23 (@fpol, [2 0 -2], fref); -%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 2e-2); +%! assert ([sol.x(end); sol.y(:,end)], [-2; ref'], 2e-2); %!test # Solve another anonymous function in backward direction %! ref = [-1, 0.367879437558975]; %! sol = ode23 (@(t,y) y, [0 -1], 1); -%! assert ([sol.x(end), sol.y(end,:)], ref, 1e-2); +%! assert ([sol.x(end); sol.y(:,end)], ref', 1e-2); %!test # Solve another anonymous function below zero %! ref = [0, 14.77810590694212]; %! sol = ode23 (@(t,y) y, [-2 0], 2); -%! assert ([sol.x(end), sol.y(end,:)], ref, 1e-2); +%! assert ([sol.x(end); sol.y(:,end)], ref', 1e-2); %!test # Solve in backward direction starting at t=0 with MaxStep option %! ref = [-1.205364552835178, 0.951542399860817]; %! opt = odeset ("MaxStep", 1e-3); %! sol = ode23 (@fpol, [0 -2], [2 0], opt); %! assert ([abs(sol.x(8)-sol.x(7))], [1e-3], 1e-3); -%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [-2; ref'], 1e-3); %!test # AbsTol option %! opt = odeset ("AbsTol", 1e-5); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # AbsTol and RelTol option %! opt = odeset ("AbsTol", 1e-8, "RelTol", 1e-8); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # RelTol and NormControl option -- higher accuracy %! opt = odeset ("RelTol", 1e-8, "NormControl", "on"); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-4); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-4); %!test # Keeps initial values while integrating %! opt = odeset ("NonNegative", 2); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, 2, 0], 1e-1); +%! assert ([sol.x(end); sol.y(:,end)], [2; 2; 0], 1e-1); %!test # Details of OutputSel and Refine can't be tested %! opt = odeset ("OutputFcn", @fout, "OutputSel", 1, "Refine", 5); %! sol = ode23 (@fpol, [0 2], [2 0], opt); @@ -455,28 +456,41 @@ %!test # Mass option as function %! opt = odeset ("Mass", @fmas); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as matrix %! opt = odeset ("Mass", eye (2,2)); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as sparse matrix %! opt = odeset ("Mass", sparse (eye (2,2))); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as function and sparse matrix %! opt = odeset ("Mass", @fmsa); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as function and MStateDependence %! opt = odeset ("Mass", @fmas, "MStateDependence", "strong"); %! sol = ode23 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); -## FIXME: Missing tests. -## test for InitialSlope option is missing -## test for MaxOrder option is missing -## test for MvPattern option is missing +## Note: The following options have no effect on this solver +## therefore it makes no sense to test them here: +## +## "BDF" +## "InitialSlope" +## "JPattern" +## "Jacobian" +## "MassSingular" +## "MaxOrder" +## "MvPattern" +## "Vectorized" + +%!test # Check that imaginary part of solution does not get inverted +%! sol = ode23 (@(x,y) 1, [0 1], 1i); +%! assert (imag (sol.y), ones (size (sol.y))) +%! [x, y] = ode23 (@(x,y) 1, [0 1], 1i); +%! assert (imag (y), ones (size (y))) ## Test input validation %!error ode23 ()
--- a/scripts/ode/ode45.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/ode45.m Mon Oct 24 09:04:30 2016 -0700 @@ -58,8 +58,9 @@ ## unknown of the problem and each row corresponds to a time in @var{t}. ## ## The output can also be returned as a structure @var{solution} which -## has field @var{x} containing the time where the solution was evaluated and -## field @var{y} containing the solution matrix for the times in @var{x}. +## has a field @var{x} containing a row vector of times where the solution +## was evaluated and a field @var{y} containing the solution matrix such +## that each column corresponds to a time in @var{x}. ## Use @code{fieldnames (@var{solution})} to see the other fields and ## additional information returned. ## @@ -146,16 +147,16 @@ [defaults, classes, attributes] = odedefaults (numel (init), trange(1), trange(end)); - defaults = odeset (defaults, "Refine", 4); - defaults = rmfield (defaults, {"Jacobian", "JPattern", "Vectorized", ... - "MvPattern", "MassSingular", ... - "InitialSlope", "MaxOrder", "BDF"}); - classes = rmfield (classes, {"Jacobian", "JPattern", "Vectorized", ... - "MvPattern", "MassSingular", ... - "InitialSlope", "MaxOrder", "BDF"}); - attributes = rmfield (attributes, {"Jacobian", "JPattern", "Vectorized", ... - "MvPattern", "MassSingular", ... - "InitialSlope", "MaxOrder", "BDF"}); + ## FIXME: Refine is not correctly implemented yet + defaults = odeset (defaults, "Refine", 4); + + persistent ode45_ignore_options = ... + {"BDF", "InitialSlope", "Jacobian", "JPattern", + "MassSingular", "MaxOrder", "MvPattern", "Vectorized"}; + + defaults = rmfield (defaults, ode45_ignore_options); + classes = rmfield (classes, ode45_ignore_options); + attributes = rmfield (attributes, ode45_ignore_options); odeopts = odemergeopts ("ode45", odeopts, defaults, classes, attributes); @@ -214,6 +215,15 @@ endif endif + if (nargout == 1) + ## Single output requires auto-selected intermediate times, + ## which is obtained by NOT specifying specific solution times. + trange = [trange(1); trange(end)]; + odeopts.Refine = []; # disable Refine when single output requested + elseif (numel (trange) > 2) + odeopts.Refine = []; # disable Refine when specific times requested + endif + solution = integrate_adaptive (@runge_kutta_45_dorpri, order, fun, trange, init, odeopts); @@ -223,7 +233,7 @@ endif if (! isempty (odeopts.Events)) # Cleanup event function handling ode_event_handler (odeopts.Events, solution.t(end), - solution.x(end,:)', "done", odeopts.funarguments{:}); + solution.x(end,:).', "done", odeopts.funarguments{:}); endif ## Print additional information if option Stats is set @@ -246,8 +256,8 @@ varargout{1} = solution.t; # Time stamps are first output argument varargout{2} = solution.x; # Results are second output argument elseif (nargout == 1) - varargout{1}.x = solution.t; # Time stamps are saved in field x - varargout{1}.y = solution.x; # Results are saved in field y + varargout{1}.x = solution.t.'; # Time stamps are saved in field x (row vector) + varargout{1}.y = solution.x.'; # Results are saved in field y (row vector) varargout{1}.solver = solver; # Solver name is saved in field solver if (! isempty (odeopts.Events)) varargout{1}.ie = solution.event{2}; # Index info which event occurred @@ -312,12 +322,6 @@ %!function ref = fref () # The computed reference solution %! ref = [0.32331666704577, -1.83297456798624]; %!endfunction -%!function jac = fjac (t, y, varargin) # its Jacobian -%! jac = [0, 1; -1 - 2 * y(1) * y(2), 1 - y(1)^2]; -%!endfunction -%!function jac = fjcc (t, y, varargin) # sparse type -%! jac = sparse ([0, 1; -1 - 2 * y(1) * y(2), 1 - y(1)^2]); -%!endfunction %!function [val, trm, dir] = feve (t, y, varargin) %! val = fpol (t, y, varargin); # We use the derivatives %! trm = zeros (2,1); # that's why component 2 @@ -385,54 +389,54 @@ %! opt = odeset ("MaxStep", 1e-3); %! sol = ode45 (@fpol, [0 0.2], [2 0], opt); %! assert ([sol.x(5)-sol.x(4)], [1e-3], 1e-3); -%!test # Solve with intermidiate step -%! sol = ode45 (@fpol, [0 1 2], [2 0]); -%! assert (any((sol.x-1) == 0)); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%!test # Solve with intermediate step +%! [t, y] = ode45 (@fpol, [0 1 2], [2 0]); +%! assert (any((t-1) == 0)); +%! assert ([t(end), y(end,:)], [2, fref], 1e-3); %!test # Solve in backward direction starting at t=0 %! vref = [-1.205364552835178, 0.951542399860817]; %! sol = ode45 (@fpol, [0 -2], [2 0]); -%! assert ([sol.x(end), sol.y(end,:)], [-2, vref], 1e-2); +%! assert ([sol.x(end); sol.y(:,end)], [-2; vref'], 1e-2); %!test # Solve in backward direction starting at t=2 %! vref = [-1.205364552835178, 0.951542399860817]; %! sol = ode45 (@fpol, [2 -2], fref); -%! assert ([sol.x(end), sol.y(end,:)], [-2, vref], 1e-2); -%!test # Solve in backward direction starting at t=2, with intermidiate step +%! assert ([sol.x(end); sol.y(:,end)], [-2; vref'], 1e-2); +%!test # Solve in backward direction starting at t=2, with intermediate step %! vref = [-1.205364552835178, 0.951542399860817]; -%! sol = ode45 (@fpol, [2 0 -2], fref); -%! idx = find(sol.x < 0, 1, "first") - 1; -%! assert ([sol.x(idx), sol.y(idx,:)], [0 2 0], 1e-2); -%! assert ([sol.x(end), sol.y(end,:)], [-2, vref], 1e-2); +%! [t, y] = ode45 (@fpol, [2 0 -2], fref); +%! idx = find(y < 0, 1, "first") - 1; +%! assert ([t(idx), y(idx,:)], [0,2,0], 1e-2); +%! assert ([t(end), y(end,:)], [-2, vref], 1e-2); %!test # Solve another anonymous function in backward direction %! vref = [-1, 0.367879437558975]; %! sol = ode45 (@(t,y) y, [0 -1], 1); -%! assert ([sol.x(end), sol.y(end,:)], vref, 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], vref', 1e-3); %!test # Solve another anonymous function below zero %! vref = [0, 14.77810590694212]; %! sol = ode45 (@(t,y) y, [-2 0], 2); -%! assert ([sol.x(end), sol.y(end,:)], vref, 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], vref', 1e-3); %!test # Solve in backward direction starting at t=0 with MaxStep option %! vref = [-1.205364552835178, 0.951542399860817]; %! opt = odeset ("MaxStep", 1e-3); %! sol = ode45 (@fpol, [0 -2], [2 0], opt); %! assert ([abs(sol.x(8)-sol.x(7))], [1e-3], 1e-3); -%! assert ([sol.x(end), sol.y(end,:)], [-2, vref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [-2; vref'], 1e-3); %!test # AbsTol option %! opt = odeset ("AbsTol", 1e-5); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # AbsTol and RelTol option %! opt = odeset ("AbsTol", 1e-8, "RelTol", 1e-8); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # RelTol and NormControl option -- higher accuracy %! opt = odeset ("RelTol", 1e-8, "NormControl", "on"); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-5); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-5); %!test # Keeps initial values while integrating %! opt = odeset ("NonNegative", 2); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, 2, 0], 0.5); +%! assert ([sol.x(end); sol.y(:,end)], [2; 2; 0], 0.5); %!test # Details of OutputSel and Refine can't be tested %! opt = odeset ("OutputFcn", @fout, "OutputSel", 1, "Refine", 5); %! sol = ode45 (@fpol, [0 2], [2 0], opt); @@ -463,28 +467,41 @@ %!test # Mass option as function %! opt = odeset ("Mass", @fmas); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as matrix %! opt = odeset ("Mass", eye (2,2)); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as sparse matrix %! opt = odeset ("Mass", sparse (eye (2,2))); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as function and sparse matrix %! opt = odeset ("Mass", @fmsa); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); %!test # Mass option as function and MStateDependence %! opt = odeset ("Mass", @fmas, "MStateDependence", "strong"); %! sol = ode45 (@fpol, [0 2], [2 0], opt); -%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3); +%! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-3); -## FIXME: Missing tests. -## test for InitialSlope option is missing -## test for MaxOrder option is missing -## test for MvPattern option is missing +## Note: The following options have no effect on this solver +## therefore it makes no sense to test them here: +## +## "BDF" +## "InitialSlope" +## "JPattern" +## "Jacobian" +## "MassSingular" +## "MaxOrder" +## "MvPattern" +## "Vectorized" + +%!test # Check that imaginary part of solution does not get inverted +%! sol = ode45 (@(x,y) 1, [0 1], 1i); +%! assert (imag (sol.y), ones (size (sol.y))) +%! [x, y] = ode45 (@(x,y) 1, [0 1], 1i); +%! assert (imag (y), ones (size (y))) %!error ode45 () %!error ode45 (1)
--- a/scripts/ode/odeset.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/odeset.m Mon Oct 24 09:04:30 2016 -0700 @@ -60,6 +60,7 @@ ## ## @item BDF ## Use BDF formulas in implicit multistep methods. +## @strong{Note:} This option is not yet implemented. ## ## @item Events ## Event function. An event function must have the form @@ -103,6 +104,7 @@ ## @item MvPattern ## If the mass matrix is sparse and non-constant but maintains a ## constant sparsity pattern, specify the sparsity pattern. +## @strong{Note:} This option is not yet implemented. ## ## @item NonNegative ## Specify elements of the state vector that are expected to remain @@ -125,6 +127,7 @@ ## time step or also at intermediate time instances. The value should be ## a scalar indicating the number of equally spaced time points to use ## within each timestep at which to return output. +## @strong{Note:} This option is not yet implemented. ## ## @item RelTol ## Relative error tolerance.
--- a/scripts/ode/private/integrate_adaptive.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/private/integrate_adaptive.m Mon Oct 24 09:04:30 2016 -0700 @@ -193,6 +193,9 @@ approxvals = interp1 ([t_old, t(t_caught), t_new], [x_old, x(:, t_caught), x_new] .', approxtime, "linear") .'; + if (isvector (approxvals)) + approxvals = approxvals.'; + endif if (! isempty (options.OutputSel)) approxvals = approxvals(options.OutputSel, :); endif @@ -241,6 +244,9 @@ approxvals = interp1 ([t_old, t_new], [x_old, x_new] .', approxtime, "linear") .'; + if (isvector (approxvals)) + approxvals = approxvals.'; + endif if (! isempty (options.OutputSel)) approxvals = approxvals(options.OutputSel, :); endif
--- a/scripts/ode/private/ode_event_handler.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/private/ode_event_handler.m Mon Oct 24 09:04:30 2016 -0700 @@ -88,7 +88,7 @@ [evt, term, dir] = feval (inpargs{:}); ## We require that all return values be row vectors - evt = evt(:)'; term = term(:)'; dir = dir(:)'; + evt = evt(:).'; term = term(:).'; dir = dir(:).'; ## Check if one or more signs of the event has changed signum = (sign (evtold) != sign (evt)); @@ -115,7 +115,7 @@ ## calculate new values for the integration results, we do both by ## a linear interpolation tnew = t - evt(1,idx) * (t - told) / (evt(1,idx) - evtold(1,idx)); - ynew = (y - (t - tnew) * (y - yold) / (t - told))'; + ynew = (y - (t - tnew) * (y - yold) / (t - told)).'; retcell{3}(evtcnt,1) = tnew; retcell{4}(evtcnt,:) = ynew; evtcnt += 1; @@ -142,7 +142,7 @@ [evtold, ~, ~] = feval (inpargs{:}); ## We require that all return values be row vectors - evtold = evtold(:)'; told = t; yold = y; + evtold = evtold(:).'; told = t; yold = y; evtcnt = 1; retval = retcell = cell (1,4);
--- a/scripts/ode/private/odedefaults.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/private/odedefaults.m Mon Oct 24 09:04:30 2016 -0700 @@ -47,6 +47,7 @@ "Stats", "off", "Vectorized", "off"); + defaults.InitialSlope = zeros (n,1); defaults.MaxStep = 0.1 * abs (tf -t0); persistent classes = struct ("AbsTol", {{"float"}}, @@ -95,5 +96,9 @@ "RelTol", {{"scalar", "positive", "real"}}, "Stats", {{"on", "off"}}, "Vectorized", {{"on", "off"}}); + + attributes.InitialSlope = {"real", "vector", "numel", n}; + attributes.OutputSel = {"vector", "integer", "positive", ">", 0, "<=", n}; + endfunction
--- a/scripts/ode/private/runge_kutta_45_dorpri.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/private/runge_kutta_45_dorpri.m Mon Oct 24 09:04:30 2016 -0700 @@ -60,6 +60,9 @@ k_vals = [], t_next = t + dt) + ## Reference: Hairer, Ernst; Nørsett, Syvert Paul; Wanner, Gerhard (2008), + ## Solving ordinary differential equations I: Nonstiff problems, + ## Berlin, New York: Springer-Verlag, ISBN 978-3-540-56670-0 persistent a = [0 0 0 0 0 0; 1/5 0 0 0 0 0; 3/40 9/40 0 0 0 0; @@ -70,18 +73,13 @@ persistent c = [35/384, 0, 500/1113, 125/192, -2187/6784, 11/84]; persistent c_prime = [5179/57600, 0, 7571/16695, 393/640, ... -92097/339200, 187/2100, 1/40]; - ## FIXME: Which source is c_prime derived from? - ## Can't the Shampine clause be deleted if it will never be used? - ## According to Shampine 1986: - ## persistent c_prime = [(1951/21600) 0 (22642/50085) (451/720), ... - ## (-12231/42400) (649/6300) (1/60)]; s = t + dt * b; cc = dt * c; aa = dt * a; k = zeros (rows (x), 7); - if (! isempty (options)) # extra arguments for function evaluator + if (! isempty (options)) # extra arguments for function evaluator args = options.funarguments; else args = {};
--- a/scripts/ode/private/runge_kutta_interpolate.m Sun Oct 23 13:57:00 2016 -0700 +++ b/scripts/ode/private/runge_kutta_interpolate.m Mon Oct 24 09:04:30 2016 -0700 @@ -22,7 +22,7 @@ switch (order) case 1 - u_interp = interp1 (z, u', t, "linear"); + u_interp = interp1 (z, u.', t, "linear"); case 2 if (! isempty (k_vals)) @@ -35,15 +35,6 @@ case 3 u_interp = hermite_cubic_interpolation (z, u, k_vals, t); - ## FIXME: Do we need an algorithm for order = 4? - #{ - case 4 - ## if ode45 is used without local extrapolation this function - ## doesn't require a new function evaluation. - u_interp = dorpri_interpolation ([z(i-1) z(i)], - [u(:,i-1) u(:,i)], - k_vals, tspan(counter)); - #} case 5 ## ode45 with Dormand-Prince scheme: u_interp = hermite_quartic_interpolation (z, u, k_vals, t);