1 % (c) 2009-2026 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(random_permutations, [get_num_bits/3,
6 get_masks/3,
7 random_permutation_element/10,
8 init_random_permutations/0,
9
10 enum_fd_random/3 % high-level predicate
11 ]).
12
13 :- use_module(probsrc(module_information),[module_info/2]).
14 :- module_info(group,cbc).
15 :- module_info(description,'This module provides on-the-fly construction of random permutations of intervals.').
16
17 foreign_resource(random_permutations,[get_num_bits,draw_index]).
18 foreign(get_num_bits, c, get_num_bits(+integer,-integer,-integer)).
19 foreign(draw_index, c, draw_index(+integer,+integer,+integer,+integer,+integer,+integer,+integer,+integer,-integer,-integer)).
20
21 :- dynamic is_initialised/0.
22
23 :- use_module(probsrc(pathes_lib),[safe_load_foreign_resource/2]).
24
25 init_random_permutations :- is_initialised,!.
26 init_random_permutations :-
27 safe_load_foreign_resource(random_permutations,random_permutations),
28 assertz(is_initialised).
29
30
31 get_masks(HalfNumBits,LeftMask,RightMask) :-
32 RightMask is (1 << HalfNumBits) - 1,
33 LeftMask is RightMask << HalfNumBits.
34
35 random_permutation_element(Index,MaxIndex,From,To,Seed,NumBits,LeftMask,RightMask,RandomElement,NextIndex) :-
36 draw_index(Index,MaxIndex,Seed,NumBits,LeftMask,RightMask,From,To,DrawnElement,NextIndex),
37 % working on a 4^x long interval. thus, we might pick a number that is too large
38 % if this happens, we just pick a new one
39 % to avoid context switching overhead, this is now done inside the C code
40 RandomElement is DrawnElement + From.
41
42
43 :- use_module(library(random),[random/1]).
44 % enumerate Prolog/FD variable between low and up in random order
45 % in SICStus 4.10 we have random labeling option which does the same; but seems much slower
46 % | ?- statistics(walltime,_),(random_permutations:enum_fd_random(Var,1,200000),fail ; statistics(walltime,W)).
47 % W = [141558,50] ?
48 % | ?- statistics(walltime,_),(X in 1..2000, labeling([random],[X]), fail ; statistics(walltime,W)).
49 % W = [372383,34] ?
50 % | ?- statistics(walltime,_),(X in 1..20000, labeling([random],[X]), fail ; statistics(walltime,W)).
51 % W = [118049,1943] ?
52 % | ?- statistics(walltime,_),(X in 1..200000, labeling([random],[X]), fail ; statistics(walltime,W)).
53 % W = [323412,198936] ?
54 enum_fd_random(Var,Low,Up) :-
55 init_random_permutations,
56 IntervalLength is Up - Low + 1,
57 get_num_bits(IntervalLength,MaxIdx,NumBits),
58 get_masks(NumBits,LeftMask,RightMask),
59 % the seed relies on the random predicate, not on now/1,
60 % thus prob can be made deterministic by setting a central random seed
61 random(TempSeed),
62 Seed is floor(TempSeed * 10000),
63 ? enum_fd_random_aux(Var,0,MaxIdx,Low,Up,Seed,NumBits,LeftMask,RightMask).
64
65 enum_fd_random_aux(Var,CurIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask) :-
66 random_permutation_element(CurIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask,Drawn,NextIdx),
67 ? (Var=Drawn ; enum_fd_random_aux(Var,NextIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask)).
68
69
70 % -------------------
71 % Testing predicates
72 % -------------------
73 % unused at the moment:
74 %:- public shuffle/2.
75 %:- use_module(library(system)).
76 %shuffle(From,To) :-
77 % init_random_permutations,
78 % IntervalLength is To - From + 1,
79 % get_num_bits(IntervalLength,MaxIndex,NumBits),
80 % get_masks(NumBits,LeftMask,RightMask),
81 % now(Seed),
82 % shuffle(From,0,To,MaxIndex,Seed,NumBits,LeftMask,RightMask).
83 %shuffle(From,CurIdx,To,MaxIndex,Seed,NumBits,LeftMask,RightMask) :-
84 % random_permutation_element(CurIdx,MaxIndex,From,To,Seed,NumBits,LeftMask,RightMask,Drawn,NextIdx),
85 % format('Drawing index ~w resulted in ~w~n',[CurIdx,Drawn]),
86 % shuffle(From,NextIdx,To,MaxIndex,Seed,NumBits,LeftMask,RightMask).
87 %shuffle(_,_,_,_,_,_,_,_).