changeset 33007:19973af3ac42 bytecode-interpreter

maint: merge default to bytecode-interpreter
author John W. Eaton <jwe@octave.org>
date Sun, 11 Feb 2024 09:40:35 -0500
parents f2ed83c748cf (current diff) 3a0d7c21384c (diff)
children 1220b63eea0e
files
diffstat 3 files changed, 55 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/documentation.cc	Fri Feb 09 21:47:16 2024 -0500
+++ b/libgui/src/documentation.cc	Sun Feb 11 09:40:35 2024 -0500
@@ -1103,9 +1103,14 @@
 documentation_browser::handle_index_clicked (const QUrl& url, const QString&)
 {
   if (url.scheme () == "qthelp")
-    setSource (url);
+    {
+      // URL wihtin the help system, replace #XREF by #index-
+      QString u = url.toString ();
+      u.replace ("#XREF", "#index-");
+      setSource (QUrl (u));
+    }
   else
-    QDesktopServices::openUrl (url);
+    QDesktopServices::openUrl (url);  // URL outside help system
 }
 
 void
--- a/libinterp/corefcn/perms.cc	Fri Feb 09 21:47:16 2024 -0500
+++ b/libinterp/corefcn/perms.cc	Sun Feb 11 09:40:35 2024 -0500
@@ -28,6 +28,7 @@
 #endif
 
 #include <algorithm>
+#include <numeric>
 
 #include "defun.h"
 #include "error.h"
@@ -48,119 +49,83 @@
 //
 // Use C++ template to cater for the different octave array classes.
 //
-template <typename T>
-static inline Array<T>
-GetPerms (const Array<T>& ar_in, bool uniq_v, bool do_sort = false)
-{
-  octave_idx_type m = ar_in.numel ();
-  double nr = Factorial (m);
-
-  // Setup index vector filled from 0..m-1
-  OCTAVE_LOCAL_BUFFER (int, myvidx, m);
-  for (int i = 0; i < m; i++)
-    myvidx[i] = i;
-
-  // Interim array to sort ar_in for octave sort order and to implement
-  // "unique".
-  Array<T> ar (ar_in);
-
-  if (uniq_v)
-    {
-      ar = ar.sort (ar.dims () (1) > ar.dims () (0) ? 1 : 0, ASCENDING);
-      const T *Ar = ar.data ();
-      int ctr = 0;
-      int N_el = 1;
 
-      // Number of same elements where we need to remove permutations
-      // Number of unique permutations is n! / (n_el1! * n_el2! * ...)
-      for (octave_idx_type i = 0; i < m - 1; i++)
-        {
-          myvidx[i] = ctr;
-          if (Ar[i + 1] != Ar[i])
-            {
-              nr /= Factorial (N_el);
-              ctr = i + 1;  // index of next different element
-              N_el = 1;
-            }
-          else
-            N_el++;
-        }
-      myvidx[m - 1] = ctr;
-      nr /= Factorial (N_el);
-    }
-  else if (do_sort)
-    {
-      ar = ar.sort (ar.dims () (1) > ar.dims () (0) ? 1 : 0, ASCENDING);
-    }
+// FIXME: To allow comparison between all supported template types, we need
+// to use either "if constexpr" (supported in C++17) or template specialisation
+// (supported in C++11).  Currently (2024), Octave stipulates the usage of
+// C++11, so the (slightly more complex) template specialization is used.
+// Once Octave moves to C++17 or beyond, the following code snippet is
+// preferrable and the comparison templates can be removed:
+// bool isequal;
+// if constexpr (std::is_same<T, octave_value>::value)
+//   isEqual = Ar[i].is_equal (Ar[j]);
+// else
+//   isEqual =  (Ar[i] == Ar[j]);
 
-  // Sort vector indices for inverse lexicographic order later.
-  std::sort (myvidx, myvidx + m, std::greater<int> ());
-
-  const T *Ar = ar.data ();
-
-  // Set up result array
-  octave_idx_type n = static_cast<octave_idx_type> (nr);
-  Array<T> res (dim_vector (n, m));
-  T *Res = res.rwdata ();
-
-  // Do the actual job
-  octave_idx_type i = 0;
-  std::sort (myvidx, myvidx + m, std::greater<int> ());
-  do
-    {
-      for (octave_idx_type j = 0; j < m; j++)
-        Res[i + j * n] = Ar[myvidx[j]];
-      i++;
-    }
-  while (std::next_permutation (myvidx, myvidx + m, std::greater<int> ()));
-
-  return res;
+template <typename T>
+bool is_equal_T (T a, T b)
+{
+  return a == b;
 }
 
-// Template for non-numerical types (e.g. Cell) without sorting.
-// The C++ compiler complains as the provided type octave_value does not
-// support the test of equality via '==' in the above template.
+template <>
+bool is_equal_T<octave_value> (octave_value a, octave_value b)
+{
+  return a.is_equal (b);
+}
 
 template <typename T>
 static inline Array<T>
-GetPermsNoSort (const Array<T>& ar_in, bool uniq_v = false)
+GetPerms (const Array<T>& ar_in, bool uniq_v = false)
 {
   octave_idx_type m = ar_in.numel ();
-  double nr = Factorial (m);
+  double nr;  // number of rows of resulting array
 
   // Setup index vector filled from 0..m-1
-  OCTAVE_LOCAL_BUFFER (int, myvidx, m);
-  for (int i = 0; i < m; i++)
-    myvidx[i] = i;
+  OCTAVE_LOCAL_BUFFER (octave_idx_type, myvidx, m);
+  std::iota (&myvidx[0], &myvidx[m], 0);
 
   const T *Ar = ar_in.data ();
 
   if (uniq_v)
     {
-      // Mutual Comparison using is_equal to detect duplicated values
-      int N_el = 1;
+      // Mutual Comparison is used to detect duplicated values.
+      // Using sort would be possible for numerical values and be of
+      // O(n*log (n)) complexity instead of O(n*(n -1) / 2).  But sort
+      // is not supported for the octave_value container (structs/cells).
+      // Moreover, sort requires overhead for creating, filling, and sorting
+      // the intermediate array which would need to be post-processed.
+      // In practice, and because n must be very small, mutual comparison is
+      // typically faster and consumes less memory.
+
+      octave_idx_type N_el = 1;
+      double denom = 1.0;
       // Number of unique permutations is n! / (n_el1! * n_el2! * ...)
       for (octave_idx_type i = 0; i < m - 1; i++)
         {
           for (octave_idx_type j = i + 1; j < m; j++)
             {
-              if (myvidx[j] > myvidx[i] && Ar[i].is_equal (Ar[j]))
+              bool isequal = is_equal_T<T>(Ar[i], Ar[j]);
+              if (myvidx[j] > myvidx[i] && isequal)
                 {
                   myvidx[j] = myvidx[i];  // not yet processed...
                   N_el++;
                 }
               else
                 {
-                  nr /= Factorial (N_el);
+                  denom *= Factorial (N_el);
                   N_el = 1;
                 }
             }
         }
-      nr /= Factorial (N_el);
+      denom *= Factorial (N_el);
+      nr = Factorial (m) / denom;
     }
+  else
+    nr = Factorial (m);
 
   // Sort vector indices for inverse lexicographic order later.
-  std::sort (myvidx, myvidx + m, std::greater<int> ());
+  std::sort (myvidx, myvidx + m, std::greater<octave_idx_type> ());
 
   // Set up result array
   octave_idx_type n = static_cast<octave_idx_type> (nr);
@@ -259,8 +224,8 @@
          || args (0).iscell () || args (0).is_scalar_type ()
          || args (0).isstruct ()))
     {
-      error ("perms: INPUT must be a matrix, a range, a cell array, "
-             "a struct or a scalar.");
+      error ("perms: V must be a matrix, range, cell array, "
+             "struct, or a scalar.");
     }
 
   std::string clname = args (0).class_name ();
@@ -291,7 +256,7 @@
   else if (clname == "uint64")
     retval = GetPerms<octave_uint64> (args (0).uint64_array_value (), uniq_v);
   else if (clname == "cell")
-    retval = GetPermsNoSort<octave_value> (args (0).cell_value (), uniq_v);
+    retval = GetPerms<octave_value> (args (0).cell_value (), uniq_v);
   else if (clname == "struct")
     {
       const octave_map map_in (args (0).map_value ());
@@ -312,7 +277,7 @@
             {
               for (octave_idx_type i = 0; i < fn.numel (); i++)
                 {
-                  out.assign (fn (i), GetPermsNoSort<octave_value>
+                  out.assign (fn (i), GetPerms<octave_value>
                                       (map_in.contents (fn (i)), uniq_v));
                 }
             }
--- a/scripts/specfun/betaln.m	Fri Feb 09 21:47:16 2024 -0500
+++ b/scripts/specfun/betaln.m	Sun Feb 11 09:40:35 2024 -0500
@@ -56,8 +56,6 @@
 
   if (! isreal (a) || ! isreal (b))
     error ("betaln: A and B must be real");
-  elseif (! size_equal (a, b) && numel (a) != 1 && numel (b) != 1)
-    error ("betaln: A and B must have consistent sizes");
   endif
 
   lnb = gammaln (a) + gammaln (b) - gammaln (a + b);
@@ -72,6 +70,3 @@
 %!error <Invalid call> betaln (1)
 %!error <A and B must be real> betaln (1i, 2)
 %!error <A and B must be real> betaln (2, 1i)
-%!error <A and B must have consistent sizes> betaln ([1 2], [1 2 3])
-%!error <A and B must have consistent sizes> betaln ([1 2 3], [1 2])
-%!error <A and B must have consistent sizes> betaln ([1 2 3], [1 2 3]')