# HG changeset patch # User Rik # Date 1440706341 25200 # Node ID 16b9ec39ff46a42c28074466a050f3afbca03442 # Parent 44eb1102f8a8d3afba12e7a0ffeca490d67f5be3 Return empty matrix when linspace called with 0 points (bug #45820) * NEWS: Announce change. * data.cc (Flinspace): Verify input N is scalar. Verify inputs BASE, LIMIT are scalar/vectors. Add BIST tests for input validation, complex values, class of output, Matlab compatibility. Clarify documentation about vector inputs. * CMatrix.cc, CRowVector.cc, dMatrix.cc, dRowVector.cc, fCMatrix.cc, fCRowVector.cc, fMatrix.cc, fRowVector.cc: Return empty matrix when N < 1. diff -r 44eb1102f8a8 -r 16b9ec39ff46 NEWS --- a/NEWS Wed Aug 26 16:05:49 2015 -0400 +++ b/NEWS Thu Aug 27 13:12:21 2015 -0700 @@ -22,6 +22,11 @@ ** mkfifo now interprets the MODE argument as an octal, not decimal, integer. This is consistent with the equivalent shell command. + ** linspace now returns an empty matrix if the number of requested points + is 0 or a negative number. This change was made to be compatible with + Matlab releases newer than 2011. In addition, Octave no longer supports + matrix inputs for A or B. + ** The griddata function no longer plots the interpolated mesh if no output argument is requested, instead the vector or array of interpolated values is always returned for Matlab compatibility. diff -r 44eb1102f8a8 -r 16b9ec39ff46 libinterp/corefcn/data.cc --- a/libinterp/corefcn/data.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/libinterp/corefcn/data.cc Thu Aug 27 13:12:21 2015 -0700 @@ -5342,9 +5342,11 @@ than @var{limit}, the elements are stored in decreasing order. If the\n\ number of points is not specified, a value of 100 is used.\n\ \n\ -The @code{linspace} function always returns a row vector if both @var{base}\n\ -and @var{limit} are scalars. If one, or both, of them are column vectors,\n\ -@code{linspace} returns a matrix.\n\ +The @code{linspace} function returns a row vector when both @var{base}\n\ +and @var{limit} are scalars. If one, or both, inputs are vectors, then\n\ +@code{linspace} transforms them to column vectors and returns a matrix where\n\ +each row is an independent sequence between\n\ +@w{@code{@var{base}(@var{row_n}), @var{limit}(@var{row_n})}}.\n\ \n\ For compatibility with @sc{matlab}, return the second argument (@var{limit})\n\ if fewer than two values are requested.\n\ @@ -5372,6 +5374,8 @@ if (arg_3.is_numeric_type () && arg_3.is_empty ()) npoints = 1; + else if (! arg_3.is_scalar_type ()) + error ("linspace: N must be a scalar"); else npoints = arg_3.idx_type_value (); } @@ -5381,7 +5385,14 @@ octave_value arg_1 = args(0); octave_value arg_2 = args(1); - if (arg_1.is_single_type () || arg_2.is_single_type ()) + dim_vector sz1 = arg_1.dims (); + bool isvector1 = sz1.length () == 2 && (sz1(0) == 1 || sz1(1) == 1); + dim_vector sz2 = arg_2.dims (); + bool isvector2 = sz2.length () == 2 && (sz2(0) == 1 || sz2(1) == 1); + + if (! isvector1 || ! isvector2) + error ("linspace: A, B must be scalars or vectors"); + else if (arg_1.is_single_type () || arg_2.is_single_type ()) { if (arg_1.is_complex_type () || arg_2.is_complex_type ()) retval = do_linspace (arg_1, arg_2, npoints); @@ -5413,12 +5424,32 @@ %! assert (size (x2) == [1, 10] && x2(1) == 1 && x2(10) == 2); %! assert (size (x3) == [1, 10] && x3(1) == 1 && x3(10) == -2); -%! ##assert (linspace ([1, 2; 3, 4], 5, 6), linspace (1, 5, 6)) - +## Test complex values +%!test +%! exp = [1+0i, 2-1.25i, 3-2.5i, 4-3.75i, 5-5i]; +%! obs = linspace (1, 5-5i, 5); +%! assert (obs, exp); + +## Test class of output +%!assert (class (linspace (1, 2)), "double") +%!assert (class (linspace (single (1), 2)), "single") +%!assert (class (linspace (1, single (2))), "single") + +## Test obscure Matlab compatibility options %!assert (linspace (0, 1, []), 1) +%!assert (linspace (10, 20, 2), [10 20]) +%!assert (linspace (10, 20, 1), [20]) +%!assert (linspace (10, 20, 0), zeros (1, 0)) +%!assert (linspace (10, 20, -1), zeros (1, 0)) +%!assert (numel (linspace (0, 1, 2+eps)), 2) +%!assert (numel (linspace (0, 1, 2-eps)), 1) %!error linspace () %!error linspace (1, 2, 3, 4) +%!error linspace (1, 2, [3, 4]) +%!error linspace (ones (2,2), 2, 3) +%!error linspace (2, ones (2,2), 3) +%!error linspace (1, [], 3) */ // FIXME: should accept dimensions as separate args for N-d diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/CMatrix.cc --- a/liboctave/array/CMatrix.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/CMatrix.cc Thu Aug 27 13:12:21 2015 -0700 @@ -3999,8 +3999,6 @@ octave_idx_type n) { - if (n < 1) n = 1; - octave_idx_type m = x1.numel (); if (x2.numel () != m) @@ -4009,11 +4007,17 @@ NoAlias retval; + if (n < 1) + { + retval.clear (m, 0); + return retval; + } + retval.clear (m, n); for (octave_idx_type i = 0; i < m; i++) retval(i, 0) = x1(i); - // The last column is not needed while using delta. + // The last column is unused so temporarily store delta there Complex *delta = &retval(0, n-1); for (octave_idx_type i = 0; i < m; i++) delta[i] = (x2(i) - x1(i)) / (n - 1.0); diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/CRowVector.cc --- a/liboctave/array/CRowVector.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/CRowVector.cc Thu Aug 27 13:12:21 2015 -0700 @@ -462,14 +462,19 @@ ComplexRowVector linspace (const Complex& x1, const Complex& x2, octave_idx_type n) { - if (n < 1) n = 1; + NoAlias retval; - NoAlias retval (n); + if (n < 1) + return retval; + else + retval.clear (n); + + retval(0) = x1; Complex delta = (x2 - x1) / (n - 1.0); - retval(0) = x1; for (octave_idx_type i = 1; i < n-1; i++) retval(i) = x1 + static_cast (i)*delta; + retval(n-1) = x2; return retval; diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/dMatrix.cc --- a/liboctave/array/dMatrix.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/dMatrix.cc Thu Aug 27 13:12:21 2015 -0700 @@ -3330,8 +3330,6 @@ octave_idx_type n) { - if (n < 1) n = 1; - octave_idx_type m = x1.numel (); if (x2.numel () != m) @@ -3340,11 +3338,17 @@ NoAlias retval; + if (n < 1) + { + retval.clear (m, 0); + return retval; + } + retval.clear (m, n); for (octave_idx_type i = 0; i < m; i++) retval(i, 0) = x1(i); - // The last column is not needed while using delta. + // The last column is unused so temporarily store delta there double *delta = &retval(0, n-1); for (octave_idx_type i = 0; i < m; i++) delta[i] = (x2(i) - x1(i)) / (n - 1); @@ -3359,6 +3363,7 @@ return retval; } + MS_CMP_OPS (Matrix, double) MS_BOOL_OPS (Matrix, double) diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/dRowVector.cc --- a/liboctave/array/dRowVector.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/dRowVector.cc Thu Aug 27 13:12:21 2015 -0700 @@ -293,14 +293,19 @@ RowVector linspace (double x1, double x2, octave_idx_type n) { - if (n < 1) n = 1; + NoAlias retval; - NoAlias retval (n); + if (n < 1) + return retval; + else + retval.clear (n); + + retval(0) = x1; double delta = (x2 - x1) / (n - 1); - retval(0) = x1; for (octave_idx_type i = 1; i < n-1; i++) retval(i) = x1 + i*delta; + retval(n-1) = x2; return retval; diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/fCMatrix.cc --- a/liboctave/array/fCMatrix.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/fCMatrix.cc Thu Aug 27 13:12:21 2015 -0700 @@ -4019,8 +4019,6 @@ octave_idx_type n) { - if (n < 1) n = 1; - octave_idx_type m = x1.numel (); if (x2.numel () != m) @@ -4029,11 +4027,17 @@ NoAlias retval; + if (n < 1) + { + retval.clear (m, 0); + return retval; + } + retval.clear (m, n); for (octave_idx_type i = 0; i < m; i++) retval(i, 0) = x1(i); - // The last column is not needed while using delta. + // The last column is unused so temporarily store delta there FloatComplex *delta = &retval(0, n-1); for (octave_idx_type i = 0; i < m; i++) delta[i] = (x2(i) - x1(i)) / (n - 1.0f); diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/fCRowVector.cc --- a/liboctave/array/fCRowVector.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/fCRowVector.cc Thu Aug 27 13:12:21 2015 -0700 @@ -463,14 +463,19 @@ FloatComplexRowVector linspace (const FloatComplex& x1, const FloatComplex& x2, octave_idx_type n) { - if (n < 1) n = 1; + NoAlias retval; - NoAlias retval (n); + if (n < 1) + return retval; + else + retval.clear (n); + + retval(0) = x1; FloatComplex delta = (x2 - x1) / (n - 1.0f); - retval(0) = x1; for (octave_idx_type i = 1; i < n-1; i++) retval(i) = x1 + static_cast (i)*delta; + retval(n-1) = x2; return retval; diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/fMatrix.cc --- a/liboctave/array/fMatrix.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/fMatrix.cc Thu Aug 27 13:12:21 2015 -0700 @@ -3335,8 +3335,6 @@ octave_idx_type n) { - if (n < 1) n = 1; - octave_idx_type m = x1.numel (); if (x2.numel () != m) @@ -3345,11 +3343,17 @@ NoAlias retval; + if (n < 1) + { + retval.clear (m, 0); + return retval; + } + retval.clear (m, n); for (octave_idx_type i = 0; i < m; i++) retval(i, 0) = x1(i); - // The last column is not needed while using delta. + // The last column is unused so temporarily store delta there float *delta = &retval(0, n-1); for (octave_idx_type i = 0; i < m; i++) delta[i] = (x2(i) - x1(i)) / (n - 1); diff -r 44eb1102f8a8 -r 16b9ec39ff46 liboctave/array/fRowVector.cc --- a/liboctave/array/fRowVector.cc Wed Aug 26 16:05:49 2015 -0400 +++ b/liboctave/array/fRowVector.cc Thu Aug 27 13:12:21 2015 -0700 @@ -293,14 +293,19 @@ FloatRowVector linspace (float x1, float x2, octave_idx_type n) { - if (n < 1) n = 1; + NoAlias retval; - NoAlias retval (n); + if (n < 1) + return retval; + else + retval.clear (n); + + retval(0) = x1; float delta = (x2 - x1) / (n - 1); - retval(0) = x1; for (octave_idx_type i = 1; i < n-1; i++) retval(i) = x1 + i*delta; + retval(n-1) = x2; return retval;