changeset 16370:7ce21619a4b9

min Matlab compatibility issue (bug #33530) * max.cc (do_minmax_red_op<charNDArray>, do_minmax_bin_op<charNDArray>): New specializations. (do_minmax_body): Handle char arrays. New tests. * chNDArray.h, chNDArray.cc (charNDArray::min, charNDArray::max): New functions.
author Axel Mathéi <axel.mathei@gmail.com>
date Tue, 26 Mar 2013 10:43:42 -0400
parents 29e03b0e7e8d
children effe80808118
files libinterp/corefcn/max.cc liboctave/array/chNDArray.cc liboctave/array/chNDArray.h
diffstat 3 files changed, 189 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/max.cc	Tue Mar 26 09:50:20 2013 -0400
+++ b/libinterp/corefcn/max.cc	Tue Mar 26 10:43:42 2013 -0400
@@ -74,6 +74,47 @@
   return retval;
 }
 
+// Matlab returns double arrays for min/max operations on character
+// arrays, so we specialize here to get that behavior.  Other possible
+// solutions are to convert the argument to double here and call the
+// code for double, but that could waste memory, or to have the
+// underlying charNDArray::min/max functions return NDArray instead of
+// charNDArray, but that is inconsistent with the way other min/max
+// functions work.
+
+template <>
+octave_value_list
+do_minmax_red_op<charNDArray> (const octave_value& arg,
+                               int nargout, int dim, bool ismin)
+{
+  octave_value_list retval;
+  charNDArray array = octave_value_extract<charNDArray> (arg);
+
+  if (error_state)
+    return retval;
+
+  if (nargout == 2)
+    {
+      retval.resize (2);
+      Array<octave_idx_type> idx;
+      if (ismin)
+        retval(0) = NDArray (array.min (idx, dim));
+      else
+        retval(0) = NDArray (array.max (idx, dim));
+
+      retval(1) = octave_value (idx, true, true);
+    }
+  else
+    {
+      if (ismin)
+        retval(0) = NDArray (array.min (dim));
+      else
+        retval(0) = NDArray (array.max (dim));
+    }
+
+  return retval;
+}
+
 // Specialization for bool arrays.
 template <>
 octave_value_list
@@ -154,6 +195,61 @@
   return retval;
 }
 
+// Matlab returns double arrays for min/max operations on character
+// arrays, so we specialize here to get that behavior.  Other possible
+// solutions are to convert the arguments to double here and call the
+// code for double, but that could waste a lot of memory, or to have the
+// underlying charNDArray::min/max functions return NDArray instead of
+// charNDArray, but that is inconsistent with the way other min/max
+// functions work.
+
+template <>
+octave_value
+do_minmax_bin_op<charNDArray> (const octave_value& argx,
+                               const octave_value& argy, bool ismin)
+{
+  octave_value retval;
+
+  if (argx.is_scalar_type () == 1)
+    {
+      char x = octave_value_extract<char> (argx);
+      charNDArray y = octave_value_extract<charNDArray> (argy);
+
+      if (error_state)
+        ;
+      else if (ismin)
+        retval = NDArray (min (x, y));
+      else
+        retval = NDArray (max (x, y));
+    }
+  else if (argy.is_scalar_type () == 1)
+    {
+      charNDArray x = octave_value_extract<charNDArray> (argx);
+      char y = octave_value_extract<char> (argy);
+
+      if (error_state)
+        ;
+      else if (ismin)
+        retval = NDArray (min (x, y));
+      else
+        retval = NDArray (max (x, y));
+    }
+  else
+    {
+      charNDArray x = octave_value_extract<charNDArray> (argx);
+      charNDArray y = octave_value_extract<charNDArray> (argy);
+
+      if (error_state)
+        ;
+      else if (ismin)
+        retval = NDArray (min (x, y));
+      else
+        retval = NDArray (max (x, y));
+    }
+
+  return retval;
+}
+
 static octave_value_list
 do_minmax_body (const octave_value_list& args,
                 int nargout, bool ismin)
@@ -227,6 +323,9 @@
         case btyp_float_complex:
           retval = do_minmax_red_op<FloatComplexNDArray> (arg, nargout, dim, ismin);
           break;
+        case btyp_char:
+          retval = do_minmax_red_op<charNDArray> (arg, nargout, dim, ismin);
+          break;
 #define MAKE_INT_BRANCH(X) \
         case btyp_ ## X: \
           retval = do_minmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \
@@ -251,7 +350,11 @@
     {
       octave_value argx = args(0), argy = args(1);
       builtin_type_t xtyp = argx.builtin_type (), ytyp = argy.builtin_type ();
-      builtin_type_t rtyp = btyp_mixed_numeric (xtyp, ytyp);
+      builtin_type_t rtyp;
+      if (xtyp == btyp_char && ytyp == btyp_char)
+        rtyp = btyp_char;
+      else
+        rtyp = btyp_mixed_numeric (xtyp, ytyp);
 
       switch (rtyp)
         {
@@ -281,6 +384,9 @@
         case btyp_float_complex:
           retval = do_minmax_bin_op<FloatComplexNDArray> (argx, argy, ismin);
           break;
+        case btyp_char:
+          retval = do_minmax_bin_op<charNDArray> (argx, argy, ismin);
+          break;
 #define MAKE_INT_BRANCH(X) \
         case btyp_ ## X: \
           retval = do_minmax_bin_op<X ## NDArray> (argx, argy, ismin); \
@@ -361,6 +467,10 @@
 %!assert (min ([1, 4, 2, 3]), 1)
 %!assert (min ([1; -10; 5; -2]), -10)
 %!assert (min ([4, i; -2, 2]), [-2, i])
+%!assert (min (char(42)), 42)
+%!assert (min (char(21), char(3)), 3)
+%!assert (min([char(21), char(3)]), 3)
+%!assert (min([char(100) char(3)], [char(42) char(42)]), [42 3])
 
 %!test
 %! x = reshape (1:8, [2,2,2]);
--- a/liboctave/array/chNDArray.cc	Tue Mar 26 09:50:20 2013 -0400
+++ b/liboctave/array/chNDArray.cc	Tue Mar 26 10:43:42 2013 -0400
@@ -92,6 +92,30 @@
   return *this;
 }
 
+charNDArray
+charNDArray::max (int dim) const
+{
+  return do_mx_minmax_op<char> (*this, dim, mx_inline_max);
+}
+
+charNDArray
+charNDArray::max (Array<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_minmax_op<char> (*this, idx_arg, dim, mx_inline_max);
+}
+
+charNDArray
+charNDArray::min (int dim) const
+{
+  return do_mx_minmax_op<char> (*this, dim, mx_inline_min);
+}
+
+charNDArray
+charNDArray::min (Array<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_minmax_op<char> (*this, idx_arg, dim, mx_inline_min);
+}
+
 charNDArray&
 charNDArray::insert (const charNDArray& a, octave_idx_type r, octave_idx_type c)
 {
@@ -139,6 +163,48 @@
   return Array<char>::diag (m, n);
 }
 
+charNDArray
+min (char d, const charNDArray& m)
+{
+  return do_sm_binary_op<charNDArray::element_type, char, charNDArray::element_type>
+           (d, m, mx_inline_xmin);
+}
+
+charNDArray
+min (const charNDArray& m, char d)
+{
+  return do_ms_binary_op<charNDArray::element_type, charNDArray::element_type, char>
+           (m, d, mx_inline_xmin);
+}
+
+charNDArray
+min (const charNDArray& a, const charNDArray& b)
+{
+  return do_mm_binary_op<charNDArray::element_type, charNDArray::element_type, charNDArray::element_type>
+           (a, b, mx_inline_xmin, mx_inline_xmin, mx_inline_xmin, "min");
+}
+
+charNDArray
+max (char d, const charNDArray& m)
+{
+  return do_sm_binary_op<charNDArray::element_type, char, charNDArray::element_type>
+           (d, m, mx_inline_xmax);
+}
+
+charNDArray
+max (const charNDArray& m, char d)
+{
+  return do_ms_binary_op<charNDArray::element_type, charNDArray::element_type, char>
+           (m, d, mx_inline_xmax);
+}
+
+charNDArray
+max (const charNDArray& a, const charNDArray& b)
+{
+  return do_mm_binary_op<charNDArray::element_type, charNDArray::element_type, charNDArray::element_type>
+           (a, b, mx_inline_xmax, mx_inline_xmax, mx_inline_xmax, "max");
+}
+
 NDS_CMP_OPS (charNDArray, char)
 NDS_BOOL_OPS (charNDArray, char)
 
--- a/liboctave/array/chNDArray.h	Tue Mar 26 09:50:20 2013 -0400
+++ b/liboctave/array/chNDArray.h	Tue Mar 26 10:43:42 2013 -0400
@@ -73,6 +73,11 @@
   charNDArray concat (const charNDArray& rb, const Array<octave_idx_type>& ra_idx);
   charNDArray concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx);
 
+  charNDArray max (int dim = -1) const;
+  charNDArray max (Array<octave_idx_type>& index, int dim = -1) const;
+  charNDArray min (int dim = -1) const;
+  charNDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+
   charNDArray& insert (const charNDArray& a, octave_idx_type r, octave_idx_type c);
   charNDArray& insert (const charNDArray& a, const Array<octave_idx_type>& ra_idx);
 
@@ -97,6 +102,13 @@
   charNDArray diag (octave_idx_type m, octave_idx_type n) const;
 };
 
+extern OCTAVE_API charNDArray min (char d, const charNDArray& m);
+extern OCTAVE_API charNDArray min (const charNDArray& m, char d);
+extern OCTAVE_API charNDArray min (const charNDArray& a, const charNDArray& b);
+extern OCTAVE_API charNDArray max (char d, const charNDArray& m);
+extern OCTAVE_API charNDArray max (const charNDArray& m, char d);
+extern OCTAVE_API charNDArray max (const charNDArray& a, const charNDArray& b);
+
 NDS_CMP_OP_DECLS (charNDArray, char, OCTAVE_API)
 NDS_BOOL_OP_DECLS (charNDArray, char, OCTAVE_API)