[m-dev.] diff: random permutations
Zoltan Somogyi
zs at cs.mu.OZ.AU
Mon Jan 3 16:23:25 AEDT 2000
I am committing this now because the new predicate I am adding is used in
some of the tabling test cases I am about to commit. If anyone wishes to
make improvements, such as using arrays instead of maps, go ahead.
library/random.m:
Add a predicate for computing a random permutation of the first N
integers.
Zoltan.
Index: random.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/random.m,v
retrieving revision 1.16
diff -u -b -r1.16 random.m
--- random.m 1998/10/28 23:18:42 1.16
+++ random.m 2000/01/03 05:16:01
@@ -43,6 +43,12 @@
:- pred random__randmax(int, random__supply, random__supply).
:- mode random__randmax(out, mdi, muo) is det.
+ % random__permutation(Num, List, RS0, RS): binds List to a
+ % random permutation of the numbers in the range 0 .. Num - 1,
+ % and binds RS to the new state of the random number supply.
+:- pred random__permutation(int, list(int), random__supply, random__supply).
+:- mode random__permutation(in, out, mdi, muo) is det.
+
%---------------------------------------------------------------------------%
:- implementation.
@@ -59,7 +65,7 @@
%---------------------------------------------------------------------------%
:- implementation.
-:- import_module int.
+:- import_module int, map.
:- type random__supply == int. % I(j)
@@ -82,6 +88,54 @@
M1 is M - 1.
%---------------------------------------------------------------------------%
+
+ % The random permutation is implemented via a "sampling without
+ % replacement" method. In init_record, we build up a map in which
+ % every integer in the range 0 .. Num - 1 is mapped to itself. The
+ % sampling stage iterates from Num - 1 down to 0. The invariant being
+ % maintained is that at iteration I, the numbers in the image of
+ % the part of the map indexed by 0 .. I-1 are the numbers that have
+ % not been selected yet. At each iteration, perform_sampling generates
+ % a random number Index in the range 0 .. I-1, adds the number that
+ % Index is mapped to, Next, to the permutation, and then ensures that
+ % Next is not generated again by swapping it with the image of I-1.
+
+random__permutation(Num, List, RS0, RS) :-
+ map__init(Empty),
+ init_record(Num, Empty, Samples0),
+ perform_sampling(Num, Samples0, [], List, RS0, RS).
+
+:- pred init_record(int::in, map(int, int)::in, map(int, int)::out) is det.
+
+init_record(N, Record0, Record) :-
+ ( N =< 0 ->
+ Record = Record0
+ ;
+ N1 = N - 1,
+ map__det_insert(Record0, N1, N1, Record1),
+ init_record(N1, Record1, Record)
+ ).
+
+:- pred perform_sampling(int::in, map(int, int)::in,
+ list(int)::in, list(int)::out,
+ random__supply::mdi, random__supply::muo) is det.
+
+perform_sampling(I, Record0, Order0, Order, RS0, RS) :-
+ ( I =< 0 ->
+ Order = Order0,
+ RS = RS0
+ ;
+ I1 = I - 1,
+ random__random(Random, RS0, RS1),
+ Index = Random mod I,
+ map__lookup(Record0, Index, Next),
+ map__lookup(Record0, I1, MaxImage),
+ Order1 = [Next | Order0],
+ map__det_update(Record0, Index, MaxImage, Record1),
+ map__det_update(Record1, I1, Next, Record2),
+ perform_sampling(I1, Record2, Order1, Order, RS1, RS)
+ ).
+
%---------------------------------------------------------------------------%
random__test(Seed, N, Nums, Max) :-
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list