sagemath / sage

Main repository of SageMath
https://www.sagemath.org
Other
1.45k stars 482 forks source link

Improve lookahead in IntegerListsLex #18055

Open nthiery opened 9 years ago

nthiery commented 9 years ago

IntegerListsLex uses a depth first search in a prefix tree, with lookahead to prune branches. The purpose of this ticket is to improve the lookahead algorithm in two directions:

Example:: even just for n=1000 this is taking a long time:

    sage: n = 100
    sage: IntegerListsLex(binomial(n,2)-1, length=n, min_slope=1).list()

The following also take a long time, which should be optimized:

    sage: IntegerListsLex(10^100, max_length=1).list()
    sage: IntegerListsLex(499499, length=1000, min_slope=1).list()

One could hope that one could reach an average complexity roughly linear in O(log(max_n), max_length) per list generated.

Concrete steps:

Depends on #18109

CC: @bgillesp

Component: combinatorics

Issue created by migration from https://trac.sagemath.org/ticket/18055

anneschilling commented 9 years ago

Description changed:

--- 
+++ 
@@ -10,6 +10,11 @@
     sage: n = 100
     sage: IntegerListsLex(binomial(n,2)-1, length=n, min_slope=1).list()

+The following also takes a long time, which should be optimized: + +```

anneschilling commented 9 years ago

Description changed:

--- 
+++ 
@@ -10,10 +10,11 @@
     sage: n = 100
     sage: IntegerListsLex(binomial(n,2)-1, length=n, min_slope=1).list()

-The following also takes a long time, which should be optimized: +The following also take a long time, which should be optimized:

     sage: IntegerListsLex(10^100, max_length=1).list()
+    sage: IntegerListsLex(499499, length=1000, min_slope=1).list()

One could hope that, in non degenerate cases, one could reach an

nthiery commented 9 years ago

Description changed:

--- 
+++ 
@@ -21,3 +21,43 @@
 average complexity roughly linear in `O(log(max_n), max_length)` per
 list generated.

+Concrete steps:
+
+- Extend `Envelope` with a function:
+
+  ```
+      def area(k):
+          """Return the area under the envelope between `0` and `k`"""
+  ```
+
+  This functions should handle the "reverse smoothing" from position
+  `k` (so that the envelope satisfies both `min_slope` and `max_slope`
+  conditions between `1` and `k`), and have appropriate algorithmic
+  and caching so that the overall complexity of computing all
+  `area(k)` for `k<=l` is linear in `l`.
+
+- Replace:
+
+  ```
+      def _possible_m(self, m, ...):
+  ```
+  by:
+
+  ```
+      def lookahead(self):
+  ```
+
+  which shall detect whether `_current_list` has a chance to be a
+  prefix of some valid list. Using the above `area` method of the
+  envelopes, it should be possible to detect most dead branches.
+
+  This method should support `_current_list=[]` as well.
+
+  This method should store as much information as relevant to avoid
+  later recomputation for lower nodes in the tree. A minima, this
+  could possibly return/store a range for the next value, removing the
+  need for a separate `_m_interval` method.
+
+- Update `next` accordingly (the logic should be slightly simpler
+  thanks to the handling of the empty prefix).
+
nthiery commented 9 years ago

Description changed:

--- 
+++ 
@@ -50,6 +50,8 @@
   which shall detect whether `_current_list` has a chance to be a
   prefix of some valid list. Using the above `area` method of the
   envelopes, it should be possible to detect most dead branches.
+  Using dichotomy on the area / parts, it should be possible to
+  achieve good complexity in most cases.

   This method should support `_current_list=[]` as well.
jdemeyer commented 9 years ago

Description changed:

--- 
+++ 
@@ -17,7 +17,7 @@
     sage: IntegerListsLex(499499, length=1000, min_slope=1).list()

-One could hope that, in non degenerate cases, one could reach an +One could hope that one could reach an average complexity roughly linear in O(log(max_n), max_length) per list generated.

jdemeyer commented 9 years ago
comment:5

Can we please stop talking about "degenerate cases" without specifying what that means?

nthiery commented 9 years ago
comment:6

Replying to @jdemeyer:

Can we please stop talking about "degenerate cases" without specifying what that means?

This ticket involves some research, which includes in particular defining precisely what "degenerate" is. Until this research is done, we can't do anything but remain vague.

nthiery commented 9 years ago

Description changed:

--- 
+++ 
@@ -63,3 +63,4 @@
 - Update `next` accordingly (the logic should be slightly simpler
   thanks to the handling of the empty prefix).

+- Remove `integer_list_old` at the final stage.
jdemeyer commented 9 years ago

Dependencies: #18181

jdemeyer commented 9 years ago

Changed dependencies from #18181 to #18109

nthiery commented 9 years ago

Description changed:

--- 
+++ 
@@ -1,7 +1,7 @@
 `IntegerListsLex` uses a depth first search in a prefix tree, with lookahead to prune branches.
 The purpose of this ticket is to improve the lookahead algorithm in two directions:

-- Detect more branches that can be cut.
+- Detect more (all?) branches that can be cut.
 - Better time complexity; this probably will involve identifying important invariants and caching them.

 Example:: even just for n=1000 this is taking a long time:
@@ -17,50 +17,93 @@
     sage: IntegerListsLex(499499, length=1000, min_slope=1).list()

-One could hope that one could reach an -average complexity roughly linear in O(log(max_n), max_length) per -list generated. +One could hope that one could reach an average complexity roughly +linear in O(log(max_n), max_length) per list generated.

Concrete steps:

-- Extend Envelope with a function: +- If we want the floor function to satisfy the max_slope constraint,

-- Replace:

+- If not implemented elsewhere: let the constructor accept a prefix as