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 |