Can we improve upon this primes sieve code from SICP - scheme

A recent Q&A entry showcased the following primes generating code from SICP, using lazy streams:
(define (sieve stream)
(cons-stream
(stream-car stream)
(sieve (stream-filter
(lambda (x)
(not (divisible? x (stream-car stream))))
(stream-cdr stream)))))
(define primes (sieve (integers-starting-from 2)))
An answer there showed primes to be equivalent, among other possibilities, to the following:
(cons-stream 2
(cons-stream 3
(cons-stream 5
(cons-stream 7
(sieve
(stream-filter (lambda (x) (not (divisible? x 7)))
(stream-filter (lambda (x) (not (divisible? x 5)))
(stream-filter (lambda (x) (not (divisible? x 3)))
(stream-filter (lambda (x) (not (divisible? x 2)))
(integers-starting-from 9))))))))))
It seems there are too many filter streams here -- for instance 7 was produced by filtering the input numbers by 2, 3 and 5, whereas it only really had to be tested by 2 alone -- only the numbers above 9 need really be test divided by 3, let alone by 5 etc.
This problem becomes more and more pronounced as we go along producing this stream of primes. Overall, producing first n primes takes O(n^2) with this code.
Can we do better?

Indeed, we need to only start filtering out multiples of a prime after its square is encountered in the input.
For that, we shall use the primes and their squares. And we'll use the same code to produce the primes we need to produce our primes:
(define (pprimes)
(cons-stream 2
(psieve (stream-map (lambda (x) (cons x (* x x)))
(pprimes)) ;; here
(integers-starting-from 3))))
(define (psieve pr-sqrs numbers) ;; prime+square pairs
(if (< (stream-car numbers)
(cdr (stream-car pr-sqrs))) ;; prime's square
(cons-stream
(stream-car numbers)
(psieve pr-sqrs ;; same prime+square pair
(stream-cdr numbers))) ;; for the next number
(psieve
(stream-cdr pr-sqrs) ;; advance prime+square's stream
(stream-filter ;; and start filtering
(let ((p (car (stream-car pr-sqrs)))) ;; by this prime now
(lambda (x)
(not (divisible? x p))))
(stream-cdr numbers)))))
Now this leads to
(pprimes)
=
....
=
(cons-stream 2
(cons-stream 3
(cons-stream 5
(cons-stream 7
(cons-stream 11
(cons-stream 13
(cons-stream 17
(cons-stream 19
(psieve (cons-stream 5 ... )
(cons-stream 25 ... )
(stream-filter (lambda (x) (not (divisible? x 3)))
(stream-filter (lambda (x) (not (divisible? x 2)))
(integers-starting-from 20))))))))))))
=
....
which, undoubtedly, is much better. No number below 25 will be tested by 5, etc.
This is still trial division, and runs in about n^1.5. True sieve of Eratosthenes should run at n log n log log n which is empirically usually close to n^1.1..1.2 or thereabouts. But this n^1.5 is a great improvement over the quadratic algorithm too, and in practice will run much faster than it in absolute terms as well.

Related

Geometric Series function in Scheme language

Im trying to learn scheme and Im having trouble with the arithmetic in the Scheme syntax.
Would anyone be able to write out a function in Scheme that represents the Geometric Series?
You have expt, which is Scheme power procedure. (expt 2 8) ; ==> 256 and you have * that does multiplication. eg. (* 2 3) ; ==> 6. From that you should be able to make a procedure that takes a n and produce the nth number in a specific geometric series.
You can also produce a list with the n first if you instead of using expt just muliply in a named let, basically doing the expt one step at a time and accumulate the values in a list. Here is an example of a procedure that makes a list of numbers:
(define (range from to)
(let loop ((n to) (acc '())
(if (< n from)
acc
(loop (- 1 n) (cons n acc)))))
(range 3 10) ; ==> (3 4 5 6 7 8 9 10)
Notice I'm doing them in reverse. If I cannot do it in reverse I would in the base case do (reverse acc) to get the right order as lists are always made from end to beginning. Good luck with your series.
range behaves exactly like Python's range.
(define (range from (below '()) (step 1) (acc '()))
(cond ((null? below) (range 0 from step))
((> (+ from step) below) (reverse acc))
(else (range (+ from step) below step (cons from acc)))))
Python's range can take only one argument (the upper limit).
If you take from and below as required arguments, the definition is shorter:
(define (range from below (step 1) (acc '()))
(cond ((> (+ from step) below) (reverse acc))
(else (range (+ from step) below step (cons from acc)))))
Here is an answer, in Racket, that you probably cannot submit as homework.
(define/contract (geometric-series x n)
;; Return a list of x^k for k from 0 to n (inclusive).
;; This will be questionable if x is not exact.
(-> number? natural-number/c (listof number?))
(let gsl ((m n)
(c (expt x n))
(a '()))
(if (zero? m)
(cons 1 a)
(gsl (- m 1)
(/ c x)
(cons c a)))))

Reordering streams in Racket

I want to write a procedure that rearranges the items in one stream (the data stream) into the order specified by another stream (the order stream), which consists of item numbers specifying the desired order.
For example, if the data stream starts with 4, 13, 2, 8 and the order stream starts with 3, 1, 4, 2 then the result stream will start with 2, 4, 8, 13. (The first item of the result is the third item of the data, the second item of the result is the first item of the data, and so on.)
I have got so far...
(define (reorder order-stream data-stream)
(cond ((stream-null? order-stream) the-empty-stream)
((stream-null? data-stream) the-empty-stream)
(else (cons-stream (stream-ref order-stream data-stream))))
(define (stream-ref s n)
(if (= n 0)
(stream-car s)
(stream-ref (stream-cdr s) (- n 1))))
However, the output is not as expected.
Using Racket streams.
Notice that
(stream-ref data-stream (stream-first order-stream))
will use the first element of the order stream to pick out an element of the data stream.
Note also that unless the data stream support random access, this will be we slow.
#lang racket
(require racket/stream)
(define (reorder order-stream data-stream)
(cond ((stream-empty? order-stream) empty-stream)
(else (stream-cons (stream-ref data-stream (stream-first order-stream))
(reorder (stream-rest order-stream) data-stream)))))
(define ones (stream-cons 1 ones))
(define (stream-add s1 s2)
(stream-cons (+ (stream-first s1) (stream-first s2))
(stream-add (stream-rest s1) (stream-rest s2))))
(define fibonacci (stream-cons 1 (stream-cons 1 (stream-add fibonacci (stream-rest fibonacci)))))
(for/list ([x fibonacci] [n 10]) x) ; '(1 1 2 3 5 8 13 21 34 55)
(for/list ([x (reorder '(3 1 4 2 10) fibonacci)]) x) ; '(3 1 5 2 89)

finding subsets of length N of a list in scheme

I wrote a function which finds all the subsets of a list already and it works. I'm trying to write a second function where I get all the subsets of N length, but it's not working very well.
This is my code:
(define (subset_length_n n lst)
(cond
[(empty? lst) empty]
[else (foldr (lambda (x y) (if (equal? (length y) n) (cons y x) x)) empty (powerset lst))]
))
where (powerset lst) gives a list of all the subsets.
Am I misunderstanding the purpose of foldr?
I was thinking that the program would go through each element of the list of subsets, compare the length to n, cons it onto the empty list if there the same, ignore it if it's not.
But (subset_length_n 2 (list 1 2 3)) gives me (list (list 1 2) 1 2 3) when I want (list (list 1 2) (list 1 3) (list 2 3))
Thanks in advance
When using foldr you don't have to test if the input list is empty, foldr takes care of that for you. And this seems like a job better suited for filter:
(define (subset_length_n n lst)
(filter (lambda (e) (= (length e) n))
(powerset lst)))
If you must, you can use foldr for this, but it's a rather contrived solution. You were very close to getting it right! in your code, just change the lambda's parameters, instead of (x y) write (y x). See how a nice indentation and appropriate parameter names go a long way toward writing correct solutions:
(define (subset_length_n n lst)
(foldr (lambda (e acc)
(if (= (length e) n)
(cons e acc)
acc))
empty
(powerset lst)))
Anyway, it works as expected:
(subset_length_n 4 '(1 2 3 4 5))
=> '((1 2 3 4) (1 2 3 5) (1 2 4 5) (1 3 4 5) (2 3 4 5))

Improving performance of Racket Code and error when trying to byte compile

I hacked together several code snippets from various sources and created a crude implementation of a Wolfram Blog article at http://bit.ly/HWdUqK - for those that are mathematically inclined, it is very interesting!
Not surprisingly, given that I'm still a novice at Racket, the code takes too much time to calculate the results (>90 min versus 49 seconds for the author) and eats up a lot of memory. I suspect it is all about the definition (expListY) which needs to be reworked.
Although I have it working in DrRacket, I am also having problems byte-compiling the source, and still working on it
(Error message: +: expects type <number> as 1st argument, given: #f; other arguments were: 1 -1)
Anybody want to take a stab at improving the performance and efficiency? I apologize for the unintelligible code and lack of better code comments.
PS: Should I be cutting and pasting the code directly here?
Probably similar to soegaard's solution, except this one rolls its own "parser", so it's self contained. It produces the complete 100-year listing in a bit under 6 seconds on my machine. There's a bunch of tricks that this code uses, but it's not really something that would be called "optimized" in any serious way: I'm sure that it can be made much faster with some memoization, care for maximizing tree sharing etc etc. But for such a small domain it's not worth the effort... (Same goes for the quality of this code...)
BTW#1, more than parsing, the original solution(s) use eval which does not make things faster... For things like this it's usually better to write the "evaluator" manually. BTW#2, this doesn't mean that Racket is faster than Mathematica -- I'm sure that the solution in that post makes it grind redundant cpu cycles too, and a similar solution would be faster.
#lang racket
(define (tuples list n)
(let loop ([n n])
(if (zero? n)
'(())
(for*/list ([y (in-list (loop (sub1 n)))] [x (in-list list)])
(cons x y)))))
(define precedence
(let ([t (make-hasheq)])
(for ([ops '((#f) (+ -) (* /) (||))] [n (in-naturals)])
(for ([op ops]) (hash-set! t op n)))
t))
(define (do op x y)
(case op
[(+) (+ x y)] [(-) (- x y)] [(*) (* x y)] [(/) (/ x y)]
[(||) (+ (* 10 x) y)]))
(define (run ops nums)
(unless (= (add1 (length ops)) (length nums)) (error "poof"))
(let loop ([nums (cddr nums)]
[ops (cdr ops)]
[numstack (list (cadr nums) (car nums))]
[opstack (list (car ops))])
(if (and (null? ops) (null? opstack))
(car numstack)
(let ([op (and (pair? ops) (car ops))]
[topop (and (pair? opstack) (car opstack))])
(if (> (hash-ref precedence op)
(hash-ref precedence topop))
(loop (cdr nums)
(cdr ops)
(cons (car nums) numstack)
(cons op opstack))
(loop nums
ops
(cons (do topop (cadr numstack) (car numstack))
(cddr numstack))
(cdr opstack)))))))
(define (expr ops* nums*)
(define ops (map symbol->string ops*))
(define nums (map number->string nums*))
(string-append* (cons (car nums) (append-map list ops (cdr nums)))))
(define nums (for/list ([i (in-range 10 0 -1)]) i))
(define year1 2012)
(define nyears 100)
(define year2 (+ year1 nyears))
(define years (make-vector nyears '()))
(for ([ops (in-list (tuples '(+ - * / ||) 9))])
(define r (run ops nums))
(when (and (integer? r) (<= year1 r) (< r year2))
(vector-set! years (- r year1)
(cons ops (vector-ref years (- r year1))))))
(for ([solutions (in-vector years)] [year (in-range year1 year2)])
(if (pair? solutions)
(printf "~a = ~a~a\n"
year (expr (car solutions) nums)
(if (null? (cdr solutions))
""
(format " (~a more)" (length (cdr solutions)))))
(printf "~a: no combination!\n" year)))
Below is my implementation. I tweaked and optimized a thing or two in your code, in my laptop it takes around 35 minutes to finish (certainly an improvement!) I found that the evaluation of expressions is the real performance killer - if it weren't for the calls to the procedure to-expression, the program would finish in under a minute.
I guess that in programming languages that natively use infix notation the evaluation would be much faster, but in Scheme the cost for parsing and then evaluating a string with an infix expression is just too much.
Maybe someone can point out a suitable replacement for the soegaard/infix package? or alternatively, a way to directly evaluate an infix expression list that takes into account operator precedence, say '(1 + 3 - 4 & 7) - where & stands for number concatenation and has the highest precedence (for example: 4 & 7 = 47), and the other arithmetic operators (+, -, *, /) follow the usual precedence rules.
#lang at-exp racket
(require (planet soegaard/infix)
(planet soegaard/infix/parser))
(define (product lst1 lst2)
(for*/list ([x (in-list lst1)]
[y (in-list lst2)])
(cons x y)))
(define (tuples lst n)
(if (zero? n)
'(())
(product lst (tuples lst (sub1 n)))))
(define (riffle numbers ops)
(if (null? ops)
(list (car numbers))
(cons (car numbers)
(cons (car ops)
(riffle (cdr numbers)
(cdr ops))))))
(define (expression-string numbers optuple)
(apply string-append
(riffle numbers optuple)))
(define (to-expression exp-str)
(eval
(parse-expression
#'here (open-input-string exp-str))))
(define (make-all-combinations numbers ops)
(let loop ((opts (tuples ops (sub1 (length numbers))))
(acc '()))
(if (null? opts)
acc
(let ((exp-str (expression-string numbers (car opts))))
(loop (cdr opts)
(cons (cons exp-str (to-expression exp-str)) acc))))))
(define (show-n-expressions all-combinations years)
(for-each (lambda (year)
(for-each (lambda (comb)
(when (= (cdr comb) year)
(printf "~s ~a~n" year (car comb))))
all-combinations)
(printf "~n"))
years))
Use it like this for replicating the results in the original blog post:
(define numbers '("10" "9" "8" "7" "6" "5" "4" "3" "2" "1"))
(define ops '("" "+" "-" "*" "/"))
; beware: this takes around 35 minutes to finish in my laptop
(define all-combinations (make-all-combinations numbers ops))
(show-n-expressions all-combinations
(build-list 5 (lambda (n) (+ n 2012))))
UPDATE :
I snarfed Eli Barzilay's expression evaluator and plugged it into my solution, now the pre-calculation of all combinations is done in around 5 seconds! The show-n-expressions procedure still needs some work to avoid iterating over the whole list of combinations each time, but that's left as an exercise for the reader. What matters is that now brute-forcing the values for all the possible expression combinations is blazing fast.
#lang racket
(define (tuples lst n)
(if (zero? n)
'(())
(for*/list ((y (in-list (tuples lst (sub1 n))))
(x (in-list lst)))
(cons x y))))
(define (riffle numbers ops)
(if (null? ops)
(list (car numbers))
(cons (car numbers)
(cons (car ops)
(riffle (cdr numbers)
(cdr ops))))))
(define (expression-string numbers optuple)
(string-append*
(map (lambda (x)
(cond ((eq? x '&) "")
((symbol? x) (symbol->string x))
((number? x) (number->string x))))
(riffle numbers optuple))))
(define eval-ops
(let ((precedence (make-hasheq
'((& . 3) (/ . 2) (* . 2)
(- . 1) (+ . 1) (#f . 0))))
(apply-op (lambda (op x y)
(case op
((+) (+ x y)) ((-) (- x y))
((*) (* x y)) ((/) (/ x y))
((&) (+ (* 10 x) y))))))
(lambda (nums ops)
(let loop ((nums (cddr nums))
(ops (cdr ops))
(numstack (list (cadr nums) (car nums)))
(opstack (list (car ops))))
(if (and (null? ops) (null? opstack))
(car numstack)
(let ((op (and (pair? ops) (car ops)))
(topop (and (pair? opstack) (car opstack))))
(if (> (hash-ref precedence op)
(hash-ref precedence topop))
(loop (cdr nums)
(cdr ops)
(cons (car nums) numstack)
(cons op opstack))
(loop nums
ops
(cons (apply-op topop (cadr numstack) (car numstack))
(cddr numstack))
(cdr opstack)))))))))
(define (make-all-combinations numbers ops)
(foldl (lambda (optuple tail)
(cons (cons (eval-ops numbers optuple) optuple) tail))
empty (tuples ops (sub1 (length numbers)))))
(define (show-n-expressions all-combinations numbers years)
(for-each (lambda (year)
(for-each (lambda (comb)
(when (= (car comb) year)
(printf "~s ~a~n"
year
(expression-string numbers (cdr comb)))))
all-combinations)
(printf "~n"))
years))
Use it like this:
(define numbers '(10 9 8 7 6 5 4 3 2 1))
(define ops '(& + - * /))
; this is very fast now!
(define all-combinations (make-all-combinations numbers ops))
(show-n-expressions all-combinations numbers
(build-list 5 (lambda (n) (+ n 2012))))
As Óscar points out, the problem is that soegaard/infix is slow for this type of problem.
I found a standard shunting-yard parser for infix expressions on GitHub and wrote the following program in Racket:
#lang racket
(require "infix-calc.scm")
(define operators '("*" "/" "+" "-" ""))
(time
(for*/list ([o1 (in-list operators)]
[o2 (in-list operators)]
[o3 (in-list operators)]
[o4 (in-list operators)]
[o5 (in-list operators)]
[o6 (in-list operators)]
[o7 (in-list operators)]
[o8 (in-list operators)]
[o9 (in-list operators)]
[expr (in-value
(apply string-append
(list "1" o1 "2" o2 "3" o3 "4" o4 "5" o5 "6" o6 "7" o7 "8" o8 "9" o9 "10")))]
#:when (= (first (calc expr)) 2012))
expr))
After a little less than 3 minutes the results are:
Welcome to DrRacket, version 5.2.900.2--2012-03-29(8c22c6c/a) [3m].
Language: racket; memory limit: 128 MB.
cpu time: 144768 real time: 148818 gc time: 25252
'("1*2*3+4*567*8/9-10"
"1*2+34*56+7+89+10"
"1*23+45*6*7+89+10"
"1+2+3/4*5*67*8+9-10"
"1+2+3+4*567*8/9-10"
"1+2+34*56+7+8+9*10"
"1+23+45*6*7+8+9*10"
"1-2+345*6-7*8+9-10"
"12*34*5+6+7*8-9*10"
"12*34*5+6-7-8-9-10"
"1234+5-6+789-10")
The infix parser was written by Andrew Levenson.
The parser and the above code can be found here:
https://github.com/soegaard/Scheme-Infix-Calculator
this isn't a complete answer, but i think it's an alternative to the library Óscar López is asking for. unfortunately it's in clojure, but hopefully it's clear enough...
(def default-priorities
{'+ 1, '- 1, '* 2, '/ 2, '& 3})
(defn- extend-tree [tree priorities operator value]
(if (seq? tree)
(let [[op left right] tree
[old new] (map priorities [op operator])]
(if (> new old)
(list op left (extend-tree right priorities operator value))
(list operator tree value)))
(list operator tree value)))
(defn priority-tree
([operators values] (priority-tree operators values default-priorities))
([operators values priorities] (priority-tree operators values priorities nil))
([operators values priorities tree]
(if-let [operators (seq operators)]
(if tree
(recur
(rest operators) (rest values) priorities
(extend-tree tree priorities (first operators) (first values)))
(let [[v1 v2 & values] values]
(recur (rest operators) values priorities (list (first operators) v1 v2))))
tree)))
; [] [+ & *] [1 2 3 4] 1+23*4
; [+ 1 2] [& *] [3 4] - initial tree
; [+ 1 [& 2 3]] [*] [4] - binds more strongly than + so replace right-most node
; [+ 1 [* [& 2 3] 4]] [] [] - descend until do not bind more tightly, and extend
(println (priority-tree ['+ '& '*] [1 2 3 4])) ; 1+23*4
(println (priority-tree ['& '- '* '+ '&] [1 2 3 4 5 6])) ; 12 - 3*4 + 56
the output is:
(+ 1 (* (& 2 3) 4))
(+ (- (& 1 2) (* 3 4)) (& 5 6))
[update] adding the following
(defn & [a b] (+ b (* 10 a)))
(defn all-combinations [tokens length]
(if (> length 0)
(for [token tokens
smaller (all-combinations tokens (dec length))]
(cons token smaller))
[[]]))
(defn all-expressions [operators digits]
(map #(priority-tree % digits)
(all-combinations operators (dec (count digits)))))
(defn all-solutions [target operators digits]
(doseq [expression
(filter #(= (eval %) target)
(all-expressions operators digits))]
(println expression)))
(all-solutions 2012 ['+ '- '* '/ '&] (range 10 0 -1))
solves the problem, but it's slow - 28 minutes to complete. this is on a nice, fairly recent laptop (i7-2640M).
(+ (- (+ 10 (* 9 (& 8 7))) (& 6 5)) (* 4 (& (& 3 2) 1)))
(+ (- (+ (+ (* (* 10 9) 8) 7) 6) 5) (* 4 (& (& 3 2) 1)))
(- (- (+ (- (& 10 9) (* 8 7)) (* (& (& 6 5) 4) 3)) 2) 1)
(i only printed 2012 - see code above - but it would have evaluated the entire sequence).
so, unfortunately, this doesn't really answer the question, since it's no faster than Óscar López's code. i guess the next step would be to put some smarts into the evaluation and so save some time. but what?
[update 2] after reading the other posts here i replaced eval with
(defn my-eval [expr]
(if (seq? expr)
(let [[op left right] expr]
(case op
+ (+ (my-eval left) (my-eval right))
- (- (my-eval left) (my-eval right))
* (* (my-eval left) (my-eval right))
/ (/ (my-eval left) (my-eval right))
& (& (my-eval left) (my-eval right))))
expr))
and the running time drops to 45 secs. still not great, but it's a very inefficient parse/evaluation.
[update 3] for completeness, the following is an implementation of the shunting-yard algorithm (a simple one that is always left-associative) and the associated eval, butit only reduces the time to 35s.
(defn shunting-yard
([operators values] (shunting-yard operators values default-priorities))
([operators values priorities]
(let [[value & values] values]
(shunting-yard operators values priorities nil (list value))))
([operators values priorities stack-ops stack-vals]
; (println operators values stack-ops stack-vals)
(if-let [[new & short-operators] operators]
(let [[value & short-values] values]
(if-let [[old & short-stack-ops] stack-ops]
(if (> (priorities new) (priorities old))
(recur short-operators short-values priorities (cons new stack-ops) (cons value stack-vals))
(recur operators values priorities short-stack-ops (cons old stack-vals)))
(recur short-operators short-values priorities (list new) (cons value stack-vals))))
(concat (reverse stack-vals) stack-ops))))
(defn stack-eval
([stack] (stack-eval (rest stack) (list (first stack))))
([stack values]
(if-let [[op & stack] stack]
(let [[right left & tail] values]
(case op
+ (recur stack (cons (+ left right) tail))
- (recur stack (cons (- left right) tail))
* (recur stack (cons (* left right) tail))
/ (recur stack (cons (/ left right) tail))
& (recur stack (cons (& left right) tail))
(recur stack (cons op values))))
(first values))))
Interesting! I had to try it, it's in Python, hope you don't mind. It runs in about 28 seconds, PyPy 1.8, Core 2 Duo 1.4
from __future__ import division
from math import log
from operator import add, sub, mul
div = lambda a, b: float(a) / float(b)
years = set(range(2012, 2113))
none = lambda a, b: a * 10 ** (int(log(b, 10)) + 1) + b
priority = {none: 3, mul: 2, div: 2, add: 1, sub: 1}
symbols = {none: '', mul: '*', div: '/', add: '+', sub: '-', None: ''}
def evaluate(numbers, operators):
ns, ops = [], []
for n, op in zip(numbers, operators):
while ops and (op is None or priority[ops[-1]] >= priority[op]):
last_n = ns.pop()
last_op = ops.pop()
n = last_op(last_n, n)
ns.append(n)
ops.append(op)
return n
def display(numbers, operators):
return ''.join([
i for n, op in zip(numbers, operators) for i in (str(n), symbols[op])])
def expressions(years):
numbers = 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
operators = none, add, sub, mul, div
pools = [operators] * (len(numbers) - 1) + [[None]]
result = [[]]
for pool in pools:
result = [x + [y] for x in result for y in pool]
for ops in result:
expression = evaluate(numbers, ops)
if expression in years:
yield '%d = %s' % (expression, display(numbers, ops))
for year in sorted(expressions(years)):
print year

Good simple algorithm for generating necklaces in Scheme?

A k-ary necklace of length n is an ordered list of length n whose items are drawn from an alphabet of length k, which is the lexicographically first list in a sort of all lists sharing an ordering under rotation.
Example:
(1 2 3) and (1 3 2) are the necklaces of length 3 from the alphabet {1 2 3}.
More info:
http://en.wikipedia.org/wiki/Necklace_(combinatorics)
I'd like to generate these in Scheme (or a Lisp of your choice). I've found some papers...
Savage - A New Algorithm for Generating Necklaces
Sawada - Generating Bracelets in Constant Amortized Time
Sawada - Generating Necklaces with Forbidden Substrings
...but the code presented in them is opaque to me. Mainly because they don't seem to be passing in either the alphabet or the length (n) desired. The scheme procedure I'm looking for is of the form (necklaces n '(a b c...)).
I can generate these easy enough by first generating k^n lists and then filtering out the rotations. But it's terribly memory-inefficient...
Thanks!
The FKM algorithm for generating necklaces. PLT Scheme. Not so hot on the performance. It'll take anything as an alphabet and maps the internal numbers onto whatever you provided. Seems to be correct; no guarantees. I was lazy when translating the loops, so you get this weird mix of for loops and escape continuations.
(require srfi/43)
(define (gennecklaces n alphabet)
(let* ([necklaces '()]
[alphavec (list->vector alphabet)]
[convert-necklace
(lambda (vec)
(map (lambda (x) (vector-ref alphavec x)) (cdr (vector->list vec))))]
[helper
(lambda (n k)
(let ([a (make-vector (+ n 1) 0)]
[i n])
(set! necklaces (cons (convert-necklace a) necklaces))
(let/ec done
(for ([X (in-naturals)])
(vector-set! a i (add1 (vector-ref a i)))
(for ([j (in-range 1 (add1 (- n i)))])
(vector-set! a (+ j i)
(vector-ref a j)))
(when (= 0 (modulo n i))
(set! necklaces (cons (convert-necklace a) necklaces)))
(set! i n)
(let/ec done
(for ([X (in-naturals)])
(unless (= (vector-ref a i)
(- k 1))
(done))
(set! i (- i 1))))
(when (= i 0)
(done))))))])
(helper n (length alphabet))
necklaces))
I would do a two step process. First, find each combination of n elements from the alphabet. Then, for each combination, pick the lowest value, and generate all permutations of the remaining items.
Edit: Here is some code. It assumes that the input list is already sorted and that it contains no duplicates.
(define (choose n l)
(let ((len (length l)))
(cond ((= n 0) '(()))
((> n len) '())
((= n len) (list l))
(else (append (map (lambda (x) (cons (car l) x))
(choose (- n 1) (cdr l)))
(choose n (cdr l)))))))
(define (filter pred l)
(cond ((null? l) '())
((pred (car l)) (cons (car l) (filter pred (cdr l))))
(else (filter pred (cdr l)))))
(define (permute l)
(cond ((null? l) '(()))
(else (apply append
(map (lambda (x)
(let ((rest (filter (lambda (y) (not (= x y))) l)))
(map (lambda (subperm) (cons x subperm))
(permute rest))))
l)))))
(define (necklaces n l)
(apply
append
(map
(lambda (combination)
(map (lambda (permutation)
(cons (car combination) permutation))
(permute (cdr combination))))
(choose n l))))
(display (choose 1 '(1 2 3 4 5))) (newline)
(display (choose 2 '(1 2 3 4 5))) (newline)
(display (permute '(1 2))) (newline)
(display (permute '(1 2 3))) (newline)
(display (necklaces 3 '(1 2 3 4))) (newline)
(display (necklaces 2 '(1 2 3 4))) (newline)
Example: (1 2 3) and (1 3 2) are the necklaces of length 3 from the alphabet {1 2 3}.
You forgot (1 1 1) (1 1 2) (1 1 3) (1 2 2) (1 3 3) (2 2 2) (2 2 3) (2 3 3) (3 3 3). Necklaces can contain duplicates.
If you were only looking for necklaces of length N, drawn from an alphabet of size N, that contain no duplicates, then it's pretty easy: there will be (N-1)! necklaces, and each necklace will be of the form (1 :: perm) where perm is any permutation of {2 .. N}. For example, the necklaces of {1 .. 4} would be (1 2 3 4) (1 2 4 3) (1 3 2 4) (1 3 4 2) (1 4 2 3) (1 4 3 2). Extending this method to deal with no-duplicates necklaces of length K < N is left as an exercise for the reader.
But if you want to find real necklaces, which may contain duplicate elements, then it's not so simple.
As a first idea, you can do the obvious, but inefficient: step through all combinations and check if they are a necklace, i.e. if they are the lexically smallest rotation of the elements (formal definition on p 5 in above paper). This would be like the way you proposed, but you would throw away all non-necklaces as soon as they are generated.
Other than that, I think that you will have to understand this article (http://citeseer.ist.psu.edu/old/wang90new.html):
T. Wang and C. Savage, "A new algorithm for generating necklaces," Report
TR-90-20, Department of Computer Science, North Carolina State University
(1990).
It is not too hard, you can break it down by implementing the tau and sigma functions as described and then applying them in the order outlined in the article.

Resources