1%% Copyright (C) 2014-2016, 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%% @defmethod @@sym display (@var{x})
22%% Display, on command line, the contents of a symbolic expression.
23%%
24%% Examples:
25%% @example
26%% @group
27%% x = sym('x')
28%%   @result{} x = (sym) x
29%%
30%% display(x)
31%%   @result{} x = (sym) x
32%%
33%% display([x 2 pi])
34%%   @result{} (sym) [x  2  π]  (1×3 matrix)
35%% @end group
36%% @end example
37%%
38%% Other examples:
39%% @example
40%% @group
41%% A = sym([1 2; 3 4])
42%%   @result{} A = (sym 2×2 matrix)
43%%       ⎡1  2⎤
44%%       ⎢    ⎥
45%%       ⎣3  4⎦
46%% @end group
47%%
48%% @group
49%% syms n
50%% A = sym('A', [n n])
51%%   @result{} A = (sym) A  (n×n matrix expression)
52%% B = 3*A
53%%   @result{} B = (sym) 3⋅A  (n×n matrix expression)
54%%
55%% A = sym(ones(0, 3))
56%%   @result{} A = (sym) []  (empty 0×3 matrix)
57%%
58%% A = sym('A', [0, n])
59%%   @result{} A = (sym) A  (empty 0×n matrix expression)
60%% B = 3*A
61%%   @result{} B = (sym) 3⋅A  (empty 0×n matrix expression)
62%% @end group
63%% @end example
64%%
65%% @seealso{@@sym/disp}
66%% @end defmethod
67
68
69function display(x)
70
71  %% Settings
72  wh = sympref('display');
73  if (strcmp(wh, 'unicode'))
74    unicode_dec = true;
75  else
76    unicode_dec = false;
77  end
78  if (exist('OCTAVE_VERSION', 'builtin') && ...
79      compare_versions (OCTAVE_VERSION (), '4.3.0', '>='))
80    [fmt, spacing] = format();
81    loose = strcmp (spacing, 'loose');
82  elseif (exist('OCTAVE_VERSION', 'builtin') && ...
83      compare_versions (OCTAVE_VERSION (), '4.0.0', '>='))
84    % Octave 4.1 dropped (temporarily?) the get(0,...) approach
85    loose = eval('! __compactformat__ ()');
86  else
87    % Matlab and Octave < 4
88    loose = strcmp(get(0, 'FormatSpacing'), 'loose');
89  end
90
91  % weird hack to support "ans(x) = " output for @symfun
92  name = private_disp_name(x, inputname (1));
93
94  dispstr = disp (x);
95  dispstrtrim = strtrim (dispstr);
96  hasnewlines = ~isempty (strfind (dispstrtrim, sprintf('\n')));
97
98  [desc_start, desc_end] = sym_describe (x, unicode_dec);
99
100  toobig = hasnewlines;
101  %toobig = hasnewlines || ~(isempty(x) || isscalar(x));
102
103  s1 = '';
104  if (~isempty(name))
105    s1 = sprintf ('%s = ', name);
106  end
107
108  if (toobig)
109    if (isempty(desc_end))
110      s2 = sprintf('(%s)', desc_start);
111    else
112      s2 = sprintf('(%s %s)', desc_start, desc_end);
113    end
114  else
115    if (isempty(desc_end))
116      s2 = sprintf('(%s) %s', desc_start, dispstrtrim);
117    else
118      s2 = sprintf('(%s) %s  (%s)', desc_start, dispstrtrim, desc_end);
119    end
120  end
121  s = [s1 s2];
122  disp (s)
123
124  if (toobig)
125    if (loose), fprintf ('\n'); end
126    % don't use printf b/c ascii-art might have slashes
127    disp (dispstr(1:end-1));  % remove existing newline, disp adds one
128    if (loose), fprintf ('\n'); end
129  end
130end
131
132
133function [s1 s2] = sym_describe(x, unicode_dec)
134  if (unicode_dec)
135    %timesstr = '×';  % https://savannah.gnu.org/bugs/index.php?56072
136    timesstr = do_highbyte_escapes('\xc3\x97');
137  else
138    timesstr = 'x';
139  end
140
141  s1 = class (x);
142  srepr = sympy (x);
143  d = size (x);
144
145  % sort of isinstance(x, MatrixExpr) but cheaper
146  is_matrix_symbol = false;
147  matexprlist = {'MatrixSymbol' 'MatMul' 'MatAdd' 'MatPow'};
148  for i=1:length(matexprlist)
149    if (strncmp(srepr, matexprlist{i}, length(matexprlist{i})))
150      is_matrix_symbol = true;
151    end
152  end
153
154  if (isscalar (x)) && (~is_matrix_symbol)
155    s2 = '';
156  elseif (is_matrix_symbol)
157    %if (any(isnan(d)))  % may not tell the truth
158    if (any(isnan(x.size)))
159      [nn, mm] = pycall_sympy__ ('return (_ins[0].rows, _ins[0].cols)', x);
160      numrstr = strtrim(disp(nn, 'flat'));
161      numcstr = strtrim(disp(mm, 'flat'));
162    else
163      nn = d(1);  mm = d(2);
164      numrstr = num2str(d(1), '%g');
165      numcstr = num2str(d(2), '%g');
166    end
167    if (logical(nn == 0) || logical(mm == 0))
168      estr = 'empty ';
169    else
170      estr = '';
171    end
172    s2 = sprintf ('%s%s%s%s matrix expression', estr, numrstr, timesstr, numcstr);
173  elseif (length (d) == 2)
174    if (isempty (x))
175      estr = 'empty ';
176    else
177      estr = '';
178    end
179    s2 = sprintf ('%s%g%s%g matrix', estr, d(1), timesstr, d(2));
180  else
181    s2 = sprintf ('%d-dim array', length (d))
182  end
183end
184
185
186% FIXME: Could quietly test with "evalc", but [missing in
187% Octave](https://savannah.gnu.org/patch/?8033).  For now, a dummy
188% test.  Doctests will cover this anyway.
189%!test
190%! assert(true)
191