2
2
; ;; sequences for common combinatorial functions.
3
3
4
4
; ; by Mark Engelberg (mark.engelberg@gmail.com)
5
- ; ; Last updated - May 18, 2016
5
+ ; ; Last updated - Jan 6, 2017
6
6
7
7
(ns
8
8
#^{:author " Mark Engelberg" ,
9
9
:doc " Efficient, functional algorithms for generating lazy
10
10
sequences for common combinatorial functions. (See the source code
11
11
for a longer description.)" }
12
12
clojure.math.combinatorics
13
- (:refer-clojure :exclude [update]))
13
+ (:refer-clojure :exclude [update]))
14
14
15
15
(comment
16
16
"
@@ -88,17 +88,6 @@ to write our own version that considers the empty-list to be distinct"
88
88
(apply distinct? s)
89
89
true ))
90
90
91
- (defmacro assert-with-message
92
- " Clojure 1.2 didn't allow asserts with a message, so we roll our own here for backwards compatibility"
93
- [x message]
94
- (when *assert*
95
- `(when-not ~x
96
- (throw (new AssertionError (str " Assert failed: " ~message " \n " (pr-str '~x)))))))
97
-
98
- ; ; so this code works with both 1.2.x and 1.3.0:
99
- (def ^{:private true } plus (first [+' +]))
100
- (def ^{:private true } mult (first [*' *]))
101
-
102
91
(defn- index-combinations
103
92
[n cnt]
104
93
(lazy-seq
@@ -310,7 +299,7 @@ In prior versions of the combinatorics library, there were two similar functions
310
299
{:pre [(integer? n) (not (neg? n))]}
311
300
; (Long/valueOf (long 1)) eliminates loop auto-boxing warning, in a way compatible with Clojure 1.2
312
301
(loop [acc (Long/valueOf (long 1 )), n n]
313
- (if (zero? n) acc (recur (mult acc n) (dec n)))))
302
+ (if (zero? n) acc (recur (*' acc n) (dec n)))))
314
303
315
304
(defn- factorial-numbers
316
305
" Input is a non-negative base 10 integer, output is the number in the
@@ -333,9 +322,8 @@ expressed as a list of 'digits'"
333
322
" Input should be a sorted sequential collection l of distinct items,
334
323
output is nth-permutation (0-based)"
335
324
[l n]
336
- (assert-with-message (< n (factorial (count l)))
337
- (format " %s is too large. Input has only %s permutations."
338
- (str n) (str (factorial (count l)))))
325
+ (assert (< n (factorial (count l)))
326
+ (print-str n " is too large. Input has only" (factorial (count l)) " permutations." ))
339
327
(let [length (count l)
340
328
fact-nums (factorial-numbers n)]
341
329
(loop [indices (concat (repeat (- length (count fact-nums)) 0 )
@@ -413,10 +401,9 @@ Output is a list of 'digits' in this wacky duplicate factorial number system"
413
401
(defn- nth-permutation-duplicates
414
402
" Input should be a sorted sequential collection l of distinct items,
415
403
output is nth-permutation (0-based)"
416
- [l n]
417
- (assert-with-message (< n (count-permutations l))
418
- (format " %s is too large. Input has only %s permutations."
419
- (str n) (str (count-permutations l))))
404
+ [l n]
405
+ (assert (< n (count-permutations l))
406
+ (print-str n " is too large. Input has only" (count-permutations l) " permutations." ))
420
407
(loop [freqs (into (sorted-map ) (frequencies l)),
421
408
indices (factorial-numbers-with-duplicates n freqs)
422
409
perm []]
@@ -480,8 +467,8 @@ output is nth-permutation (0-based)"
480
467
(zero? k) 1
481
468
(= k 1 ) n
482
469
(> k (quot n 2 )) (recur n (- n k))
483
- :else (/ (apply mult (range (inc (- n k)) (inc n)))
484
- (apply mult (range 1 (inc k))))))
470
+ :else (/ (apply *' (range (inc (- n k)) (inc n)))
471
+ (apply *' (range 1 (inc k))))))
485
472
486
473
(defn- ^{:dynamic true } count-combinations-from-frequencies [freqs t]
487
474
(let [counts (vals freqs)
@@ -495,7 +482,7 @@ output is nth-permutation (0-based)"
495
482
(= (count freqs) 1 ) 1
496
483
:else
497
484
(let [new-freqs (dec-key freqs (first (keys freqs)))]
498
- (plus (count-combinations-from-frequencies new-freqs (dec t))
485
+ (+' (count-combinations-from-frequencies new-freqs (dec t))
499
486
(count-combinations-from-frequencies (dissoc freqs (first (keys freqs))) t))))))
500
487
501
488
(defn- count-combinations-unmemoized
@@ -516,16 +503,16 @@ so that we can memoize over a series of calls."
516
503
(loop [n pow, y (Long/valueOf (long 1 )), z base]
517
504
(let [t (even? n), n (quot n 2 )]
518
505
(cond
519
- t (recur n y (mult z z))
520
- (zero? n) (mult z y)
521
- :else (recur n (mult z y) (mult z z))))))
506
+ t (recur n y (*' z z))
507
+ (zero? n) (*' z y)
508
+ :else (recur n (*' z y) (*' z z))))))
522
509
523
510
(defn- count-subsets-unmemoized
524
511
[items]
525
512
(cond
526
513
(empty? items) 1
527
514
(all-different? items) (expt-int 2 (count items))
528
- :else (apply plus (for [i (range 0 (inc (count items)))]
515
+ :else (apply +' (for [i (range 0 (inc (count items)))]
529
516
(count-combinations-unmemoized items i)))))
530
517
531
518
(defn count-subsets
@@ -569,9 +556,9 @@ represented by freqs"
569
556
(defn nth-combination
570
557
" The nth element of the sequence of t-combinations of items"
571
558
[items t n]
572
- (assert-with-message (< n (count-combinations items t))
573
- ( format " %s is too large. Input has only %s combinations. "
574
- ( str n) ( str ( count-combinations-unmemoized items t)) ))
559
+ (assert (< n (count-combinations items t))
560
+ ( print-str n " is too large. Input has only"
561
+ ( count-combinations-unmemoized items t) " combinations. " ))
575
562
(if (all-different? items)
576
563
(nth-combination-distinct items t n)
577
564
(binding [count-combinations-from-frequencies (memoize count-combinations-from-frequencies)]
@@ -585,9 +572,8 @@ represented by freqs"
585
572
586
573
(defn nth-subset
587
574
[items n]
588
- (assert-with-message (< n (count-subsets items))
589
- (format " %s is too large. Input has only %s subsets."
590
- (str n) (str (count-subsets items))))
575
+ (assert (< n (count-subsets items))
576
+ (print-str n " is too large. Input has only" (count-subsets items) " subsets." ))
591
577
(loop [size 0 ,
592
578
n n]
593
579
(let [num-combinations (count-combinations items size)]
0 commit comments