|
1 | 1 | ## Copyright (C) 2015 Carnë Draug <carandraug@octave.org> |
2 | 2 | ## Copyright (C) 2026 Andreas Bertsatos <abertsatos@biol.uoa.gr> |
| 3 | +## Copyright (C) 2026 Avanish Salunke <avanishsalunke16@gmail.com> |
3 | 4 | ## |
4 | 5 | ## This file is part of the statistics package for GNU Octave. |
5 | 6 | ## |
|
31 | 32 | ## @code{pdist} into a distance matrix. It performs the opposite operation |
32 | 33 | ## if input is a matrix. |
33 | 34 | ## |
34 | | -## If @var{x} is a numeric or logical vector, its number of elements must fit into the |
35 | | -## triangular part of a matrix (main diagonal excluded). In other words, |
36 | | -## @code{numel (@var{x}) = @var{n} * (@var{n} - 1) / 2} for some integer |
| 35 | +## If @var{x} is a numeric or logical vector, its number of elements must fit |
| 36 | +## into the triangular part of a matrix (main diagonal excluded). In other |
| 37 | +## words, @code{numel (@var{x}) = @var{n} * (@var{n} - 1) / 2} for some integer |
37 | 38 | ## @var{n}. The resulting matrix will be @var{n} by @var{n}. |
38 | 39 | ## |
39 | | -## If @var{x} is a numeric or logical distance matrix, it must be square and the diagonal entries |
40 | | -## of @var{x} must all be zeros. If @var{x} is not symmetric, only the lower |
41 | | -## triangular part is used. |
| 40 | +## If @var{x} is a numeric or logical distance matrix, it must be square and the |
| 41 | +## diagonal entries of @var{x} must all be zeros. If @var{x} is not symmetric, |
| 42 | +## only the lower triangular part is used. |
42 | 43 | ## |
43 | | -## The second argument is used to specify the output type in case there |
44 | | -## is a single element. Accepted values are @qcode{"tomatrix"} (or @qcode{"tom"}) |
45 | | -## and @qcode{"tovector"} (or @qcode{"tov"}). It will default to |
| 44 | +## The second argument is used to specify the output type in case the distance |
| 45 | +## input is a scalar. Accepted values are @qcode{'tomatrix'} (or @qcode{'tom'}) |
| 46 | +## and @qcode{'tovector'} (or @qcode{'tov'}). If not specified, it defaults to |
46 | 47 | ## @qcode{"tomatrix"} otherwise. |
47 | 48 | ## |
48 | 49 | ## @seealso{pdist} |
|
53 | 54 | if (nargin < 1 || nargin > 2) |
54 | 55 | print_usage (); |
55 | 56 | elseif (! isnumeric (x) && ! islogical (x)) |
56 | | - error ("squareform: Y or Z must be either numeric or logical."); |
| 57 | + error ("squareform: distance input must be either numeric or logical."); |
57 | 58 | elseif (! ismatrix (x)) |
58 | | - error ("squareform: Y or Z must be either a vector or a matrix."); |
| 59 | + error ("squareform: distance input must be either a vector or a matrix."); |
59 | 60 | endif |
60 | 61 |
|
61 | 62 | if (nargin == 1) |
62 | 63 | ## This is ambiguous when numel (x) == 1, but that's the whole reason |
63 | 64 | ## why the "method" option exists. |
64 | 65 | if (isvector (x)) |
65 | | - method = "tomatrix"; |
| 66 | + method = 'tomatrix'; |
66 | 67 | else |
67 | | - method = "tovector"; |
| 68 | + method = 'tovector'; |
68 | 69 | endif |
| 70 | + elseif (isstring (method)) |
| 71 | + if (! isscalar (method)) |
| 72 | + error (strcat ("squareform: second argument must be either", ... |
| 73 | + " a character vector or a string scalar.")); |
| 74 | + endif |
| 75 | + method = char (method); |
| 76 | + elseif (! ischar (method)) |
| 77 | + error (strcat ("squareform: second argument must be either", ... |
| 78 | + " a character vector or a string scalar.")); |
69 | 79 | endif |
70 | 80 |
|
71 | 81 | switch (tolower (method)) |
72 | 82 | case {'tovector', 'tov'} |
73 | 83 | if (! issquare (x)) |
74 | | - error ("squareform: Z is not a square matrix."); |
| 84 | + error ("squareform: distance input is not a square matrix."); |
75 | 85 | elseif (any (diag (x) != 0)) |
76 | | - error ("squareform: Z is not a hollow matrix."); |
| 86 | + error ("squareform: distance input is not a hollow matrix."); |
77 | 87 | endif |
78 | 88 |
|
79 | 89 | y = vec (tril (x, -1, "pack"), 2); |
|
83 | 93 | ## length (x) = (sy - 1) * (sy / 2) |
84 | 94 | sy = (1 + sqrt (1 + 8 * numel (x))) / 2; |
85 | 95 | if (fix (sy) != sy) |
86 | | - error ("squareform: the numel of Y cannot form a square matrix."); |
| 96 | + error ("squareform: distance input vector cannot form a square matrix."); |
87 | 97 | endif |
88 | 98 |
|
89 | 99 | y = zeros (sy, class (x)); |
|
103 | 113 |
|
104 | 114 | %!shared v, m |
105 | 115 | %! v = 1:6; |
106 | | -%! m = [0 1 2 3;1 0 4 5;2 4 0 6;3 5 6 0]; |
| 116 | +%! m = [0, 1, 2, 3; 1, 0, 4, 5; 2, 4, 0, 6; 3, 5, 6, 0]; |
107 | 117 |
|
108 | 118 | ## make sure that it can go both directions automatically |
109 | 119 | %!test |
|
118 | 128 | ## handle 1 element input properly |
119 | 129 | %!test |
120 | 130 | %!assert (squareform (1), [0 1;1 0]) |
121 | | -%!assert (squareform (1, "tomatrix"), [0 1; 1 0]) |
122 | | -%!assert (squareform (0, "tovector"), zeros (1, 0)) |
| 131 | +%!assert (squareform (1, 'tomatrix'), [0 1; 1 0]) |
| 132 | +%!assert (squareform (0, 'tovector'), zeros (1, 0)) |
123 | 133 |
|
124 | 134 | ## confirm that it respects input class |
125 | 135 | %!test |
126 | | -%! for c = {@single, @double, @uint8, @uint32, @uint64, @logical} |
| 136 | +%! for c = {@single, @double, @uint8, @uint16, @uint32, @uint64, @logical} |
127 | 137 | %! f = c{1}; |
128 | 138 | %! assert (squareform (f (v)), f (m)) |
129 | 139 | %! assert (squareform (f (m)), f (v)) |
|
137 | 147 | %! assert (squareform (m_log), v_log); |
138 | 148 |
|
139 | 149 | ## test partial string matching and case insensitivity |
140 | | -%!test |
141 | | -%! assert (squareform (v, "tom"), m); |
142 | | -%! assert (squareform (m, "tov"), v); |
143 | | -%! assert (squareform (v, "TOMATRIX"), m); |
| 150 | +%!assert (squareform (v, 'tom'), m); |
| 151 | +%!assert (squareform (m, 'tov'), v); |
| 152 | +%!assert (squareform (v, 'TOMATRIX'), m); |
| 153 | +%!assert (squareform (v, string ('tomatrix')), m); |
| 154 | +%!assert (squareform (m, string ('tovector')), v); |
144 | 155 |
|
145 | 156 | ## input validations |
146 | | -%!error <squareform: Y or Z must be either numeric or logical.> squareform ("string") |
147 | | -%!error <squareform: Y or Z must be either numeric or logical.> squareform ({1, 2, 3}) |
148 | | -%!error <squareform: Z is not a square matrix.> squareform ([1, 2, 3; 4, 5, 6], "tovector") |
149 | | -%!error <squareform: Z is not a hollow matrix.> squareform (eye (3), "tovector") |
150 | | -%!error <squareform: the numel of Y cannot form a square matrix.> squareform ([1, 2, 3, 4], "tomatrix") |
151 | | -%!error <squareform: invalid METHOD 'to'> squareform ([1, 2, 3], "to") |
152 | | -%!error <squareform: invalid METHOD 'invalid'> squareform ([1, 2, 3], "invalid") |
| 157 | +%!error <squareform: distance input must be either numeric or logical.> ... |
| 158 | +%! squareform ('string') |
| 159 | +%!error <squareform: distance input must be either numeric or logical.> ... |
| 160 | +%! squareform ({1, 2, 3}) |
| 161 | +%!error <squareform: distance input is not a square matrix.> ... |
| 162 | +%! squareform ([1, 2, 3; 4, 5, 6], 'tovector') |
| 163 | +%!error <squareform: distance input is not a hollow matrix.> ... |
| 164 | +%! squareform (eye (3), 'tovector') |
| 165 | +%!error <squareform: second argument must be either a character vector or a string scalar.> ... |
| 166 | +%! squareform ([1, 2, 3; 4, 5, 6], string ({'tomatrix', 'tomatrix'})) |
| 167 | +%!error <squareform: second argument must be either a character vector or a string scalar.> ... |
| 168 | +%! squareform ([1, 2, 3; 4, 5, 6], true) |
| 169 | +%!error <squareform: distance input vector cannot form a square matrix.> ... |
| 170 | +%! squareform ([1, 2, 3, 4], 'tomatrix') |
| 171 | +%!error <squareform: invalid METHOD 'invalid'> squareform ([1, 2, 3], 'invalid') |
153 | 172 |
|
154 | 173 |
|
0 commit comments