Skip to content

Commit d461943

Browse files
committed
squareform: add BISTs, improve docstring and input validation, #417
1 parent 8b2bf64 commit d461943

File tree

1 file changed

+50
-31
lines changed

1 file changed

+50
-31
lines changed

inst/squareform.m

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## Copyright (C) 2015 Carnë Draug <carandraug@octave.org>
22
## Copyright (C) 2026 Andreas Bertsatos <abertsatos@biol.uoa.gr>
3+
## Copyright (C) 2026 Avanish Salunke <avanishsalunke16@gmail.com>
34
##
45
## This file is part of the statistics package for GNU Octave.
56
##
@@ -31,18 +32,18 @@
3132
## @code{pdist} into a distance matrix. It performs the opposite operation
3233
## if input is a matrix.
3334
##
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
3738
## @var{n}. The resulting matrix will be @var{n} by @var{n}.
3839
##
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.
4243
##
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
4647
## @qcode{"tomatrix"} otherwise.
4748
##
4849
## @seealso{pdist}
@@ -53,27 +54,36 @@
5354
if (nargin < 1 || nargin > 2)
5455
print_usage ();
5556
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.");
5758
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.");
5960
endif
6061

6162
if (nargin == 1)
6263
## This is ambiguous when numel (x) == 1, but that's the whole reason
6364
## why the "method" option exists.
6465
if (isvector (x))
65-
method = "tomatrix";
66+
method = 'tomatrix';
6667
else
67-
method = "tovector";
68+
method = 'tovector';
6869
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."));
6979
endif
7080

7181
switch (tolower (method))
7282
case {'tovector', 'tov'}
7383
if (! issquare (x))
74-
error ("squareform: Z is not a square matrix.");
84+
error ("squareform: distance input is not a square matrix.");
7585
elseif (any (diag (x) != 0))
76-
error ("squareform: Z is not a hollow matrix.");
86+
error ("squareform: distance input is not a hollow matrix.");
7787
endif
7888

7989
y = vec (tril (x, -1, "pack"), 2);
@@ -83,7 +93,7 @@
8393
## length (x) = (sy - 1) * (sy / 2)
8494
sy = (1 + sqrt (1 + 8 * numel (x))) / 2;
8595
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.");
8797
endif
8898

8999
y = zeros (sy, class (x));
@@ -103,7 +113,7 @@
103113

104114
%!shared v, m
105115
%! 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];
107117

108118
## make sure that it can go both directions automatically
109119
%!test
@@ -118,12 +128,12 @@
118128
## handle 1 element input properly
119129
%!test
120130
%!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))
123133

124134
## confirm that it respects input class
125135
%!test
126-
%! for c = {@single, @double, @uint8, @uint32, @uint64, @logical}
136+
%! for c = {@single, @double, @uint8, @uint16, @uint32, @uint64, @logical}
127137
%! f = c{1};
128138
%! assert (squareform (f (v)), f (m))
129139
%! assert (squareform (f (m)), f (v))
@@ -137,18 +147,27 @@
137147
%! assert (squareform (m_log), v_log);
138148

139149
## 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);
144155

145156
## 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')
153172

154173

0 commit comments

Comments
 (0)