1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
From kris.wbst129@xerox.com Thu May 19 13:22:54 EDT 1994
Article: 12774 of comp.lang.lisp
Xref: glinda.oz.cs.cmu.edu comp.lang.lisp:12774
Newsgroups: comp.lang.lisp
Path: honeydew.srv.cs.cmu.edu!nntp.club.cc.cmu.edu!newsfeed.pitt.edu!gatech!howland.reston.ans.net!usc!nic-nac.CSU.net!charnel.ecst.csuchico.edu!olivea!decwrl!parc!rocksanne!kris
From: kris%.wbst129@xerox.com (Kris A. Schneider)
Subject: Efficient way to generate permutations?
Message-ID: <1994May11.205732.19694@news.wrc.xerox.com>
Sender: news@news.wrc.xerox.com
Reply-To: kris.wbst129@xerox.com
Organization: Xerox
X-Newsreader: TIN [version 1.2 PL1]
Date: Wed, 11 May 1994 20:57:32 GMT
Lines: 33
Hi all,
I'm currently using something like the following code to generate a
permutation of *N* integers (1 through *N* inclusive) in an *N*-length array:
(defconstant *N* 100)
(defvar *PERM* (make-array *N* :initial-element 0)
"Array to hold permutation")
(defvar *CHECK* (make-array *N* :initial-element 0)
"Flags to check if a number has already been generated")
(defun permute ()
(dotimes (i *N*)
(let ((j (do ((r (1+ (random *N*)) (1+ (random *N*))))
((zerop (aref *CHECK* (1- r))) r))))
(setf (aref *CHECK* (1- j)) 1)
(setf (aref *PERM* i) j))))
The do loop that eventually returns a value to bind to "j" keeps generating
random numbers until it finds one that hasn't been generated yet. The
appropriate "flag" is then set in the *CHECK* array and the number is added to
the permutation (the array *PERM*). The whole do loop construct strikes me as
overkill, so I'm curious if anyone has a more effecient approach? Thanks for
any suggestions.
Kris A. Schneider
---------------------------------------------------------------------
Net Xerox 800 Phillips Rd.
kris.wbst129@xerox.com Kris:Wbst129:Xerox Xerox Corp.
716.422.5013 8*222-5013 (x25013) Mail Stop: 129-39A
Webster, NY 14580
---------------------------------------------------------------------
Article 12779 of comp.lang.lisp:
Xref: glinda.oz.cs.cmu.edu comp.lang.lisp:12779
Path: honeydew.srv.cs.cmu.edu!nntp.club.cc.cmu.edu!newsfeed.pitt.edu!gatech!swrinde!cs.utexas.edu!usc!nic-nac.CSU.net!charnel.ecst.csuchico.edu!olivea!koriel!news2me.EBay.Sun.COM!cronkite.Central.Sun.COM!sixgun.East.Sun.COM!brinkley.East.Sun.COM!dr-pepper.East.Sun.COM!eastnews!pnorvig
From: pnorvig@norvig.eastnews (Peter Norvig)
Newsgroups: comp.lang.lisp
Subject: Re: Efficient way to generate permutations?
Date: 12 May 1994 13:53:49 GMT
Organization: Sun Microsystems Laboratories Inc.
Lines: 5
Message-ID: <PNORVIG.94May12095349@norvig.eastnews>
References: <1994May11.205732.19694@news.wrc.xerox.com>
NNTP-Posting-Host: norvig.east.sun.com
In-reply-to: kris%.wbst129@xerox.com's message of Wed, 11 May 1994 20:57:32 GMT
(defun permute (vector)
(loop for i from (length vector) downto 1 do
(rotatef (aref vector (- i 1)) (aref vector (random i))))
vector)
Article 12780 of comp.lang.lisp:
Xref: glinda.oz.cs.cmu.edu comp.lang.lisp:12780
Path: honeydew.srv.cs.cmu.edu!nntp.club.cc.cmu.edu!newsfeed.pitt.edu!gatech!howland.reston.ans.net!xlink.net!sbusol.rz.uni-sb.de!sbusol.rz.uni-sb.de!usenet
From: nesmith@cs.uni-sb.de (Daniel Nesmith)
Newsgroups: comp.lang.lisp
Subject: Re: Efficient way to generate permutations?
Date: 12 May 1994 21:14:18 GMT
Organization: CS Department, University of the Saarland
Lines: 44
Distribution: world
Message-ID: <2qu67aINNc6t@sbusol.rz.uni-sb.de>
References: <1994May11.205732.19694@news.wrc.xerox.com>
Reply-To: nesmith@cs.uni-sb.de
NNTP-Posting-Host: js-sfbslc10.cs.uni-sb.de
I would be inclined to do something like the following. ALL-PERMUTATIONS will
compute all permutations (here represented as lists), while RANDOM-PERMUTATION
will return a single random permutation.
(defun all-permutations (n)
"Returns a list of all permutations of the integers 1 .. N. Each
permutation is represented as a list. N must be an integer greater than 0."
(if (= n 1)
(list (list 1))
(let ((other-permutes
(all-permutations (1- n))))
;; for each permutation of 1 .. n-1, stick n in at all possible
;; places
(mapcan
#'(lambda (seq)
(let ((res-list nil))
(dotimes (i n res-list)
(push
(nconc (subseq seq 0 i)
(cons n
(subseq seq i)))
res-list))))
other-permutes))))
(defun random-permutation (n)
"Returns a list of the integers 1 .. N in some random permutation.
N must be an integer greater than 0."
(if (= n 1)
(list 1)
(let ((other-permute
(random-permutation (1- n)))
(i (random n)))
;; stick N in just before the I'th elt of OTHER-PERMUTE
(if (zerop i)
(cons n other-permute)
(let ((spot (nthcdr (1- i) other-permute)))
(setf (cdr spot) (cons n (cdr spot)))
other-permute)))))
Dan
Article 12836 of comp.lang.lisp:
Xref: glinda.oz.cs.cmu.edu comp.lang.lisp:12836
Path: honeydew.srv.cs.cmu.edu!nntp.club.cc.cmu.edu!godot.cc.duq.edu!news.duke.edu!convex!cs.utexas.edu!swrinde!ihnp4.ucsd.edu!library.ucla.edu!galaxy.ucr.edu!valiant!wilbur
From: wilbur@valiant.ucr.edu (Wilhelm Burger)
Newsgroups: comp.lang.lisp
Subject: Re: Efficient way to generate permutations?
Date: 17 May 1994 22:01:38 GMT
Organization: University of California, Riverside (Visualization and Intelligent Systems Laboratory)
Lines: 98
Message-ID: <2rbes2$6hn@galaxy.ucr.edu>
References: <1994May11.205732.19694@news.wrc.xerox.com> <2qu67aINNc6t@sbusol.rz.uni-sb.de>
NNTP-Posting-Host: valiant.ucr.edu
Hi,
Here is what I did some time back to go through *all* permutations
efficiently. Please keep me updated on other solutions.
Good luck and best regards,
Wilhelm.
;;;-----------------------------------------------------------------------------
;;; Author: Wilhelm Burger (wilbur@constitution.ucr.edu)
;;;-----------------------------------------------------------------------------
(in-package 'user)
(defun make-permutation-vector (n)
(let ((perm (make-array n :element-type 'fixnum
:initial-contents
(loop for i from 0 to (1- n) collect i))))
perm))
(defmacro swap-elements (vector i j)
`(setf (aref ,vector ,i)
(prog1
(aref ,vector ,j)
(setf (aref ,vector ,j) (aref ,vector ,i))))
)
(defun next-permutation (in-perm &optional data-vector)
(declare (type (simple-array fixnum (*)) in-perm))
;in-perm is an integer vector
(let* ((n (1- (length in-perm))) ;n ... max.index
(i (1- n)) (first nil))
(declare (fixnum i n))
(setq i
(do ((ii (1- n) (1- ii)))
((or (< ii 0) (<= (aref in-perm ii) (aref in-perm (1+ ii)))) ii)
(declare (fixnum ii))))
(setq first (< i 0))
(do ((j (1+ i) (1+ j))
(k n (1- k)))
((>= j k) j)
(declare (fixnum j k))
(swap-elements in-perm j k)
(when data-vector (swap-elements data-vector j k)))
(unless first
(let ((j
(do ((jj (1+ i) (1+ jj)))
((>= (aref in-perm jj) (aref in-perm i)) jj)
(declare (fixnum jj)))))
(declare (fixnum j))
(swap-elements in-perm i j)
(when data-vector (swap-elements data-vector i j))))
(values in-perm first))
)
;;;-----------------------------------------------------------------------------
(defmacro with-permutations ((data-vector &optional permutation-var iteration-var)
&rest body)
;; data-vector is the vector to be permuted - it is destructively used
;; but returned in the original order
;; permutation-var can be used to access the current permutation vector
;; iteration-var can be used to access the current permutation number
(let ((permv (or permutation-var (gensym "permv")))
(iterv (or iteration-var (gensym "iterv")))
(dvsym (gensym "dv"))
(nsym (gensym "n")))
`(let*
((,dvsym ,data-vector)
(,nsym (length ,dvsym))
(,permv (make-array ,nsym :element-type 'fixnum
:initial-contents
(loop for i from 0 to (1- ,nsym) collect i))))
(do ((_done nil) (,iterv 0 (1+ ,iterv))) (_done ,iterv)
,@body
(multiple-value-setq (,permv _done)
(next-permutation ,permv ,dvsym))
)))
)
#|
(let ((pv (make-permutation-vector 4))
(*print-array* t))
(with-permutations (pv)
(print pv)))
|#
--
W. Burger, College of Engineering, Univ. of California, Riverside
Email: wilbur@constitution.ucr.edu Tel: (909) 787-2299 or 6383
Article 12866 of comp.lang.lisp:
Xref: glinda.oz.cs.cmu.edu comp.lang.lisp:12866
Path: honeydew.srv.cs.cmu.edu!nntp.club.cc.cmu.edu!godot.cc.duq.edu!news.duke.edu!MathWorks.Com!news2.near.net!info-server.bbn.com!news
From: chyde@bbn.com
Newsgroups: comp.lang.lisp
Subject: RE: Efficient way to generate permutations?
Date: 20 May 1994 19:27:05 GMT
Organization: Bolt, Beranek and Newman Inc.
Lines: 31
Message-ID: <2rj2u9$59s@info-server.bbn.com>
Reply-To: chyde@bbn.com
NNTP-Posting-Host: exploder.bbn.com
In-reply-to: <2qu67aINNc6t@sbusol.rz.uni-sb.de>
of course, Peter N's way was interestingly elegant...here's a different
way: make a list of N integers (or an array and just use the indices)
randomly select an element of the list and push it onto a new list,
removing it from the old list. loop until original list is empty.
I suspect that there's something wrong with this as you get close to the
end, having to do with the randomness decreasing, but maybe not...
(let ((n 10)
(start)
j
(result ()))
(dotimes (i N)
(push i start))
(dotimes (i N)
(setq j (random (- N i)))
(push (elt start j) result)
(setq start (remove (elt start j) start))
)
(print result)
)
the effect you want to get is sort of the opposite of a SORT, so it
might be that an UNSORT mechanism is the right thing, which seems to
feel like Peter's example...
-- clint
|