aboutsummaryrefslogtreecommitdiff
path: root/src/utils.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/utils.c356
1 files changed, 249 insertions, 107 deletions
diff --git a/src/utils.c b/src/utils.c
index 5b7df06..f72a00e 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,132 +1,274 @@
1#include "utils.h" 1#include "utils.h"
2 2
3/* Hardcoded factorial of small numbers (n<=12). */ 3void
4int factorial[13] = { 4apply_permutation(int *perm, int *set, int n)
5 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600 5{
6}; 6 int *aux = malloc(n * sizeof(int));
7 int i;
7 8
8/* swaps two integers */ 9 if (!is_perm(perm, n))
9void swap(int *a, int *b) { 10 return;
10 int aux = *a; 11
11 *a = *b; 12 for (i = 0; i < n; i++)
12 *b = aux; 13 aux[i] = set[perm[i]];
14
15 memcpy(set, aux, n * sizeof(int));
16 free(aux);
17}
18
19int
20binomial(int n, int k)
21{
22 if (n < 0 || k < 0 || k > n)
23 return 0;
24
25 return factorial(n) / (factorial(k) * factorial(n-k));
26}
27
28int
29digit_array_to_int(int *a, int n, int b)
30{
31 int i, ret = 0, p = 1;
32
33 for (i = 0; i < n; i++, p *= b)
34 ret += a[i] * p;
35
36 return ret;
37}
38
39int
40factorial(int n)
41{
42 int i, ret = 1;
43
44 if (n < 0)
45 return 0;
46
47 for (i = 1; i <= n; i++)
48 ret *= i;
49
50 return ret;
51}
52
53void
54index_to_perm(int p, int n, int *r)
55{
56 int *a = malloc(n * sizeof(int));
57 int i, j, c;
58
59 for (i = 0; i < n; i++)
60 a[i] = 0;
61
62 if (p < 0 || p >= factorial(n))
63 for (i = 0; i < n; i++)
64 r[i] = -1;
65
66 for (i = 0; i < n; i++) {
67 c = 0;
68 j = 0;
69 while (c <= p / factorial(n-i-1))
70 c += a[j++] ? 0 : 1;
71 r[i] = j-1;
72 a[j-1] = 1;
73 p %= factorial(n-i-1);
74 }
75
76 free(a);
77}
78
79void
80index_to_subset(int s, int n, int k, int *r)
81{
82 int i, j, v;
83
84 if (s < 0 || s >= binomial(n, k)) {
85 for (i = 0; i < n; i++)
86 r[i] = -1;
87 return;
88 }
89
90 for (i = 0; i < n; i++) {
91 if (k == n-i) {
92 for (j = i; j < n; j++)
93 r[j] = 1;
94 return;
95 }
96
97 if (k == 0) {
98 for (j = i; j < n; j++)
99 r[j] = 0;
100 return;
101 }
102
103 v = binomial(n-i-1, k);
104 if (s >= v) {
105 r[i] = 1;
106 k--;
107 s -= v;
108 } else {
109 r[i] = 0;
110 }
111 }
112}
113
114void
115int_to_digit_array(int a, int b, int n, int *r)
116{
117 int i;
118
119 if (b <= 1)
120 for (i = 0; i < n; i++)
121 r[i] = 0;
122 else
123 for (i = 0; i < n; i++, a /= b)
124 r[i] = a % b;
125}
126
127void
128int_to_sum_zero_array(int x, int b, int n, int *a)
129{
130 int i, s = 0;
131
132 if (b <= 1) {
133 for (i = 0; i < n; i++)
134 a[i] = 0;
135 } else {
136 int_to_digit_array(x, b, n-1, a);
137 for (i = 0; i < n - 1; i++)
138 s = (s + a[i]) % b;
139 a[n-1] = (b - s) % b;
140 }
13} 141}
14 142
15/* Converts the integer a to its representation in base b (first n digits 143int
16 * only) and saves the result in r. */ 144invert_digits(int a, int b, int n)
17void int_to_digit_array(int a, int b, int n, int *r) { 145{
18 for (int i = 0; i < n; i++) { 146 int i, ret, *r = malloc(n * sizeof(int));
19 r[i] = a % b; 147
20 a /= b; 148 int_to_digit_array(a, b, n, r);
21 } 149 for (i = 0; i < n; i++)
150 r[i] = (b-r[i]) % b;
151
152 ret = digit_array_to_int(r, n, b);
153 free(r);
154 return ret;
22} 155}
23 156
24/* Converts the array of n digits a to a integer using base b. */ 157bool
25int digit_array_to_int(int *a, int n, int b) { 158is_perm(int *a, int n)
26 int ret = 0, p = 1; 159{
27 for (int i = 0; i < n; i++) { 160 int *aux = malloc(n * sizeof(int));
28 ret += a[i] * p; 161 int i;
29 p *= b; 162
30 } 163 for (i = 0; i < n; i++)
31 return ret; 164 if (a[i] < 0 || a[i] >= n)
165 return false;
166 else
167 aux[a[i]] = 1;
168
169 for (i = 0; i < n; i++)
170 if (!aux[i])
171 return false;
172
173 free(aux);
174
175 return true;
32} 176}
33 177
34/* Converts a permutation on [0..(n-1)] into the integer i which is the index 178bool
35 * of the permutation in the sorted list of all n! such permutations. 179is_subset(int *a, int n, int k)
36 * Only works for n<=12. */ 180{
37int perm_to_index(int *a, int n) { 181 int i, sum = 0;
38 int ret = 0; 182
39 for (int i = 0; i < n; i++) { 183 for (i = 0; i < n; i++)
40 int c = 0; 184 sum += a[i] ? 1 : 0;
41 for (int j = i+1; j < n; j++) 185
42 if (a[i] > a[j]) 186 return sum == k;
43 c++;
44 ret += factorial[n-i-1] * c;
45 }
46 return ret;
47} 187}
48 188
49/* Converts a permutation index to the actual permutation as an array 189int
50 * (see perm_to_index) and saves the result to r. */ 190perm_sign(int *a, int n)
51void index_to_perm(int p, int n, int *r) { 191{
52 int a[n]; 192 int i, j, ret = 0;
53 for (int j = 0; j < n; j++) 193
54 a[j] = 0; /* picked elements */ 194 if (!is_perm(a,n))
55 for (int i = 0; i < n; i++) { 195 return -1;
56 int c = 0, j = 0; 196
57 while (c <= p / factorial[n-i-1]) { 197 for (i = 0; i < n; i++)
58 if (!a[j]) 198 for (j = i+1; j < n; j++)
59 c++; 199 ret += (a[i] > a[j]) ? 1 : 0;
60 j++; 200
61 } 201 return ret % 2;
62 r[i] = j-1;
63 a[j-1] = 1;
64 p %= factorial[n-i-1];
65 }
66} 202}
67 203
204int
205perm_to_index(int *a, int n)
206{
207 int i, j, c, ret = 0;
208
209 if (!is_perm(a, n))
210 return -1;
68 211
69int perm_sign_array(int a[], int n) { 212 for (i = 0; i < n; i++) {
70 int ret = 0; 213 c = 0;
71 for (int i = 0; i < n; i++) 214 for (j = i+1; j < n; j++)
72 for (int j = i+1; j < n; j++) 215 c += (a[i] > a[j]) ? 1 : 0;
73 if (a[i]>a[j]) 216 ret += factorial(n-i-1) * c;
74 ret++; 217 }
75 return ret % 2; 218
219 return ret;
76} 220}
77 221
78int perm_sign_int(int p, int n) { 222int
79 int a[n]; 223powint(int a, int b)
80 index_to_perm(p, n, a); 224{
81 return perm_sign_array(a, n); 225 if (b < 0)
226 return 0;
227 if (b == 0)
228 return 1;
229
230 if (b % 2)
231 return a * powint(a, b-1);
232 else
233 return powint(a*a, b/2);
82} 234}
83 235
236int
237subset_to_index(int *a, int n, int k)
238{
239 int i, ret = 0;
240
241 if (!is_subset(a, n, k))
242 return binomial(n, k);
84 243
85/* Converts a k-element subset of a set with an element from an array of n 244 for (i = 0; i < n; i++) {
86 * elements, of which k are 1 (or just non-zero) and n-k are 0, to its index 245 if (k == n-i)
87 * in the sorted list of all such subsets. 246 return ret;
88 * Works only for n <= 12. */ 247 if (a[i]) {
89int subset_to_index(int *a, int n, int k) { 248 ret += binomial(n-i-1, k);
90 int ret = 0; 249 k--;
91 for (int i = 0; i < n; i++) { 250 }
92 if (k == n-i) 251 }
93 return ret; 252
94 if (a[i]) { 253 return ret;
95 ret += factorial[n-i-1] / (factorial[k] * factorial[n-i-1-k]);
96 k--;
97 }
98 }
99 return ret;
100} 254}
101 255
102/* Inverse of the above */ 256void
103void index_to_subset(int s, int n, int k, int *r) { 257sum_arrays_mod(int *src, int *dst, int n, int m)
104 for (int i = 0; i < n; i++) { 258{
105 if (k == n-i) { 259 int i;
106 for (int j = i; j < n; j++) 260
107 r[j] = 1; 261 for (i = 0; i < n; i++)
108 return; 262 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
109 }
110 int v = factorial[n-i-1] / (factorial[k] * factorial[n-i-1-k]);
111 if (s >= v) {
112 r[i] = 1;
113 k--;
114 s -= v;
115 } else {
116 r[i] = 0;
117 }
118 }
119} 263}
120 264
121/* Converts the first n-1 digits of a number to an array a of digits in base b; 265void
122 * then adds one element to the array, so that the sum of the elements of a is 266swap(int *a, int *b)
123 * zero modulo b. 267{
124 * This is used for determing the edge orientation from an 11-bits integer or 268 int aux;
125 * the corner orientation from a 7-trits integer. */ 269
126void int_to_sum_zero_array(int x, int b, int n, int *a) { 270 aux = *a;
127 int_to_digit_array(x, b, n-1, a); 271 *a = *b;
128 int s = 0; 272 *b = aux;
129 for (int i = 0; i < n - 1; i++) s = (s + a[i]) % b;
130 a[n-1] = (b - s) % b;
131} 273}
132 274

Generated with cgit - Back to sebastiano.tronto.net