1 | % (c) 2025-2025 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(bit_sets,[ordlist_to_bitset/2, bitset_to_ordlist/2, | |
6 | member_bitset/2, | |
7 | empty_bit_set/1, | |
8 | bitset_union/3, bitset_intersection/3]). | |
9 | ||
10 | :- use_module(module_information). | |
11 | :- module_info(group,kernel). | |
12 | :- module_info(description,'This module packs and upacks sets as integers.'). | |
13 | ||
14 | % uses less memory | |
15 | % intersection and union are faster | |
16 | % membership is slower | |
17 | ||
18 | empty_bit_set(0). | |
19 | ||
20 | ordlist_to_bitset(ListOfInts,Integer) :- | |
21 | pack_list_aux(ListOfInts,0,Integer). | |
22 | ||
23 | % Note: until max_tagged_pow2(MaxBound) this will result in a tagged integer; otherwise we get multi-precision ints | |
24 | pack_list_aux([],A,A). | |
25 | pack_list_aux([Nr|T],Acc,Res) :- | |
26 | NewAcc is Acc \/ (1<<Nr), | |
27 | pack_list_aux(T,NewAcc,Res). | |
28 | ||
29 | bitset_to_ordlist(PackedInteger,ResList) :- | |
30 | unpack_fd_set_aux(PackedInteger,0,ResList). | |
31 | ||
32 | unpack_fd_set_aux(0,_,Res) :- !, Res=[]. | |
33 | %xunpack_fd_set_aux(Nr,X,Res) :- | |
34 | % M is Nr mod 4, | |
35 | % ( (M=1 ; M=3) -> Res = [X|T] ; Res=T), | |
36 | % ( (M=0 ; M=1) | |
37 | % -> X1 is X+2, Nr1 is (Nr>>2) | |
38 | % ; X1 is X+1, Nr1 is (Nr>>1) | |
39 | % ), | |
40 | % unpack_fd_set_aux(Nr1,X1,T). | |
41 | ||
42 | unpack_fd_set_aux(Nr,X,Res) :- Nr mod 32 =:= 0,!, | |
43 | X1 is X+5, Nr1 is (Nr>>5), | |
44 | unpack_fd_set_aux(Nr1,X1,Res). | |
45 | unpack_fd_set_aux(Nr,X,Res) :- Nr mod 8 =:= 0,!, | |
46 | X1 is X+3, Nr1 is (Nr>>3), | |
47 | unpack_fd_set_aux(Nr1,X1,Res). | |
48 | unpack_fd_set_aux(Nr,X,Res) :- | |
49 | (Nr mod 2 =:= 1 -> Res = [X|T] ; Res=T), | |
50 | X1 is X+1, Nr1 is (Nr>>1), | |
51 | unpack_fd_set_aux(Nr1,X1,T). | |
52 | ||
53 | bitset_intersection(BSet1,BSet2,Inter) :- | |
54 | Inter is BSet1 /\ BSet2. | |
55 | ||
56 | bitset_union(BSet1,BSet2,Inter) :- | |
57 | Inter is BSet1 \/ BSet2. | |
58 | ||
59 | member_bitset(Nr,BitSet) :- integer(Nr),!, | |
60 | member_grchk_bitset(Nr,BitSet). | |
61 | %member_bitset(Nr,BitSet) :- bitset_to_ordlist(BitSet,OL), member(Nr,OL). % strange: seems slightly faster? | |
62 | member_bitset(Nr,BitSet) :- | |
63 | ? | mem_bitset_aux(Nr,0,BitSet). |
64 | ||
65 | mem_bitset_aux(Nr,Index,BitSet) :- BitSet mod 32 =:= 0,!, BitSet \= 0, B1 is BitSet >> 5, I1 is Index+5, | |
66 | ? | mem_bitset_aux(Nr,I1,B1). |
67 | mem_bitset_aux(Nr,Index,BitSet) :- BitSet mod 8 =:= 0,!, BitSet \= 0, B1 is BitSet >> 3, I1 is Index+3, | |
68 | ? | mem_bitset_aux(Nr,I1,B1). |
69 | mem_bitset_aux(Nr,Index,BitSet) :- BitSet mod 2 =:= 1, Nr=Index. | |
70 | mem_bitset_aux(Nr,Index,BitSet) :- BitSet \= 0, B1 is BitSet >> 1, I1 is Index+1, | |
71 | ? | mem_bitset_aux(Nr,I1,B1). |
72 | ||
73 | % check if a ground Nr is element of a bitset | |
74 | member_grchk_bitset(Nr,BitSet) :- | |
75 | 0 =\= BitSet /\ (1<<Nr). | |
76 | ||
77 | % use_module(probsrc(bit_sets)), ordlist_to_bitset([1,10,20],B1), bitset_intersection(B1,B1,B2), bitset_to_ordlist(B2,L2), member_bitset(N,B2). | |
78 | ||
79 | ||
80 | test(N) :- L = [1,20,21,23, 44,50,51], | |
81 | tools:start_ms_timer(T1), | |
82 | t1(N,L,R), | |
83 | tools:stop_ms_timer_with_msg(T1,test1_inter(N,R)), | |
84 | ordlist_to_bitset(L,B), | |
85 | tools:start_ms_timer(T1b), | |
86 | t1bs(N,B,RBS), bitset_to_ordlist(RBS,R1BS), | |
87 | tools:stop_ms_timer_with_msg(T1b,test1_bitset(N,RBS,R1BS)), | |
88 | tools:start_ms_timer(T2), | |
89 | t2(N,L,R2), | |
90 | tools:stop_ms_timer_with_msg(T2,test2_member(N,R2)), | |
91 | tools:start_ms_timer(T2b), | |
92 | t2bs(N,B,R22), | |
93 | tools:stop_ms_timer_with_msg(T2b,test2_bitset(N,R22)). | |
94 | ||
95 | t1(0,A,A) :- !. | |
96 | t1(N,A,R) :- ordsets:ord_intersection(A,A,A1), ordsets:ord_intersection(A1,A1,A2), | |
97 | N1 is N-1, t1(N1,A2,R). | |
98 | t1bs(0,A,A) :- !. | |
99 | t1bs(N,A,R) :- bitset_intersection(A,A,A1), bitset_intersection(A1,A1,A2), | |
100 | N1 is N-1, t1bs(N1,A2,R). | |
101 | % use_module(probsrc(bit_sets)), bit_sets:test(100000). | |
102 | % Runtime for test1(1000000,[1,20,21,23,44,50,51]): 442 ms (with gc: 476 ms, walltime: 478 ms); since start: 2 h 15 min 18 sec 395 ms | |
103 | % Runtime for test1_bitset(1000000,3395291918106626,[1,20,21,23,44,50,51]): 34 ms (with gc: 34 ms, walltime: 34 ms); since start: 2 h 15 min 18 sec 429 ms | |
104 | ||
105 | t2(0,A,R) :- member(R,A),!. | |
106 | t2(N,A,R) :- (member(I,A), I=N -> true ; true), | |
107 | N1 is N-1, t2(N1,A,R). | |
108 | t2bs(0,A,R) :- member_bitset(R,A),!. | |
109 | t2bs(N,A,R) :- (member_bitset(I,A), I=N -> true ; true), | |
110 | N1 is N-1, t2bs(N1,A,R). | |
111 | ||
112 | % Runtime for test2_member(1000000,1): 149 ms (with gc: 149 ms, walltime: 149 ms); since start: 3 h 29 min 29 sec 541 ms | |
113 | % Runtime for test2_bitset(1000000,1): 1896 ms (with gc: 1896 ms, walltime: 1903 ms); since start: 3 h 29 min 31 sec 444 ms |