changeset 32929:8893636d43a5 bytecode-interpreter

maint: Merge default to bytecode-interpreter
author Arun Giridhar <arungiridhar@gmail.com>
date Sun, 04 Feb 2024 14:54:11 -0500
parents 000cb78b35fc (current diff) de39818dca5e (diff)
children da8fda0b7dd8
files
diffstat 7 files changed, 66 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS.10.md	Sat Feb 03 15:35:52 2024 +0100
+++ b/etc/NEWS.10.md	Sun Feb 04 14:54:11 2024 -0500
@@ -15,6 +15,8 @@
   * `--no-init-site` : Don't read site-wide configuration files at startup.
   * `--no-init-all` : Don't read any configuration files at startup.
 
+- `nchoosek` algorithm is now ~2x faster and provides greater precision. 
+
 ### Graphical User Interface
 
 ### Graphics backend
--- a/libgui/src/m-editor/file-editor-interface.h	Sat Feb 03 15:35:52 2024 +0100
+++ b/libgui/src/m-editor/file-editor-interface.h	Sun Feb 04 14:54:11 2024 -0500
@@ -71,7 +71,7 @@
 
   virtual void empty_script (bool, bool) = 0;
 
-  virtual void restore_session () = 0;
+  virtual void restore_session (bool) = 0;
 
   virtual void enable_menu_shortcuts (bool enable) = 0;
 
--- a/libgui/src/m-editor/file-editor.cc	Sat Feb 03 15:35:52 2024 +0100
+++ b/libgui/src/m-editor/file-editor.cc	Sun Feb 04 14:54:11 2024 -0500
@@ -114,7 +114,7 @@
 
   m_find_dialog = nullptr;
 
-  m_closed = false;
+  m_closed = true;
   m_no_focus = false;
   m_editor_ready = false;
 
@@ -324,8 +324,12 @@
 }
 
 void
-file_editor::restore_session ()
+file_editor::restore_session (bool visible)
 {
+
+  if (! visible)
+    return;
+
   gui_settings settings;
 
   //restore previous session
@@ -1580,7 +1584,7 @@
     {
       m_closed = false;
 
-      restore_session ();
+      restore_session (visible);
     }
 
   empty_script (false, visible);
--- a/libgui/src/m-editor/file-editor.h	Sat Feb 03 15:35:52 2024 +0100
+++ b/libgui/src/m-editor/file-editor.h	Sun Feb 04 14:54:11 2024 -0500
@@ -124,7 +124,7 @@
 
   void check_actions ();
   void empty_script (bool startup, bool visible);
-  void restore_session ();
+  void restore_session (bool visible = true);
 
 signals:
 
--- a/libgui/src/main-window.cc	Sat Feb 03 15:35:52 2024 +0100
+++ b/libgui/src/main-window.cc	Sun Feb 04 14:54:11 2024 -0500
@@ -1836,7 +1836,10 @@
       // This can not be done when the editor is created because all functions
       // must be known for the lexer's auto completion information
       m_editor_window->empty_script (true, false);
-      m_editor_window->restore_session ();
+      bool ed_visible =
+        settings.value (dw_is_visible.settings_key ().arg (m_editor_window->objectName ()),
+                        dw_is_visible.def ()).toBool ();
+      m_editor_window->restore_session (ed_visible);
 #endif
     }
 
--- a/scripts/linear-algebra/logm.m	Sat Feb 03 15:35:52 2024 +0100
+++ b/scripts/linear-algebra/logm.m	Sun Feb 04 14:54:11 2024 -0500
@@ -197,7 +197,7 @@
 %!      -1.9769, -1.0922, -0.5831];
 %! if (__have_feature__ ("LLVM_LIBCXX"))
 %!   ## The math libraries in libc++ seem to require larger tolerances
-%!   tol = 60*eps;
+%!   tol = 65*eps;
 %! else
 %!   tol = 40*eps;
 %! endif
--- a/scripts/specfun/nchoosek.m	Sat Feb 03 15:35:52 2024 +0100
+++ b/scripts/specfun/nchoosek.m	Sun Feb 04 14:54:11 2024 -0500
@@ -112,48 +112,53 @@
   n = numel (v);
 
   if (n == 1 && isnumeric (v))
-    ## Improve precision over direct call to prod().
-    ## Steps: 1) Make a list of integers for numerator and denominator,
-    ## 2) filter out common factors, 3) multiply what remains.
-    k = min (k, v-k);
-
-    if (isinteger (v) || isinteger (k))
-      numer = (v-k+1):v;
-      denom = (1:k);
+    ## Compute number of combinations rather than actual set combinations.
+    try
+      ## Use subtraction operation to validate combining integer data types
+      ## and for type propagation rules between integer and floating point.
+      k = min (k, v-k);
+    catch
+      error ("nchoosek: incompatible input types for N (%s), K (%s)", ...
+             class (v), class (k));
+    end_try_catch
+    is_int = isinteger (k);
+    if (is_int)
+      imax = intmax (k);
     else
-      ## For a ~25% performance boost, multiply values pairwise so there
-      ## are fewer elements in do/until loop which is the slow part.
-      ## Since Odd*Even is guaranteed to be Even, also take out a factor
-      ## of 2 from numerator and denominator.
-      if (rem (k, 2))  # k is odd
-        numer = [((v-k+1:v-(k+1)/2) .* (v-1:-1:v-(k-1)/2)) / 2, v];
-        denom = [((1:(k-1)/2) .* (k-1:-1:(k+1)/2)) / 2, k];
-      else             # k is even
-        numer = ((v-k+1:v-k/2) .* (v:-1:v-k/2+1)) / 2;
-        denom = ((1:k/2) .* (k:-1:k/2+1)) / 2;
-      endif
+      imax = flintmax (k);
     endif
-
-    ## Remove common factors from numerator and denominator
-    do
-      for i = numel (denom):-1:1
-        factors = gcd (denom(i), numer);
-        [f, j] = max (factors);
-        denom(i) /= f;
-        numer(j) /= f;
-      endfor
-      denom = denom(denom > 1);
-      numer = numer(numer > 1);
-    until (isempty (denom))
-
-    C = prod (numer, "native");
-    if (isfloat (C) && C > flintmax (C))
+    C = 1;
+    for i = 1:k
+      if (C * (v - k + i) >= imax)
+        ## Avoid overflow / precision loss by determining the smallest
+        ## possible factor of (C * (n-k+i)) and i via the gcd.
+        ## Note that by design in each iteration
+        ##   1) C will always increase (factor is always > 1).
+        ##   2) C will always be a whole number.
+        ## Therefore, using the gcd will always provide the best possible
+        ## solution until saturation / has the least precision loss.
+        g1 = gcd (C, i);
+        g2 = gcd (v - k + i, i/g1);
+        C /= g1;
+        C *= (v - k + i)/g2;
+        if (is_int && (C == imax))
+          break;  # Stop here; saturation reached.
+        endif
+        C /= i/(g1 * g2);
+      else
+        C *= (v - k + i);
+        C /= i;
+      endif
+    endfor
+    if (! is_int && C > imax)
       warning ("Octave:nchoosek:large-output-float", ...
                "nchoosek: possible loss of precision");
-    elseif (isinteger (C) && C == intmax (C))
+    elseif (is_int && C == imax)
       warning ("Octave:nchoosek:large-output-integer", ...
                "nchoosek: result may have saturated at intmax");
     endif
+
+  ## Compute actual set combinations
   elseif (k == 0)
     C = v(zeros (1, 0));  # Return 1x0 object for Matlab compatibility
   elseif (k == 1)
@@ -283,6 +288,15 @@
 %! assert (x, uint8 (252));
 %! assert (class (x), "uint8");
 
+## Test combining rules for integers and floating point
+%!test
+%! x = nchoosek (uint8 (10), single (5));
+%! assert (x, uint8 (252));
+
+%!test
+%! x = nchoosek (double (10), single (5));
+%! assert (x, single (252));
+
 %!test <*63538>
 %! x = nchoosek ([1:3]', 2);
 %! assert (x, [1 2; 1 3; 2 3]);
@@ -299,6 +313,7 @@
 %!error <N must be a non-negative integer .= K> nchoosek (100, 145)
 %!error <N must be a non-negative integer .= K> nchoosek (-100, 45)
 %!error <N must be a non-negative integer .= K> nchoosek (100.5, 45)
+%!error <incompatible input types> nchoosek (uint8 (15), uint16 (5))
 %!warning <possible loss of precision> nchoosek (100, 45);
 %!warning <result .* saturated> nchoosek (uint64 (80), uint64 (40));
 %!warning <result .* saturated> nchoosek (uint32 (80), uint32 (40));