comparison libinterp/corefcn/data.cc @ 30230:bd02f48ac38f

allow size function to query arbitrary list of dimensions (bug #61098) * data.cc (Fsize): Allow DIM argument to be a vector or for a list of dimensions to be specified as individual arguments. New tests from Kai T. Ohlhus <k.ohlhus@gmail.com>.
author John W. Eaton <jwe@octave.org>
date Wed, 29 Sep 2021 16:22:00 +0900
parents 7d6709900da7
children 81d26e8481a6
comparison
equal deleted inserted replaced
30229:3b3ec2ea46ef 30230:bd02f48ac38f
2654 2654
2655 DEFUN (size, args, nargout, 2655 DEFUN (size, args, nargout,
2656 doc: /* -*- texinfo -*- 2656 doc: /* -*- texinfo -*-
2657 @deftypefn {} {@var{sz} =} size (@var{a}) 2657 @deftypefn {} {@var{sz} =} size (@var{a})
2658 @deftypefnx {} {@var{dim_sz} =} size (@var{a}, @var{dim}) 2658 @deftypefnx {} {@var{dim_sz} =} size (@var{a}, @var{dim})
2659 @deftypefnx {} {@var{dim_sz} =} size (@var{a}, @var{d1}, @var{d2}, @dots{})
2659 @deftypefnx {} {[@var{rows}, @var{cols}, @dots{}, @var{dim_N_sz}] =} size (@dots{}) 2660 @deftypefnx {} {[@var{rows}, @var{cols}, @dots{}, @var{dim_N_sz}] =} size (@dots{})
2660 Return a row vector with the size (number of elements) of each dimension for 2661 Return a row vector with the size (number of elements) of each dimension for
2661 the object @var{a}. 2662 the object @var{a}.
2662 2663
2663 When given a second argument, @var{dim}, return the size of the corresponding 2664 When given a second argument, @var{dim}, return the size of the corresponding
2664 dimension. 2665 dimension. If @var{dim} is a vector, return each of the corresponding
2666 dimensions. Multiple dimensions may also be specified as separate arguments.
2665 2667
2666 With a single output argument, @code{size} returns a row vector. When called 2668 With a single output argument, @code{size} returns a row vector. When called
2667 with multiple output arguments, @code{size} returns the size of dimension N 2669 with multiple output arguments, @code{size} returns the size of dimension N
2668 in the Nth argument. The number of rows, dimension 1, is returned in the 2670 in the Nth argument. The number of rows, dimension 1, is returned in the
2669 first argument, the number of columns, dimension 2, is returned in the 2671 first argument, the number of columns, dimension 2, is returned in the
2710 @end example 2712 @end example
2711 2713
2712 @seealso{numel, ndims, length, rows, columns, size_equal, common_size} 2714 @seealso{numel, ndims, length, rows, columns, size_equal, common_size}
2713 @end deftypefn */) 2715 @end deftypefn */)
2714 { 2716 {
2715 octave_value_list retval;
2716
2717 int nargin = args.length (); 2717 int nargin = args.length ();
2718 2718
2719 if (nargin == 0)
2720 print_usage ();
2721
2722 // For compatibility with Matlab, size returns dimensions as doubles.
2723
2724 Matrix m;
2725
2726 dim_vector dimensions = args(0).dims ();
2727 int ndims = dimensions.ndims ();
2728
2719 if (nargin == 1) 2729 if (nargin == 1)
2720 { 2730 {
2721 const dim_vector dimensions = args(0).dims ();
2722
2723 if (nargout > 1) 2731 if (nargout > 1)
2724 { 2732 {
2725 const dim_vector rdims = dimensions.redim (nargout); 2733 dimensions = dimensions.redim (nargout);
2726 retval.resize (nargout); 2734 ndims = dimensions.ndims ();
2727 for (int i = 0; i < nargout; i++) 2735 }
2728 retval(i) = rdims(i); 2736
2737 m.resize (1, ndims);
2738
2739 for (octave_idx_type i = 0; i < ndims; i++)
2740 m(i) = dimensions(i);
2741 }
2742 else
2743 {
2744 Array<octave_idx_type> query_dims;
2745
2746 if (nargin > 2)
2747 {
2748 query_dims.resize (dim_vector (1, nargin-1));
2749
2750 for (octave_idx_type i = 0; i < nargin-1; i++)
2751 query_dims(i) = args(i+1).idx_type_value (true);
2729 } 2752 }
2730 else 2753 else
2754 query_dims = args(1).octave_idx_type_vector_value (true);
2755
2756 if (nargout > 1 && nargout != query_dims.numel ())
2757 error ("size: nargout > 1 but does not match number of requested dimensions");
2758
2759 octave_idx_type nidx = query_dims.numel ();
2760
2761 m.resize (1, nidx);
2762
2763 for (octave_idx_type i = 0; i < nidx; i++)
2731 { 2764 {
2732 int ndims = dimensions.ndims (); 2765 octave_idx_type nd = query_dims.xelem (i);
2733 2766
2734 Matrix m (1, ndims); 2767 if (nd < 1)
2735 2768 error ("size: requested dimension DIM (= %"
2736 for (int i = 0; i < ndims; i++) 2769 OCTAVE_IDX_TYPE_FORMAT ") out of range", nd);
2737 m.xelem (i) = dimensions(i); 2770
2738 2771 m(i) = nd <= ndims ? dimensions (nd-1) : 1;
2739 retval(0) = m;
2740 } 2772 }
2741 } 2773 }
2742 else if (nargin == 2 && nargout < 2) 2774
2743 { 2775 if (nargout > 1)
2744 if (! args(1).is_real_scalar ()) 2776 {
2745 error ("size: DIM must be a positive integer"); 2777 octave_value_list retval (nargout);
2746 2778
2747 octave_idx_type nd = args(1).idx_type_value (); 2779 for (octave_idx_type i = 0; i < nargout; i++)
2748 2780 retval(i) = m(i);
2749 const dim_vector dv = args(0).dims (); 2781
2750 2782 return retval;
2751 if (nd < 1) 2783 }
2752 error ("size: requested dimension DIM (= %" OCTAVE_IDX_TYPE_FORMAT ") " 2784
2753 "out of range", nd); 2785 return ovl (m);
2754 2786 }
2755 if (nd <= dv.ndims ()) 2787
2756 retval(0) = dv(nd-1); 2788 /*
2757 else 2789 ## Plain call
2758 retval(0) = 1; 2790
2759 } 2791 %!assert (size ([1, 2; 3, 4; 5, 6]), [3, 2])
2760 else 2792
2761 print_usage (); 2793 %!test
2762 2794 %! [nr, nc] = size ([1, 2; 3, 4; 5, 6]);
2763 return retval; 2795 %! assert (nr, 3)
2764 } 2796 %! assert (nc, 2)
2797
2798 %!test
2799 %! [nr, remainder] = size (ones (2, 3, 4, 5));
2800 %! assert (nr, 2)
2801 %! assert (remainder, 60)
2802
2803 ## Call for single existing dimension
2804
2805 %!assert (size ([1, 2; 3, 4; 5, 6], 1), 3)
2806 %!assert (size ([1, 2; 3, 4; 5, 6], 2), 2)
2807
2808 ## Call for single non-existing dimension
2809
2810 %!assert (size ([1, 2; 3, 4; 5, 6], 3), 1)
2811 %!assert (size ([1, 2; 3, 4; 5, 6], 4), 1)
2812
2813 ## Call for more than existing dimensions
2814
2815 %!test
2816 %! [nr, nc, e1, e2] = size ([1, 2; 3, 4; 5, 6]);
2817 %! assert (nr, 3)
2818 %! assert (nc, 2)
2819 %! assert (e1, 1)
2820 %! assert (e2, 1)
2821
2822 ## Call for two arbitrary dimensions
2823
2824 %!test
2825 %! dim = [3, 2, 1, 1, 1];
2826 %! for i = 1:5
2827 %! for j = 1:5
2828 %! assert (size ([1, 2; 3, 4; 5, 6], i, j), [dim(i), dim(j)])
2829 %! assert (size ([1, 2; 3, 4; 5, 6], [i, j]), [dim(i), dim(j)])
2830 %! [a, b] = size ([1, 2; 3, 4; 5, 6], i, j);
2831 %! assert (a, dim(i));
2832 %! assert (b, dim(j));
2833 %! [a, b] = size ([1, 2; 3, 4; 5, 6], [i, j]);
2834 %! assert (a, dim(i));
2835 %! assert (b, dim(j));
2836 %! end
2837 %! end
2838
2839 ## Call for three arbitrary dimensions
2840
2841 %!test
2842 %! dim = [3, 2, 1, 1, 1];
2843 %! for i = 1:5
2844 %! for j = 1:5
2845 %! for k = 1:5
2846 %! assert (size ([1, 2; 3, 4; 5, 6], i, j, k), [dim(i), dim(j), dim(k)])
2847 %! assert (size ([1, 2; 3, 4; 5, 6], [i, j, k]), [dim(i), dim(j), dim(k)])
2848 %! [a, b, c] = size ([1, 2; 3, 4; 5, 6], i, j, k);
2849 %! assert (a, dim(i));
2850 %! assert (b, dim(j));
2851 %! assert (c, dim(k));
2852 %! [a, b, c] = size ([1, 2; 3, 4; 5, 6], [i, j, k]);
2853 %! assert (a, dim(i));
2854 %! assert (b, dim(j));
2855 %! assert (c, dim(k));
2856 %! end
2857 %! end
2858 %! end
2859
2860 %!error <does not match number of requested dimensions>
2861 %! [a, b, c] = size ([1, 2; 3, 4; 5, 6], 1:4)
2862 */
2765 2863
2766 DEFUN (size_equal, args, , 2864 DEFUN (size_equal, args, ,
2767 doc: /* -*- texinfo -*- 2865 doc: /* -*- texinfo -*-
2768 @deftypefn {} {} size_equal (@var{a}, @var{b}, @dots{}) 2866 @deftypefn {} {} size_equal (@var{a}, @var{b}, @dots{})
2769 Return true if the dimensions of all arguments agree. 2867 Return true if the dimensions of all arguments agree.