1 | % (c) 2009-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(kernel_card_arithmetic,[is_inf_or_overflow_card/1, is_finite_card/1, | |
6 | safe_pow2/2, safe_pown/3, | |
7 | safe_add_card/3, blocking_add_card/3, | |
8 | safe_mul/3, | |
9 | safe_minus/3, blocking_factorial/2, blocking_factorial_k/3, | |
10 | choose_nk/3, | |
11 | blocking_nr_iseq/2, blocking_nr_iseq1/2, | |
12 | total_relation_card/3, partial_bijection_card/3, | |
13 | partial_surjection_card/3, total_surjection_card/3, | |
14 | partial_injection_card/3]). | |
15 | ||
16 | ||
17 | :- use_module(module_information). | |
18 | :- module_info(group,kernel). | |
19 | :- module_info(description,'This module contains cardinality arithmetic that also supports the symbol inf and inf_overflow.'). % in future we may support other ordinals to distinguish countable and uncountable sets | |
20 | ||
21 | :- use_module(error_manager). | |
22 | :- use_module(debug). | |
23 | :- use_module(self_check). | |
24 | ||
25 | :- assert_must_succeed((safe_pow2(3,R),R==8)). | |
26 | :- assert_must_succeed((safe_pow2(inf,R),R==inf)). | |
27 | :- assert_must_succeed((safe_pow2(inf_overflow,R),R==inf_overflow)). | |
28 | :- assert_must_succeed((safe_pow2(3072,R),R==inf_overflow)). | |
29 | :- assert_must_succeed((safe_pow2(18446744073709551616,R),R==inf_overflow)). | |
30 | :- assert_must_succeed((safe_pow2(500,X), safe_pow2(501,X2), X2 is 2*X)). | |
31 | % :- assert_must_succeed((kernel_objects:safe_pow2(1022,X), kernel_objects:safe_pow2(1023,X2), X2 is 2*X)). | |
32 | ||
33 | set_inf_due_to_overflow(Res) :- debug_println(9,'** OVERFLOW (cardinality)**'),Res=inf_overflow. | |
34 | %set_inf_due_to_overflow(Res) :- Res=inf. | |
35 | ||
36 | safe_pow2(Exp,Res) :- | |
37 | (Exp==inf -> Res=inf | |
38 | ; Exp==inf_overflow -> Res=inf_overflow | |
39 | ; Exp>1023 /* the limit where SICStus 4.2.1 reported inf; 4.2.3 goes further but uses a huge amount of memory */ | |
40 | -> set_inf_due_to_overflow(Res) | |
41 | ; Res is 2^Exp % ^ integer exponentiation operator new in SICStus 4.3 | |
42 | ). | |
43 | ||
44 | :- assert_must_succeed((safe_pown(3,2,R),R==9)). | |
45 | :- assert_must_succeed((safe_pown(2,3072,R),R==inf_overflow)). | |
46 | :- assert_must_succeed((safe_pown(3,647,R),R==inf_overflow)). | |
47 | :- assert_must_succeed((safe_pown(2,500,X), safe_pown(2,501,X2), X2 is 2*X)). | |
48 | :- assert_must_succeed((safe_pown(2,500,X), safe_pow2(500,X))). | |
49 | :- assert_must_succeed((safe_pown(2,1022,X), safe_pown(2,1023,X2), X2 is 2*X)). | |
50 | :- assert_must_succeed((safe_pown(3,500,X), safe_pown(3,501,X3), X3 is 3*X)). | |
51 | :- assert_must_succeed((safe_pown(inf,2,R),R==inf)). | |
52 | :- assert_must_succeed((safe_pown(inf,inf,R),R==inf)). | |
53 | :- assert_must_succeed((safe_pown(inf_overflow,2,R),R==inf_overflow)). | |
54 | :- assert_must_succeed((safe_pown(2,inf,R),R==inf)). | |
55 | :- assert_must_succeed((safe_pown(2,inf_overflow,R),R==inf_overflow)). | |
56 | :- assert_must_succeed((safe_pown(inf_overflow,inf,R),R==inf)). | |
57 | :- assert_must_succeed((safe_pown(inf_overflow,inf_overflow,R),R==inf_overflow)). | |
58 | safe_pown(Base,Exp,Res) :- | |
59 | ( Base=inf -> (Exp=0 -> Res=1 ; Res=Base) | |
60 | ; Exp=inf -> (Base=0 -> Res=0 ; Base=1 -> Res=1 ; Res=Exp) | |
61 | ; Base=inf_overflow -> (Exp=0 -> Res=1 ; Res=Base) | |
62 | ; Exp=inf_overflow -> (Base=0 -> Res=0 ; Base=1 -> Res=1 ; Res=Exp) | |
63 | ; infinite_pown(Base,Exp) /* SICStus 4.2.1 reported inf; 4.2.3 goes further but uses a huge amount of memory */ | |
64 | -> set_inf_due_to_overflow(Res) | |
65 | ; Res is Base ^ Exp % ^ integer exponentiation operator new in SICStus 4.3 | |
66 | ). | |
67 | ||
68 | /* SICStus 4.2.1 reported inf; 4.2.3 goes further but uses a huge amount of memory */ | |
69 | infinite_pown(Base,Exp) :- Exp > 1023, !, Base >= 2. | |
70 | infinite_pown(Base,Exp) :- Exp > 646, !, Base >= 3. % was not really necessary when using overflow_float_pown | |
71 | infinite_pown(Base,Exp) :- Exp > 511, !, Base >= 4. | |
72 | infinite_pown(Base,Exp) :- Exp > 441, !, Base >= 5. | |
73 | ||
74 | is_inf_or_overflow_card(inf). | |
75 | is_inf_or_overflow_card(inf_overflow). | |
76 | ||
77 | is_finite_card(Card) :- number(Card). | |
78 | ||
79 | ||
80 | :- assert_must_succeed((safe_mul(3,2,R),R==6)). | |
81 | :- assert_must_succeed((safe_mul(inf,2,R),R==inf)). | |
82 | :- assert_must_succeed((safe_mul(2,inf,R),R==inf)). | |
83 | :- assert_must_succeed((safe_mul(0,inf,R),R==0)). | |
84 | :- assert_must_succeed((safe_mul(inf,0,R),R==0)). | |
85 | % safe_multiplication for positive numbers | |
86 | safe_mul(0,_,R) :- !, R=0. % true for cartesian product: card({}*INTEGER)=0 | |
87 | safe_mul(_,0,R) :- !, R=0. % ditto | |
88 | safe_mul(inf,_,R) :- !, R=inf. | |
89 | safe_mul(_,inf,R) :- !, R=inf. | |
90 | safe_mul(inf_overflow,_,R) :- !, R=inf_overflow. | |
91 | safe_mul(_,inf_overflow,R) :- !, R=inf_overflow. | |
92 | safe_mul(X,Y,R) :- is_overflowcheck(R,X*Y). | |
93 | ||
94 | :- assert_must_succeed((safe_add_card(3,100,R),R==103)). | |
95 | :- assert_must_succeed((safe_add_card(inf,100,R),R==inf)). | |
96 | :- assert_must_succeed((safe_add_card(inf,inf_overflow,R),R==inf)). | |
97 | :- assert_must_succeed((safe_add_card(inf_overflow,inf,R),R==inf)). | |
98 | :- assert_must_succeed((safe_add_card(inf_overflow,2,R),R==inf_overflow)). | |
99 | safe_add_card(inf,_,R) :- !, R=inf. | |
100 | safe_add_card(_,inf,R) :- !, R=inf. | |
101 | safe_add_card(inf_overflow,_,R) :- !, R=inf_overflow. | |
102 | safe_add_card(_,inf_overflow,R) :- !, R=inf_overflow. | |
103 | safe_add_card(X,Y,R) :- is_overflowcheck(R,X+Y). | |
104 | ||
105 | ||
106 | /* is with overflow check */ | |
107 | is_overflowcheck(Var,Expr) :- | |
108 | (Expr=inf -> Var=inf | |
109 | ; catch(Var is Expr, error(_,_), | |
110 | set_inf_due_to_overflow(Var)) % optionally add enumeration warning in scope | |
111 | ). | |
112 | ||
113 | :- assert_must_succeed((blocking_add_card(3,100,R),R==103)). | |
114 | :- assert_must_succeed((blocking_add_card(inf,100,R),R==inf)). | |
115 | :- assert_must_succeed((blocking_add_card(inf,inf_overflow,R),R==inf)). | |
116 | :- assert_must_succeed((blocking_add_card(inf_overflow,inf,R),R==inf)). | |
117 | :- assert_must_succeed((blocking_add_card(inf_overflow,2,R),R==inf_overflow)). | |
118 | ||
119 | % add two cardinalities together: can be number or inf | |
120 | :- block blocking_add_card(-,-,?). | |
121 | blocking_add_card(X,Y,R) :- X==0,!,R=Y. | |
122 | blocking_add_card(X,Y,R) :- Y==0,!,R=X. | |
123 | blocking_add_card(X,_,R) :- X==inf,!,R=inf. | |
124 | blocking_add_card(_,Y,R) :- Y==inf,!,R=inf. | |
125 | blocking_add_card(X,Y,R) :- add_card2(X,Y,R). | |
126 | ||
127 | :- block add_card2(-,?,?), add_card2(?,-,?). | |
128 | add_card2(A,B,R) :- safe_add_card(A,B,R). | |
129 | ||
130 | ||
131 | ||
132 | :- assert_must_succeed((safe_minus(506,501,R),R==5)). | |
133 | :- assert_must_succeed((safe_minus(inf,10,R),R==inf)). | |
134 | :- assert_must_succeed((safe_minus(10,inf,R),R==0)). | |
135 | % subtraction of two positive numbers, supposing first number >= second one | |
136 | :- block safe_minus(-,?,?), safe_minus(?,-,?). | |
137 | safe_minus(_,inf,R) :- !, print('### Warning: cannot compute X - inf'),nl, R=0. | |
138 | safe_minus(inf,_,R) :- !, R=inf. | |
139 | safe_minus(_,inf_overflow,R) :- !, print('### Warning: cannot compute X - inf_overflow'),nl, R=0. | |
140 | safe_minus(inf_overflow,_,R) :- !, R=inf_overflow. | |
141 | safe_minus(X,Y,R) :- R is X-Y. | |
142 | ||
143 | ||
144 | /* | |
145 | % this code below would sometimes fail in spld generated code: | |
146 | is_overflowcheck_old(Var,Expr) :- print(is_with_overflow(Var,Expr)),nl, | |
147 | (Expr=inf -> Var=inf | |
148 | ; catch( | |
149 | catch( | |
150 | Var is Expr, | |
151 | error(evaluation_error(float_overflow),_), | |
152 | (print(float_overflow),nl,Var = inf)), | |
153 | error(type_error(evaluable,inf/0),_), | |
154 | (print(evaluable_inf),nl,Var=inf))). | |
155 | % catches any exception (e.g. also representation_error when converting inf to integer) | |
156 | % could be unsafe with timeout !! | |
157 | is_errc(Var,Expr) :- | |
158 | (Expr=inf -> Var=inf | |
159 | ; safe_on_exception(_E, Var is Expr, Var = inf)). | |
160 | */ | |
161 | ||
162 | ||
163 | ||
164 | :- assert_must_succeed((blocking_factorial(5,R),R==120)). | |
165 | :- assert_must_succeed((blocking_factorial(0,R),R==1)). | |
166 | :- assert_must_succeed((blocking_factorial(1,R),R==1)). | |
167 | :- assert_must_succeed((blocking_factorial(3,R),R==6)). | |
168 | :- assert_must_succeed((blocking_factorial(inf,R),R==inf)). | |
169 | :- block blocking_factorial(-,?). | |
170 | blocking_factorial(inf,R) :- !, R=inf. | |
171 | blocking_factorial(inf_overflow,R) :- !, R=inf_overflow. | |
172 | blocking_factorial(X,R) :- X<0,!, add_error(blocking_factorial,'Negative arg: ',blocking_factorial(X,R)),R=0. | |
173 | blocking_factorial(X,R) :- X>1000,!, | |
174 | % here we overapproximate: throw finite warning in Disprover mode ? or when checking for finite | |
175 | set_inf_due_to_overflow(R). | |
176 | % Note: blocking_safe_pow2(X,R) reports inf for X>1023; for X=171 blocking_factorial gives a result | |
177 | % which is greater than 2**1024 : | |
178 | % X=171,blocking_factorial(X,R),blocking_safe_pow2(1023,R2), R>2*R2. | |
179 | % debug:time(fact(10000,1,_)) --> 170 ms | |
180 | % debug:time(fact(1000,1,_)) --> 0 ms | |
181 | blocking_factorial(A,Res) :- fact(A,1,Res). | |
182 | ||
183 | fact(0,Acc,Res) :- !,Res=Acc. | |
184 | fact(N,Acc,Res) :- (is_inf_or_overflow_card(Acc) -> Res=Acc | |
185 | ; safe_mul(N,Acc,NAcc), N1 is N-1, fact(N1,NAcc,Res)). | |
186 | ||
187 | ||
188 | ||
189 | :- assert_must_succeed((blocking_factorial_k(5,5,R),R==120)). | |
190 | :- assert_must_succeed((blocking_factorial_k(5,2,R),R==20)). | |
191 | :- assert_must_succeed((blocking_factorial_k(5,1,R),R==5)). | |
192 | :- assert_must_succeed((blocking_factorial_k(5,0,R),R==1)). | |
193 | :- assert_must_succeed((blocking_factorial_k(5,3,R),R==60)). | |
194 | :- assert_must_succeed((blocking_factorial_k(5,4,R),R==120)). | |
195 | :- assert_must_succeed((blocking_factorial_k(5,6,R),R==0)). | |
196 | :- assert_must_succeed((blocking_factorial_k(0,0,R),R==1)). | |
197 | :- assert_must_succeed((blocking_factorial_k(0,1,R),R==0)). | |
198 | :- assert_must_succeed((blocking_factorial_k(1,1,R),R==1)). | |
199 | :- assert_must_succeed((blocking_factorial_k(2,1,R),R==2)). | |
200 | :- assert_must_succeed((blocking_factorial_k(2,2,R),R==2)). | |
201 | :- assert_must_succeed((blocking_factorial_k(3,3,R),R==6)). | |
202 | :- assert_must_succeed((blocking_factorial_k(inf,1,R),R==inf)). | |
203 | :- assert_must_succeed((blocking_factorial_k(inf,0,R),R==1)). | |
204 | :- assert_must_succeed((blocking_factorial_k(inf,inf,R),R==inf)). | |
205 | :- assert_must_succeed((blocking_factorial_k(2,inf,R),R==0)). | |
206 | % blocking_factorial_k(N,K,Res) :: Res = N*(N-1)*...*(N-K+1) | |
207 | % Number of ways to choose sequences of K different objects amongst a pool of N objects | |
208 | :- block blocking_factorial_k(-,?,?),blocking_factorial_k(?,-,?). | |
209 | blocking_factorial_k(_X,0,R) :- !, R=1. | |
210 | blocking_factorial_k(inf,_,R) :- !, R=inf. | |
211 | blocking_factorial_k(_N,K,R) :- K=inf,!, R=0. % only finitely many _N | |
212 | blocking_factorial_k(inf_overflow,_,R) :- !, R=inf_overflow. | |
213 | blocking_factorial_k(_N,K,R) :- K=inf_overflow,!, R=0. | |
214 | blocking_factorial_k(N,K,R) :- K>N,!, R=0. | |
215 | blocking_factorial_k(A,K,Res) :- fact_k(A,K,1,Res). | |
216 | ||
217 | fact_k(0,_,Acc,Res) :- !, Res=Acc. | |
218 | fact_k(_,K,Acc,Res) :- K<1,!,Res=Acc. | |
219 | fact_k(N,K,Acc,Res) :- (is_inf_or_overflow_card(Acc) -> Res=Acc | |
220 | ; safe_mul(N,Acc,NAcc), N1 is N-1, K1 is K-1, fact_k(N1,K1,NAcc,Res)). | |
221 | ||
222 | ||
223 | ||
224 | :- assert_must_succeed((choose_nk(3,3,R),R==1)). | |
225 | :- assert_must_succeed((choose_nk(3,2,R),R==3)). | |
226 | :- assert_must_succeed((choose_nk(3,1,R),R==3)). | |
227 | :- assert_must_succeed((choose_nk(3,0,R),R==1)). | |
228 | :- block choose_nk(-,?,?), choose_nk(?,-,?). | |
229 | choose_nk(N,K,Res) :- (K=0;K=N),!,Res=1. | |
230 | choose_nk(N,K,Res) :- K > N/2,!, KN is N-K, choose_nk2(N,KN,Res). | |
231 | choose_nk(N,K,Res) :- choose_nk2(N,K,Res). | |
232 | choose_nk2(N,K,Res) :- blocking_factorial_k(N,K,NK), blocking_factorial(K,KF), | |
233 | safe_div(NK,KF,Res). | |
234 | ||
235 | :- assert_must_succeed((safe_div(inf,10,R),R==inf)). | |
236 | :- assert_must_succeed((safe_div(inf_overflow,10,R),R==inf_overflow)). | |
237 | :- assert_must_succeed((safe_div(inf_overflow,inf,R),R==0)). | |
238 | :- assert_must_succeed((safe_div(inf,inf_overflow,R),R==inf)). | |
239 | :- assert_must_succeed((safe_div(10,inf,R),R==0)). | |
240 | :- assert_must_succeed((safe_div(10,5,R),R==2)). | |
241 | :- assert_must_succeed((safe_div(10,6,R),R==1)). | |
242 | :- block safe_div(-,?,?), safe_div(?,-,?). | |
243 | safe_div(X,0,R) :- print(div_by_zero(X,0,R)),nl, !, R=inf. | |
244 | safe_div(inf,K,R) :- | |
245 | (number(K) -> true ; K=inf_overflow -> true ; print(safe_div(inf,K,R)),nl), !, R=inf. | |
246 | safe_div(_N,inf,R) :- !, R=0. | |
247 | safe_div(inf_overflow,K,R) :- | |
248 | (number(K) -> true ; print(safe_div(inf_overflow,K,R)),nl), !, R=inf_overflow. | |
249 | safe_div(_N,inf_overflow,R) :- !, R=0. | |
250 | safe_div(X,Y,Z) :- Z is X//Y. | |
251 | ||
252 | ||
253 | ||
254 | :- assert_must_succeed((blocking_nr_iseq(2,R),R==5)). | |
255 | :- assert_must_succeed((blocking_nr_iseq(0,R),R==1)). | |
256 | :- assert_must_succeed((blocking_nr_iseq(1,R),R==2)). | |
257 | :- assert_must_succeed((blocking_nr_iseq(3,R),R==16)). | |
258 | :- assert_must_succeed((blocking_nr_iseq(inf,R),R==inf)). | |
259 | :- assert_must_succeed((blocking_nr_iseq(inf_overflow,R),R==inf_overflow)). | |
260 | % number of injective sequences | |
261 | :- block blocking_nr_iseq(-,?). | |
262 | blocking_nr_iseq(inf,R) :- !, R=inf. | |
263 | blocking_nr_iseq(inf_overflow,R) :- !, R=inf_overflow. | |
264 | blocking_nr_iseq(X,R) :- X<0,!, add_error(blocking_nr_iseq,'Negative arg: ',blocking_nr_iseq(X,R)),R=0. | |
265 | blocking_nr_iseq(X,R) :- X>500,!, set_inf_due_to_overflow(R). | |
266 | % Note: blocking_safe_pow2(X,R) reports inf for X>1023; for X=171 blocking_nr_iseq gives a result | |
267 | % which is greater than 2**1024 : | |
268 | % X=171,blocking_nr_iseq(X,R),blocking_safe_pow2(1023,R2), R>2*R2. | |
269 | % debug:time(nr_iseq(10000,_)) --> 250 ms | |
270 | % debug:time(nr_iseq(1000,_)) --> 10 ms | |
271 | % debug:time(nr_iseq(500,_)) --> 0 ms | |
272 | blocking_nr_iseq(A,Res) :- nr_iseq(A,Res). % , print(nr_iseq(A,Res)),nl. | |
273 | % number of injective sequences: f(N) = 1+N*(f(N-1)) | |
274 | nr_iseq(0,Res) :- !,Res=1. | |
275 | nr_iseq(N,Res) :- N1 is N-1, nr_iseq(N1,N1Res), | |
276 | safe_mul(N,N1Res,NAcc), safe_add_card(NAcc,1,Res). | |
277 | ||
278 | :- assert_must_succeed((blocking_nr_iseq1(2,R),R==4)). | |
279 | :- assert_must_succeed((blocking_nr_iseq1(inf,R),R==inf)). | |
280 | :- assert_must_succeed((blocking_nr_iseq1(inf_overflow,R),R==inf_overflow)). | |
281 | :- public blocking_nr_iseq1/2. % used in card_for_member_closure | |
282 | % number of non-empty injective sequences | |
283 | :- block blocking_nr_iseq1(-,?). | |
284 | blocking_nr_iseq1(inf,R) :- !, R=inf. | |
285 | blocking_nr_iseq1(inf_overflow,R) :- !, R=inf_overflow. | |
286 | blocking_nr_iseq1(A,Res1) :- blocking_nr_iseq(A,Res) , safe_add_card(Res,-1,Res1). %, print(nr_iseq1(A,Res1)),nl. | |
287 | ||
288 | ||
289 | ||
290 | :- assert_must_succeed((total_relation_card(0,inf,R),R==1)). | |
291 | :- assert_must_succeed((total_relation_card(2,inf,R),R==inf)). | |
292 | :- assert_must_succeed((total_relation_card(inf,0,R),R==0)). | |
293 | :- assert_must_succeed((total_relation_card(inf,1,R),R==1)). | |
294 | :- assert_must_succeed((total_relation_card(inf,2,R),R==inf)). | |
295 | :- assert_must_succeed((total_relation_card(inf,inf,R),R==inf)). | |
296 | :- assert_must_succeed((total_relation_card(2,2,R),R==9)). | |
297 | :- assert_must_succeed((total_relation_card(2,3,R),R==49)). | |
298 | ||
299 | :- block total_relation_card(-,?,?), total_relation_card(?,-,?). | |
300 | total_relation_card(0,_RanC,Card) :- !, Card=1. % empty set is a solution | |
301 | total_relation_card(_DomC,0,Card) :- !, Card=0. % no element to choose from in the range | |
302 | total_relation_card(inf,RanC,Card) :- !, (RanC=1 -> Card=1 ; Card=inf). | |
303 | total_relation_card(_,inf,Card) :- !, Card=inf. | |
304 | total_relation_card(DomC,RanC,Card) :- safe_pow2(RanC,SubRan), | |
305 | safe_minus(SubRan,1,S1), % as we have a total relation we cannot choose empty set | |
306 | safe_pown(S1,DomC,Card). | |
307 | ||
308 | ||
309 | ||
310 | :- assert_must_succeed((partial_bijection_card(2,inf,R),R==0)). | |
311 | :- assert_must_succeed((partial_bijection_card(inf,2,R),R==inf)). | |
312 | :- assert_must_succeed((partial_bijection_card(inf,inf,R),R==inf)). | |
313 | :- assert_must_succeed((partial_bijection_card(3,2,R),R==6)). | |
314 | :- assert_must_succeed((partial_bijection_card(2,2,R),R==2)). | |
315 | :- assert_must_succeed((partial_bijection_card(1,2,R),R==0)). | |
316 | :- assert_must_succeed((partial_bijection_card(2,1,R),R==2)). | |
317 | :- assert_must_succeed((partial_bijection_card(5,3,R),R==60)). | |
318 | :- assert_must_succeed((partial_bijection_card(6,4,R),R==360)). | |
319 | :- assert_must_succeed((partial_bijection_card(10,1,R),R==10)). | |
320 | :- assert_must_succeed((partial_bijection_card(10,2,R),R==90)). | |
321 | ||
322 | :- use_module(inf_arith,[infless/2]). | |
323 | ||
324 | :- block partial_bijection_card(-,?,?), partial_bijection_card(?,-,?). | |
325 | partial_bijection_card(_X,0,R) :- !, R=1. % the empty set is a solution | |
326 | partial_bijection_card(inf,X,R) :- !, | |
327 | print_inf_warning(X,'>+>>'), % we could have : INTEGER >+>> POW(INTEGER); TO DO: use omega(inf) for POW ? | |
328 | R=inf. % we know _X>0 | |
329 | partial_bijection_card(DomCard,RanCard,Res) :- | |
330 | infless(DomCard,RanCard),!,Res=0. % -> no way to cover all elements in range | |
331 | partial_bijection_card(DomCard,RanCard,XCard) :- | |
332 | choose_nk(DomCard,RanCard,CNK), % ways to choose domain of size RanCard | |
333 | blocking_factorial(RanCard,Card), | |
334 | safe_mul(CNK,Card,XCard). | |
335 | ||
336 | print_inf_warning(inf,FUN) :- !, print('### WARNING: Assuming '), | |
337 | print(FUN), print(' exists for two infinite sets'),nl. | |
338 | print_inf_warning(_,_). | |
339 | ||
340 | ||
341 | ||
342 | ||
343 | :- assert_must_succeed((partial_surjection_card(0,2,R),R==0)). | |
344 | :- assert_must_succeed((partial_surjection_card(0,0,R),R==1)). | |
345 | :- assert_must_succeed((partial_surjection_card(2,0,R),R==1)). | |
346 | :- assert_must_succeed((partial_surjection_card(1,1,R),R==1)). | |
347 | :- assert_must_succeed((partial_surjection_card(inf,2,R),R==inf)). | |
348 | :- assert_must_succeed((partial_surjection_card(2,inf,R),R==0)). | |
349 | :- assert_must_succeed((partial_surjection_card(inf,inf,R),R==inf)). | |
350 | :- assert_must_succeed((partial_surjection_card(inf_overflow,inf_overflow,R),R==inf_overflow)). | |
351 | :- assert_must_succeed((partial_surjection_card(inf_overflow,10,R),R==inf_overflow)). | |
352 | :- assert_must_succeed((partial_surjection_card(3,2,R),R==12)). | |
353 | :- block partial_surjection_card(-,?,?), partial_surjection_card(?,-,?). | |
354 | partial_surjection_card(_X,0,R) :- !, R=1. % the empty set is a solution | |
355 | partial_surjection_card(inf,X,R) :- !,print_inf_warning(X,'+->>'),R=inf. % we know _X>0 | |
356 | partial_surjection_card(DomCard,RanCard,R) :- | |
357 | infless(DomCard,RanCard), !, R=0. % -> no way to cover all elements in range | |
358 | partial_surjection_card(inf_overflow,_,R) :- !, R=inf_overflow. | |
359 | partial_surjection_card(A,B,Res) :- tsurjcard(A,1,B,Res). % 1 because we can choose to leave the function undefined | |
360 | ||
361 | :- assert_must_succeed((total_surjection_card(0,2,R),R==0)). | |
362 | :- assert_must_succeed((total_surjection_card(0,0,R),R==1)). | |
363 | :- assert_must_succeed((total_surjection_card(2,0,R),R==0)). | |
364 | :- assert_must_succeed((total_surjection_card(inf,0,R),R==0)). | |
365 | :- assert_must_succeed((total_surjection_card(inf,1,R),R==1)). | |
366 | :- assert_must_succeed((total_surjection_card(inf,2,R),R==inf)). | |
367 | :- assert_must_succeed((total_surjection_card(2,inf,R),R==0)). | |
368 | :- assert_must_succeed((total_surjection_card(0,inf,R),R==0)). | |
369 | :- assert_must_succeed((total_surjection_card(inf,inf,R),R==inf)). | |
370 | :- assert_must_succeed((total_surjection_card(inf,inf_overflow,R),R==inf)). | |
371 | :- assert_must_succeed((total_surjection_card(inf_overflow,inf_overflow,R),R==inf_overflow)). | |
372 | :- assert_must_succeed((total_surjection_card(inf_overflow,100,R),R==inf_overflow)). | |
373 | :- assert_must_succeed((total_surjection_card(inf_overflow,inf,R),R==0)). | |
374 | :- assert_must_succeed((total_surjection_card(3,2,R),R==6)). | |
375 | :- block total_surjection_card(-,?,?), total_surjection_card(?,-,?). | |
376 | total_surjection_card(0,Range,R) :- !,(Range=0 -> R=1 % the empty set is a solution | |
377 | ; R=0). % no solution | |
378 | total_surjection_card(_X,0,R) :- !, R=0. % as _X>0 there is no way to construct a total function | |
379 | total_surjection_card(_X,1,R) :- !, R=1. % we only have one choice for every element of _X | |
380 | total_surjection_card(inf,X,R) :- !,print_inf_warning(X,'-->>'),R=inf. % we know _X>0 | |
381 | total_surjection_card(DomCard,RanCard,R) :- | |
382 | infless(DomCard,RanCard), !, R=0. % -> no way to cover all elements in range, applicable if RanCard=inf | |
383 | total_surjection_card(inf_overflow,_,R) :- !, R=inf_overflow. | |
384 | total_surjection_card(A,B,Res) :- tsurjcard(A,0,B,Res). | |
385 | ||
386 | tsurjcard(Rem,_AlreadyUsed,StillToBeUsed,Res) :- Rem<StillToBeUsed,!,Res=0. % no solution | |
387 | tsurjcard(0,_AlreadyUsed,_StillToBeUsed,Res) :- !, Res=1. % we have finished | |
388 | tsurjcard(Rem,AlreadyUsed,StillToBeUsed,Res) :- | |
389 | R1 is Rem-1, A1 is AlreadyUsed+1, S1 is StillToBeUsed-1, | |
390 | (AlreadyUsed=0 -> ResA=0 ; tsurjcard(R1,AlreadyUsed,StillToBeUsed,ResA)), | |
391 | (StillToBeUsed=0 -> ResB =0 ; tsurjcard(R1,A1,S1,ResB)), | |
392 | Res is AlreadyUsed*ResA+StillToBeUsed*ResB. | |
393 | ||
394 | ||
395 | ||
396 | :- assert_must_succeed((partial_injection_card(1,1,R),R==2)). | |
397 | :- assert_must_succeed((partial_injection_card(1,2,R),R==3)). | |
398 | :- assert_must_succeed((partial_injection_card(1,100,R),R==101)). | |
399 | :- assert_must_succeed((partial_injection_card(0,100,R),R==1)). | |
400 | :- assert_must_succeed((partial_injection_card(1,inf,R),R==inf)). | |
401 | :- assert_must_succeed((partial_injection_card(0,inf,R),R==1)). | |
402 | :- assert_must_succeed((partial_injection_card(5,0,R),R==1)). | |
403 | :- assert_must_succeed((partial_injection_card(inf,0,R),R==1)). | |
404 | :- assert_must_succeed((partial_injection_card(inf,1,R),R==inf)). | |
405 | :- assert_must_succeed((partial_injection_card(5,1,R),R==6)). | |
406 | ||
407 | :- block partial_injection_card(-,?,?), partial_injection_card(?,-,?). | |
408 | partial_injection_card(Dom,Ran,R) :- (Dom=0;Ran=0),!, R=1. % only one solution: empty function | |
409 | partial_injection_card(Dom,1,R) :- !, | |
410 | (Dom=inf -> R=inf ; Dom=inf_overflow -> R=inf_overflow | |
411 | ; R is Dom+1). % empty function + for every domain element one function | |
412 | partial_injection_card(inf,inf,Card) :- !, print_inf_warning(inf,'>+>'), Card=inf. | |
413 | partial_injection_card(inf_overflow,inf_overflow,Card) :- !, print_inf_overflow_warning('>+>'), Card=inf_overflow. | |
414 | partial_injection_card(Dom,Ran,R) :- (Dom=inf;Ran=inf),!, R=inf. | |
415 | partial_injection_card(Dom,Ran,R) :- (Dom=inf_overflow;Ran=inf_overflow),!, R=inf_overflow. | |
416 | partial_injection_card(Dom,Ran,R) :- Dom>1000,Ran>1000,!, set_inf_due_to_overflow(R). % TO DO: refine this | |
417 | % would give a result larger than blocking_factorial(1000) | |
418 | partial_injection_card(DCard,RCard,Card) :- | |
419 | pinj_card(1,DCard,RCard,1,Card). | |
420 | ||
421 | % TO DO: can we compute this directly rather than using recursion ? | |
422 | pinj_card(I,M,N,Acc,Res) :- (I>M ; I>N ; Acc=inf),!, Res=Acc. | |
423 | pinj_card(I,M,N,Acc,Res) :- | |
424 | choose_nk(M,I,MI), % ways to choose domain of size I | |
425 | blocking_factorial_k(N,I,NI), % ways to map the domain of size I to N | |
426 | safe_mul(MI,NI,MINI), safe_add_card(MINI,Acc,NewAcc), | |
427 | I1 is I+1, pinj_card(I1,M,N,NewAcc,Res). | |
428 | ||
429 | :- public total_bijection_card/3. % exported in is_a_relation above | |
430 | :- block total_bijection_card(-,?,?), total_bijection_card(?,-,?). | |
431 | total_bijection_card(inf,inf,Card) :- !, print_inf_warning(inf,'>->>'), Card=inf. | |
432 | total_bijection_card(inf_overflow,inf_overflow,Card) :- !, print_inf_overflow_warning('>->>'), Card=inf_overflow. | |
433 | total_bijection_card(DCard,RCard,Card) :- DCard \= RCard,!,Card=0. | |
434 | total_bijection_card(RCard,RCard,Card) :- blocking_factorial(RCard,Card). | |
435 | ||
436 | ||
437 | print_inf_overflow_warning(FUN) :- !, print('### WARNING: Assuming '), | |
438 | print(FUN), print(' exists for two very large sets sets'),nl. | |
439 | % TODO: probably produce enumeration_warning or virtual time-out or similar |