| 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 |