1 % (c) 2009-2024 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.
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) :- !, (Dom=inf -> R=inf ; R is Dom+1). % empty function + for every domain element one function
410 partial_injection_card(inf,inf,Card) :- !, print_inf_warning(inf,'>+>'), Card=inf.
411 partial_injection_card(inf_overflow,inf_overflow,Card) :- !, print_inf_overflow_warning('>+>'), Card=inf_overflow.
412 partial_injection_card(Dom,Ran,R) :- (Dom=inf;Ran=inf),!, R=inf.
413 partial_injection_card(Dom,Ran,R) :- Dom>1000,Ran>1000,!, set_inf_due_to_overflow(R). % TO DO: refine this
414 % would give a result larger than blocking_factorial(1000)
415 partial_injection_card(DCard,RCard,Card) :-
416 pinj_card(1,DCard,RCard,1,Card).
417
418 % TO DO: can we compute this directly rather than using recursion ?
419 pinj_card(I,M,N,Acc,Res) :- (I>M ; I>N ; Acc=inf),!, Res=Acc.
420 pinj_card(I,M,N,Acc,Res) :-
421 choose_nk(M,I,MI), % ways to choose domain of size I
422 blocking_factorial_k(N,I,NI), % ways to map the domain of size I to N
423 safe_mul(MI,NI,MINI), safe_add_card(MINI,Acc,NewAcc),
424 I1 is I+1, pinj_card(I1,M,N,NewAcc,Res).
425
426 :- public total_bijection_card/3. % exported in is_a_relation above
427 :- block total_bijection_card(-,?,?), total_bijection_card(?,-,?).
428 total_bijection_card(inf,inf,Card) :- !, print_inf_warning(inf,'>->>'), Card=inf.
429 total_bijection_card(inf_overflow,inf_overflow,Card) :- !, print_inf_overflow_warning('>->>'), Card=inf_overflow.
430 total_bijection_card(DCard,RCard,Card) :- DCard \= RCard,!,Card=0.
431 total_bijection_card(RCard,RCard,Card) :- blocking_factorial(RCard,Card).
432
433
434 print_inf_overflow_warning(FUN) :- !, print('### WARNING: Assuming '),
435 print(FUN), print(' exists for two very large sets sets'),nl.
436 % TODO: probably produce enumeration_warning or virtual time-out or similar