Skip to content

Commit

Permalink
Merge pull request #1279 from gnu-octave/add_fplot
Browse files Browse the repository at this point in the history
New function, fplot
  • Loading branch information
cbm755 authored Oct 28, 2023
2 parents 2d607a1 + e32e175 commit 3f1b864
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 29 deletions.
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
octsympy 3.1.1+
===============

* New symbolic commands:

fplot

* Move repo to https://github.com/gnu-octave/symbolic
* `sym(<array>, ratflag)` now respects `ratflag` (issue #1273).
* Changed metainfo.xml ID and corrected long-standing "Addon"
Expand Down
10 changes: 4 additions & 6 deletions inst/@sym/ezmesh.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% Copyright (C) 2019 Colin B. Macdonald
%% Copyright (C) 2019, 2023 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
Expand Down Expand Up @@ -81,12 +81,10 @@
assert(length(thissym) <= 2, ...
'ezmesh: parameterized: functions should have at most two inputs');
if (isempty(thissym))
% a number, create a constant function in a dummy variable
% (0*t works around some Octave oddity on 3.8 and hg Dec 2014)
thisf = inline(sprintf('%g + 0*t', double(varargin{i})), 't');
%thisf = @(t) 0*t + double(varargin{i}); % no
% constant function
thisf = function_handle (varargin{i}, 'vars', sym ('t'));
else
% check variables match (sanity check)
% check variables match over each function
if (isempty(firstsym))
firstsym = thissym;
else
Expand Down
12 changes: 5 additions & 7 deletions inst/@sym/ezplot.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% Copyright (C) 2014-2017 Colin B. Macdonald
%% Copyright (C) 2014-2017, 2023 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
Expand Down Expand Up @@ -73,7 +73,7 @@
%% The solution, as shown in the example, is to convert the sym to
%% a double.
%%
%% @seealso{ezplot, @@sym/ezplot3, @@sym/ezsurf, @@sym/function_handle}
%% @seealso{ezplot, @@sym/ezplot3, @@sym/ezsurf, @@sym/fplot, @@sym/function_handle}
%% @end defmethod


Expand Down Expand Up @@ -102,12 +102,10 @@
assert(length(thissym) <= 2, ...
'ezplot: plotting curves: functions should have at most two inputs');
if (isempty(thissym))
% a number, create a constant function in a dummy variable
% (0*t works around some Octave oddity on 3.8 and hg Dec 2014)
thisf = inline(sprintf('%g + 0*t', double(varargin{i})), 't');
%thisf = @(t) 0*t + double(varargin{i}); % no
% constant function
thisf = function_handle (varargin{i}, 'vars', sym ('t'));
else
% check variables match (sanity check)
% check variables match over each function
if (isempty(firstsym))
firstsym = thissym;
else
Expand Down
10 changes: 4 additions & 6 deletions inst/@sym/ezplot3.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% Copyright (C) 2014-2016 Colin B. Macdonald
%% Copyright (C) 2014-2016, 2023 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
Expand Down Expand Up @@ -66,12 +66,10 @@
assert(length(thissym) <= 1, ...
'ezplot3: plotting curves: functions should have at most one input');
if (isempty(thissym))
% a number, create a constant function in a dummy variable
% (0*t works around some Octave oddity on 3.8 and hg Dec 2014)
thisf = inline(sprintf('%g + 0*t', double(varargin{i})), 't');
%thisf = @(t) 0*t + double(varargin{i}); % no
% constant function
thisf = function_handle (varargin{i}, 'vars', sym ('t'));
else
% check variables match (sanity check)
% check variables match over each function
if (isempty(firstsym))
firstsym = thissym;
else
Expand Down
12 changes: 5 additions & 7 deletions inst/@sym/ezsurf.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% Copyright (C) 2016-2017, 2019 Colin B. Macdonald
%% Copyright (C) 2016-2017, 2019, 2023 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
Expand Down Expand Up @@ -80,13 +80,11 @@
thissym = symvar(varargin{i});
assert(length(thissym) <= 2, ...
'ezsurf: parameterized: functions should have at most two inputs');
if (isempty(thissym))
% a number, create a constant function in a dummy variable
% (0*t works around some Octave oddity on 3.8 and hg Dec 2014)
thisf = inline(sprintf('%g + 0*t', double(varargin{i})), 't');
%thisf = @(t) 0*t + double(varargin{i}); % no
if (isempty (thissym))
% constant function
thisf = function_handle (varargin{i}, 'vars', sym ('t'));
else
% check variables match (sanity check)
% check variables match over each function
if (isempty(firstsym))
firstsym = thissym;
else
Expand Down
211 changes: 211 additions & 0 deletions inst/@sym/fplot.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
%% Copyright (C) 2023 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod @@sym fplot (@var{f})
%% @defmethodx @@sym fplot (@var{f}, @var{limits})
%% @defmethodx @@sym fplot (@dots{}, @dots{}, @var{N})
%% @defmethodx @@sym fplot (@dots{}, @dots{}, @var{tol})
%% @defmethodx @@sym fplot (@dots{}, @dots{}, @var{fmt})
%% @defmethodx @@sym {[@var{x}, @var{y}] =} fplot (@dots{})
%% Plot a symbolic expression.
%%
%% Examples:
%% @example
%% @group
%% syms x
%% y = cos(3*x)
%% @result{} y = (sym) cos(3⋅x)
%%
%% @c doctest: +SKIP
%% fplot (y)
%%
%% @c doctest: +SKIP
%% fplot (y, [0 pi])
%% @end group
%% @end example
%%
%% You can also grab the data that would be plotted and plot it
%% yourself:
%% @example
%% @group
%% syms x
%%
%% @c doctest: +SKIP_IF(compare_versions (OCTAVE_VERSION(), '6.0.0', '<'))
%% [xx, yy] = fplot (sin (x), [0 1])
%% @result{} xx =
%% 0
%% ...
%% 1.0000
%% @result{} yy =
%% 0
%% ...
%% 0.8415
%%
%% @c doctest: +SKIP
%% plot (xx, yy)
%% @end group
%% @end example
%%
%% See help for the (non-symbolic) @code{fplot}, which this
%% routine calls after trying to convert sym inputs to
%% anonymous functions.
%%
%% @seealso{fplot, @@sym/ezplot, @@sym/function_handle}
%% @end defmethod


function [xx, yy] = fplot (varargin)

% first input is handle, shift
if (ishandle (varargin{1}))
fshift = 1;
else
fshift = 0;
end

for i = (1+fshift):nargin
if (isa (varargin{i}, 'sym'))
if (i == 1 + fshift)
thissym = symvar (varargin{i});
assert (length (thissym) <= 1, ...
'fplot: functions should have at most one input');
if (isempty (thissym))
thisf = function_handle (varargin{i}, 'vars', sym ('x'));
else
thisf = function_handle (varargin{i});
end

varargin{i} = thisf;

else
% plot ranges, etc, convert syms to doubles
varargin{i} = double (varargin{i});
end
end
end

if (nargout)
[xx, yy] = fplot (varargin{:});
else
fplot(varargin{:});
end

end


%!test
%! % simple
%! syms x
%! f = cos (x);
%! fplot (f);

%!test
%! % constant function
%! fplot (sym (10));

%!test
%! syms x
%! f = cos (x);
%! [xx, yy] = fplot (f);
%! assert (xx(1), -5)
%! assert (xx(end), 5)
%! assert (min (yy), -1, 0.1)
%! assert (max (yy), 1, 0.1)

%!test
%! syms x
%! f = cos (x);
%! dom = [1 3];
%! [xx, yy] = fplot (f, dom);
%! assert (xx(1), dom(1))
%! assert (xx(end), dom(2))

%!test
%! syms x
%! f = cos (x);
%! dom = [1 3];
%! fplot (f, dom);
%! assert (get (gca, 'xlim'), dom)

%!test
%! syms x
%! f = exp (x);
%! dom = [1 2 3 4];
%! fplot (f, dom);
%! assert (get (gca, 'xlim'), dom(1:2))
%! assert (get (gca, 'ylim'), dom(3:4))

%!test
%! % bounds as syms
%! syms x
%! f = cos (x);
%! dom = [1 2 3 4];
%! fplot (f, sym (dom));
%! assert (get (gca, 'xlim'), dom(1:2))
%! assert (get (gca, 'ylim'), dom(3:4))

%!test
%! % bounds as syms, regular handle for function
%! % fails on 6.1.0, maybe earlier too?
%! if (compare_versions (OCTAVE_VERSION (), '6.1.0', '!='))
%! dom = [1 2];
%! fplot (@cos, sym (dom));
%! assert (get (gca, 'xlim'), dom(1:2))
%! end

%!error <at most one>
%! syms x y
%! fplot (x*y)

%!test
%! % N parameter does something
%! syms x
%! [xx, yy] = fplot (sin (x), [0 2], 5);
%! N = length (xx);
%! assert (N >= 5)
%! [xx, yy] = fplot (sin (x), [0 2], 1000);
%! N = length (xx);
%! assert (N == 1000)

%!test
%! % tolerance parameter does something
%! syms x
%! [xx, yy] = fplot (sin (exp (x/2)), [0 3], 0.1);
%! N1 = length (xx);
%! [xx, yy] = fplot (sin (exp (x/2)), [0 3], 0.01);
%! N2 = length (xx);
%! assert (N2 > N1)

%!test
%! % fmt parameter does something
%! syms x
%! fplot (sin (x), [0 6], 'rx--', 'linewidth', 5);
%! l = get (gca (), 'children');
%! assert (get (l, 'color'), [1 0 0])
%! assert (get (l, 'linewidth'), 5)

%! f = exp (x);
%! dom = [1 2 3 4];
%! fplot (f, dom);
%! assert (get (gca, 'xlim'), dom(1:2))
%! assert (get (gca, 'ylim'), dom(3:4))

%!test
%! close all
2 changes: 1 addition & 1 deletion inst/@sym/function_handle.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
M.name = out{1}{1};
M.code = out{1}{2};

assert (strcmp (M.name, [fcnname '.m']), 'sanity check failed: names should match');
assert (strcmp (M.name, [fcnname '.m']), 'correctness check failed: names should match');

file_to_write = fullfile(fcnpath, [fcnname '.m']);
[fid,msg] = fopen(file_to_write, 'w');
Expand Down
4 changes: 2 additions & 2 deletions util/convert_comments.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% Copyright (C) 2014-2018 Colin B. Macdonald
%% Copyright (C) 2014-2018, 2023 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
Expand Down Expand Up @@ -209,7 +209,7 @@ function convert_comments (basedir, subdir, dirout)
N = Nfcn;
fcn_line = ins{N};

% sanity checks
% correctness checks
I = strfind(ins{N+1}, '%');
if ~isempty(I) && I(1) == 1
ins{N}
Expand Down

0 comments on commit 3f1b864

Please sign in to comment.