biome-query: faster sorting

This commit is contained in:
Pavel Korytov 2023-07-11 12:55:34 +03:00
parent 013bf3d3ef
commit b41a805949

View file

@ -65,6 +65,7 @@ It is an alist with the following keys:
(defvar biome-query--layout-cache (make-hash-table :test 'equal) (defvar biome-query--layout-cache (make-hash-table :test 'equal)
"Cache for dynamic transient layout.") "Cache for dynamic transient layout.")
;; TODO delete this
(setq biome-query--layout-cache (make-hash-table :test 'equal)) (setq biome-query--layout-cache (make-hash-table :test 'equal))
;; Transient display classes ;; Transient display classes
@ -241,30 +242,63 @@ OBJ is an instance of `biome-query--transient-date-variable'."
b)) b))
a)) a))
(iter-defun biome-query--unique-key-cands (name) (defun biome-query--unique-key-weight (it seq-lengths)
"Generate unique key candidates for NAME." ;; TODO better weight function
(cl-loop for take in it
for length in seq-lengths
if (= 2 length) sum 1
else sum take))
(iter-defun biome-query--unique-key-cands (name &optional max-words max-weight)
"Generate unique key candidates for NAME.
The algorithm is as follows: NAME is split into words, each word
produces a list of all its prefixes. E.g. \"hello\" produces \"\",
\"h\", \"he\", \"hel\", etc. Numbers are takes as a whole,
e.g. \"100\" produces just \"\" and \"100\".
One key canditate is a concatenation of prefixes of the first
MAX-WORDS words, in the same order in which words appeared in NAME.
All possible key candidates are weighted by
`biome-query--unique-key-weight'. The iteration yields these
candidates in the ascending order by these weights, up to MAX-WEIGHT.
This algorithm has exponential computational complexity because
it sorts the cartesian product of all prefixes of each word, and it
gets pretty slow at more than 3 words. Hence the words are truncated
at 3."
(let ((name-low (replace-regexp-in-string (rx (not alnum)) " " (downcase name))) (let ((name-low (replace-regexp-in-string (rx (not alnum)) " " (downcase name)))
(generated-keys (make-hash-table :test 'equal))) (generated-keys (make-hash-table :test 'equal))
(let* ((items (seq-filter (max-weight (or max-weight 6))
(lambda (i) (max-words (or max-words 3)))
(not (member i biome-query--ignore-items))) (let* ((items (cl-loop for item in (split-string name-low)
(split-string name-low))) if (and (not (member item biome-query--ignore-items))
(sequences (mapcar (lambda (item) (< (length res) max-words))
(if (string-match-p (rx num) item) collect item into res
(number-sequence 0 (length item) (length item)) finally return res))
(number-sequence 0 (length item) 1))) (sequences (cl-loop for item in items
items))) for is-num = (string-match-p (rx num) item)
if is-num
collect (number-sequence 0 (length item) (length item))
else if (not is-num)
collect (number-sequence 0 (length item) 1)))
(seq-lengths (mapcar #'length sequences)))
(dolist (item-take (thread-last (dolist (item-take (thread-last
(reverse sequences) (reverse sequences)
(reduce #'biome-query--cartesian-product) (reduce #'biome-query--cartesian-product)
(mapcar (lambda (it) (if (listp it) (nreverse it) (list it)))) (mapcar (lambda (it) (if (listp it) (nreverse it) (list it))))
;; TODO delete comment
;; ((lambda (kek) (message "Sorting %s" (length kek)) kek))
;; XXX this seems to be just a bit faster than `seq-sort-by'.
(mapcar (lambda (it)
(cons (biome-query--unique-key-weight it seq-lengths) it)))
(seq-filter (lambda (it) (< (car it) max-weight)))
((lambda (sequences) (sort sequences (lambda (a b) (< (car a) (car b))))))
(mapcar #'cdr)
(seq-sort-by (seq-sort-by
(lambda (it) (lambda (it)
;; TODO better weight function (biome-query--unique-key-weight it seq-lengths))
(cl-loop for take in it
for seq in sequences
if (= 2 (length seq)) sum 1
else sum take))
#'<))) #'<)))
(let ((val (cl-loop for i from 0 (let ((val (cl-loop for i from 0
for item in items for item in items
@ -462,7 +496,7 @@ SECTION is a form as defined in `biome-api-parse--page'."
(interactive (list nil)) (interactive (list nil))
(unwind-protect (unwind-protect
(progn (progn
(biome-query--prepare-layout (biome-query--transient-prepare-layout
'biome-query--section 'biome-query--section
(append (append
'([(biome-query--transient-path-infix)]) '([(biome-query--transient-path-infix)])