1%% Copyright (C) 2014, 2016, 2018-2019 Colin B. Macdonald 2%% 3%% This file is part of OctSymPy. 4%% 5%% OctSymPy is free software; you can redistribute it and/or modify 6%% it under the terms of the GNU General Public License as published 7%% by the Free Software Foundation; either version 3 of the License, 8%% or (at your option) any later version. 9%% 10%% This software is distributed in the hope that it will be useful, 11%% but WITHOUT ANY WARRANTY; without even the implied warranty 12%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13%% the GNU General Public License for more details. 14%% 15%% You should have received a copy of the GNU General Public 16%% License along with this software; see the file COPYING. 17%% If not, see <http://www.gnu.org/licenses/>. 18 19%% -*- texinfo -*- 20%% @documentencoding UTF-8 21%% @defun findsymbols (@var{x}) 22%% Return a list (cell array) of the symbols in an expression. 23%% 24%% The list is sorted alphabetically. For details, @pxref{@@sym/symvar}. 25%% 26%% If two variables have the same symbol but different assumptions, 27%% they will both appear in the output. It is not well-defined 28%% in what order they appear. 29%% 30%% @var{x} could be a sym, sym array, cell array, or struct. 31%% 32%% @example 33%% @group 34%% syms x y z 35%% C = @{x, 2*x*y, [1 x; sin(z) pi]@}; 36%% S = findsymbols (C) 37%% @result{} S = @{ ... @} 38%% S@{:@} 39%% @result{} ans = (sym) x 40%% @result{} ans = (sym) y 41%% @result{} ans = (sym) z 42%% @end group 43%% @end example 44%% 45%% Note ℯ, ⅈ, π, etc are not considered as symbols. 46%% 47%% Note only returns symbols actually appearing in the RHS of a 48%% @code{symfun}. 49%% 50%% @seealso{symvar, @@sym/symvar, @@sym/findsym} 51%% @end defun 52 53function L = findsymbols(obj, dosort) 54 55 if (nargin == 1) 56 dosort = true; 57 elseif (nargin ~= 2) 58 print_usage (); 59 end 60 61 if isa(obj, 'sym') 62 cmd = { 's = _ins[0].free_symbols' 63 'l = list(s)' 64 'l = sorted(l, key=str)' 65 'return l,' }; 66 L = pycall_sympy__ (cmd, obj); 67 68 69 elseif iscell(obj) 70 %fprintf('Recursing into a cell array of numel=%d\n', numel(obj)) 71 L = {}; 72 for i=1:numel(obj) 73 temp = findsymbols(obj{i}, false); 74 if ~isempty(temp) 75 L = {L{:} temp{:}}; 76 end 77 end 78 79 80 elseif isstruct(obj) 81 %fprintf('Recursing into a struct array of numel=%d\n', numel(obj)) 82 L = {}; 83 fields = fieldnames(obj); 84 for i=1:numel(obj) 85 for j=1:length(fields) 86 thisobj = getfield(obj, {i}, fields{j}); 87 temp = findsymbols(thisobj, false); 88 if ~isempty(temp) 89 L = {L{:} temp{:}}; 90 end 91 end 92 end 93 94 else 95 L = {}; 96 end 97 98 99 % sort and make unique using internal representation 100 if dosort 101 Ls = {}; 102 for i=1:length(L) 103 Ls{i} = sympy (L{i}); 104 end 105 [tilde, I] = unique(Ls); 106 L = L(I); 107 end 108end 109 110 111%!test 112%! syms x b y n a arlo 113%! z = a*x + b*pi*sin (n) + exp (y) + exp (sym (1)) + arlo; 114%! s = findsymbols (z); 115%! assert (isequal ([s{:}], [a,arlo,b,n,x,y])) 116%!test 117%! syms x 118%! s = findsymbols (x); 119%! assert (isequal (s{1}, x)) 120%!test 121%! syms z x y a 122%! s = findsymbols ([x y; 1 a]); 123%! assert (isequal ([s{:}], [a x y])) 124%!assert (isempty (findsymbols (sym (1)))) 125%!assert (isempty (findsymbols (sym ([1 2])))) 126%!assert (isempty (findsymbols (sym (nan)))) 127%!assert (isempty (findsymbols (sym (inf)))) 128%!assert (isempty (findsymbols (exp (sym (2))))) 129 130%!test 131%! % empty sym for findsymbols, findsym, and symvar 132%! assert (isempty (findsymbols (sym([])))) 133%! assert (isempty (findsym (sym([])))) 134%! assert (isempty (symvar (sym([])))) 135 136%!test 137%! % diff. assumptions make diff. symbols 138%! x1 = sym('x'); 139%! x2 = sym('x', 'positive'); 140%! f = x1*x2; 141%! assert (length (findsymbols (f)) == 2) 142 143%!test 144%! % symfun or sym 145%! syms x f(y) 146%! a = f*x; 147%! b = f(y)*x; 148%! assert (isequal (findsymbols(a), {x y})) 149%! assert (isequal (findsymbols(b), {x y})) 150 151%!test 152%! % findsymbols on symfun does not find the argnames (unless they 153%! % are on the RHS of course, this matches SMT 2014a). 154%! syms a x y 155%! f(x, y) = a; % const symfun 156%! assert (isequal (findsymbols(f), {a})) 157%! syms a x y 158%! f(x, y) = a*y; 159%! assert (isequal (findsymbols(f), {a y})) 160 161%!test 162%! % sorts lexigraphically, same as symvar *with single input* 163%! % (note symvar does something different with 2 inputs). 164%! syms A B a b x y X Y 165%! f = A*a*B*b*y*X*Y*x; 166%! assert (isequal (findsymbols(f), {A B X Y a b x y})) 167%! assert (isequal (symvar(f), [A B X Y a b x y])) 168 169%!test 170%! % symbols in matpow 171%! syms x y 172%! syms n 173%! A = [sin(x) 2; y 1]; 174%! B = A^n; 175%! L = findsymbols(B); 176%! assert (isequal (L, {n x y})) 177