Orbiter 2022
Combinatorial Objects
finite_ring.cpp
Go to the documentation of this file.
1// finite_ring.cpp
2//
3// Anton Betten
4//
5// started: June 21, 2010
6
7
8
9#include "foundations.h"
10
11using namespace std;
12
13
14namespace orbiter {
15namespace layer1_foundations {
16namespace ring_theory {
17
18
20{
21 null();
22}
23
25{
26 freeself();
27}
28
30{
31 add_table = NULL;
32 mult_table = NULL;
33 f_is_unit_table = NULL;
34 negate_table = NULL;
35 inv_table = NULL;
36 Fp = NULL;
37}
38
40{
41 if (add_table) {
42 FREE_int(add_table);
43 }
44 if (mult_table) {
45 FREE_int(mult_table);
46 }
47 if (f_is_unit_table) {
48 FREE_int(f_is_unit_table);
49 }
50 if (negate_table) {
51 FREE_int(negate_table);
52 }
53 if (inv_table) {
54 FREE_int(inv_table);
55 }
56 if (Fp) {
57 FREE_OBJECT(Fp);
58 }
59 null();
60}
61
62void finite_ring::init(int q, int verbose_level)
63{
64 int f_v = (verbose_level >= 1);
65 int i, j, a;
67
68 if (f_v) {
69 cout << "finite_ring::init q=" << q << endl;
70 }
72 if (NT.is_prime_power(q)) {
74 NT.factor_prime_power(q, p, e);
76 Fp->finite_field_init(p, FALSE /* f_without_tables */, verbose_level);
77 }
78 else {
80 p = 0;
81 e = 0;
82 Fp = NULL;
83 }
84 add_table = NEW_int(q * q);
85 mult_table = NEW_int(q * q);
86 f_is_unit_table = NEW_int(q);
87 negate_table = NEW_int(q);
88 inv_table = NEW_int(q);
89 for (i = 0; i < q; i++) {
90 f_is_unit_table[i] = FALSE;
91 negate_table[i] = -1;
92 inv_table[i] = -1;
93 }
94 for (i = 0; i < q; i++) {
95 for (j = 0; j < q; j++) {
96 add_table[i * q + j] = a = (i + j) % q;
97 if (a == 0) {
98 negate_table[i] = j;
99 }
100 mult_table[i * q + j] = a = (i * j) % q;
101 if (a == 1) {
102 f_is_unit_table[i] = TRUE;
103 inv_table[i] = j;
104 }
105 }
106 }
107}
108
110{
111 return e;
112}
113
115{
116 return p;
117}
118
120{
121 return Fp;
122}
123
125{
126 return 0;
127}
128
130{
131 return 1;
132}
133
135{
136 if (i == 0)
137 return TRUE;
138 else
139 return FALSE;
140}
141
143{
144 if (i == 1)
145 return TRUE;
146 else
147 return FALSE;
148}
149
151{
152 return f_is_unit_table[i];
153}
154
155int finite_ring::add(int i, int j)
156{
157 //cout << "finite_field::add i=" << i << " j=" << j << endl;
158 if (i < 0 || i >= q) {
159 cout << "finite_ring::add() i = " << i << endl;
160 exit(1);
161 }
162 if (j < 0 || j >= q) {
163 cout << "finite_ring::add() j = " << j << endl;
164 exit(1);
165 }
166 return add_table[i * q + j];
167}
168
169int finite_ring::mult(int i, int j)
170{
171 //cout << "finite_field::mult i=" << i << " j=" << j << endl;
172 if (i < 0 || i >= q) {
173 cout << "finite_ring::mult() i = " << i << endl;
174 exit(1);
175 }
176 if (j < 0 || j >= q) {
177 cout << "finite_ring::mult() j = " << j << endl;
178 exit(1);
179 }
180 return mult_table[i * q + j];
181}
182
184{
185 if (i < 0 || i >= q) {
186 cout << "finite_ring::negate() i = " << i << endl;
187 exit(1);
188 }
189 return negate_table[i];
190}
191
193{
194 if (i <= 0 || i >= q) {
195 cout << "finite_ring::inverse() i = " << i << endl;
196 exit(1);
197 }
198 if (!f_is_unit_table[i]) {
199 cout << "finite_ring::inverse() i = " << i
200 << " is not a unit" << endl;
201 exit(1);
202 }
203 return inv_table[i];
204}
205
206int finite_ring::Gauss_int(int *A, int f_special,
207 int f_complete, int *base_cols,
208 int f_P, int *P, int m, int n, int Pn, int verbose_level)
209// returns the rank which is the number of entries in base_cols
210// A is a m x n matrix,
211// P is a m x Pn matrix (if f_P is TRUE)
212{
213 int f_v = (verbose_level >= 1);
214 int f_vv = (verbose_level >= 2);
215 int f_vvv = (verbose_level >= 3);
216 int rank, i, j, k, jj;
217 int pivot, pivot_inv = 0, a, b, c, z, f;
219
220 if (f_v) {
221 cout << "finite_ring::Gauss_int Gauss algorithm for matrix:" << endl;
222 Int_vec_print_integer_matrix_width(cout, A, m, n, n, 5);
223 //print_tables();
224 }
225 i = 0;
226 for (j = 0; j < n; j++) {
227 if (f_vv) {
228 cout << "j=" << j << endl;
229 }
230 /* search for pivot element: */
231 for (k = i; k < m; k++) {
232 if (is_unit(A[k * n + j])) {
233 if (f_vv) {
234 cout << "pivot found in " << k << "," << j << endl;
235 }
236 // pivot element found:
237 if (k != i) {
238 for (jj = 0; jj < n; jj++) {
239 Algo.int_swap(A[i * n + jj], A[k * n + jj]);
240 }
241 if (f_P) {
242 for (jj = 0; jj < Pn; jj++) {
243 Algo.int_swap(P[i * Pn + jj], P[k * Pn + jj]);
244 }
245 }
246 }
247 break;
248 } // if != 0
249 } // next k
250
251 if (k == m) { // no pivot found
252 if (f_vv) {
253 cout << "no pivot found" << endl;
254 }
255 continue; // increase j, leave i constant
256 }
257
258 if (f_vv) {
259 cout << "row " << i << " pivot in row " << k
260 << " colum " << j << endl;
261 }
262
263 base_cols[i] = j;
264 //if (FALSE) {
265 // cout << "."; cout.flush();
266 // }
267
268 pivot = A[i * n + j];
269 //pivot_inv = inv_table[pivot];
270 pivot_inv = inverse(pivot);
271 if (f_vv) {
272 cout << "pivot=" << pivot << " pivot_inv=" << pivot_inv << endl;
273 }
274 if (!f_special) {
275 // make pivot to 1:
276 for (jj = 0; jj < n; jj++) {
277 A[i * n + jj] = mult(A[i * n + jj], pivot_inv);
278 }
279 if (f_P) {
280 for (jj = 0; jj < Pn; jj++) {
281 P[i * Pn + jj] = mult(P[i * Pn + jj], pivot_inv);
282 }
283 }
284 if (f_vv) {
285 cout << "pivot=" << pivot << " pivot_inv=" << pivot_inv
286 << " made to one: " << A[i * n + j] << endl;
287 }
288 if (f_vvv) {
289 Int_vec_print_integer_matrix_width(cout, A, m, n, n, 5);
290 }
291 if (f_vv) {
292 cout << "made pivot to one:" << endl;
293 Int_vec_print(cout, A + i * n, n);
294 cout << endl;
295 }
296 }
297
298 /* do the gaussian elimination: */
299 for (k = i + 1; k < m; k++) {
300 if (f_vv) {
301 cout << "k=" << k << endl;
302 }
303 z = A[k * n + j];
304 if (z == 0)
305 continue;
306 if (f_special) {
307 f = mult(z, pivot_inv);
308 }
309 else {
310 f = z;
311 }
312 f = negate(f);
313 //A[k * n + j] = 0;
314 if (f_vv) {
315 cout << "eliminating row " << k << endl;
316 }
317 for (jj = 0; jj < n; jj++) {
318 a = A[i * n + jj];
319 b = A[k * n + jj];
320 // c := b + f * a
321 // = b - z * a if !f_special
322 // b - z * pivot_inv * a if f_special
323 c = mult(f, a);
324 c = add(c, b);
325 A[k * n + jj] = c;
326 if (f_vv) {
327 cout << A[k * n + jj] << " ";
328 }
329 }
330 if (f_vv) {
331 cout << "after eliminating row " << k << ":" << endl;
332 Int_vec_print(cout, A + k * n, n);
333 cout << endl;
334 }
335 if (f_P) {
336 for (jj = 0; jj < Pn; jj++) {
337 a = P[i * Pn + jj];
338 b = P[k * Pn + jj];
339 // c := b - z * a
340 c = mult(f, a);
341 c = add(c, b);
342 P[k * Pn + jj] = c;
343 }
344 }
345 if (f_vv) {
346 cout << endl;
347 }
348 if (FALSE) {
349 cout << "A=" << endl;
350 Int_vec_print_integer_matrix_width(cout, A, m, n, n, 5);
351 }
352 }
353 i++;
354 if (f_vv) {
355 cout << "A=" << endl;
356 Int_vec_print_integer_matrix_width(cout, A, m, n, n, 5);
357 //print_integer_matrix(cout, A, m, n);
358 if (f_P) {
359 cout << "P=" << endl;
360 Int_vec_print_integer_matrix(cout, P, m, Pn);
361 }
362 }
363 } // next j
364 rank = i;
365 if (f_complete) {
366 //if (FALSE) {
367 // cout << ";"; cout.flush();
368 // }
369 for (i = rank - 1; i >= 0; i--) {
370 //if (f_v) {
371 // cout << "."; cout.flush();
372 // }
373 j = base_cols[i];
374 if (!f_special) {
375 a = A[i * n + j];
376 }
377 else {
378 pivot = A[i * n + j];
379 pivot_inv = inverse(pivot);
380 }
381 // do the gaussian elimination in the upper part:
382 for (k = i - 1; k >= 0; k--) {
383 z = A[k * n + j];
384 if (z == 0)
385 continue;
386 //A[k * n + j] = 0;
387 for (jj = 0; jj < n; jj++) {
388 a = A[i * n + jj];
389 b = A[k * n + jj];
390 if (f_special) {
391 a = mult(a, pivot_inv);
392 }
393 c = mult(z, a);
394 c = negate(c);
395 c = add(c, b);
396 A[k * n + jj] = c;
397 }
398 if (f_P) {
399 for (jj = 0; jj < Pn; jj++) {
400 a = P[i * Pn + jj];
401 b = P[k * Pn + jj];
402 if (f_special) {
403 a = mult(a, pivot_inv);
404 }
405 c = mult(z, a);
406 c = negate(c);
407 c = add(c, b);
408 P[k * Pn + jj] = c;
409 }
410 }
411 } // next k
412 } // next i
413 }
414 if (f_v) {
415 cout << endl;
416 Int_vec_print_integer_matrix_width(cout, A, m, n, n, 5);
417 //print_integer_matrix(cout, A, rank, n);
418 cout << "the rank is " << rank << endl;
419 }
420 return rank;
421}
422
423
424
426 int *v, int stride, int len)
427// last unit element made one
428{
429 int i, j, a;
430
431 if (!f_chain_ring) {
432 cout << "finite_ring::PHG_element_normalize not a chain ring" << endl;
433 exit(1);
434 }
435 for (i = len - 1; i >= 0; i--) {
436 a = v[i * stride];
437 if (is_unit(a)) {
438 if (a == 1)
439 return i;
440 a = inverse(a);
441 for (j = len - 1; j >= 0; j--) {
442 v[j * stride] = mult(v[j * stride], a);
443 }
444 return i;
445 }
446 }
447 cout << "finite_ring::PHG_element_normalize "
448 "vector is not free" << endl;
449 exit(1);
450}
451
452
454 int *v, int stride, int len)
455// first non unit element made one
456{
457 int i, j, a;
458
459 if (!f_chain_ring) {
460 cout << "finite_ring::PHG_element_normalize_from_front not a chain ring" << endl;
461 exit(1);
462 }
463 for (i = 0; i < len; i++) {
464 a = v[i * stride];
465 if (is_unit(a)) {
466 if (a == 1) {
467 return i;
468 }
469 a = inverse(a);
470 for (j = 0; j < len; j++) {
471 v[j * stride] = mult(v[j * stride], a);
472 }
473 return i;
474 }
475 }
476 cout << "finite_ring::PHG_element_normalize_from_front "
477 "vector is not free" << endl;
478 exit(1);
479}
480
482 int *v, int stride, int len)
483{
484 long int i, j, idx, a, b, r1, r2, rk, N;
485 int f_v = FALSE;
486 int *w;
487 int *embedding;
489
490 if (!f_chain_ring) {
491 cout << "finite_ring::PHG_element_rank not a chain ring" << endl;
492 exit(1);
493 }
494 if (len <= 0) {
495 cout << "finite_ring::PHG_element_rank len <= 0" << endl;
496 exit(1);
497 }
498 if (f_v) {
499 cout << "the vector before normalization is ";
500 for (i = 0; i < len; i++) {
501 cout << v[i * stride] << " ";
502 }
503 cout << endl;
504 }
505 idx = PHG_element_normalize(v, stride, len);
506 if (f_v) {
507 cout << "the vector after normalization is ";
508 for (i = 0; i < len; i++) {
509 cout << v[i * stride] << " ";
510 }
511 cout << endl;
512 }
513 w = NEW_int(len - 1);
514 embedding = NEW_int(len - 1);
515 for (i = 0, j = 0; i < len - 1; i++, j++) {
516 if (i == idx) {
517 j++;
518 }
519 embedding[i] = j;
520 }
521 for (i = 0; i < len - 1; i++) {
522 w[i] = v[embedding[i] * stride];
523 }
524 for (i = 0; i < len - 1; i++) {
525 a = w[i];
526 b = a % get_p();
527 v[embedding[i] * stride] = b;
528 w[i] = (a - b) / get_p();
529 }
530 if (f_v) {
531 cout << "w=";
532 Int_vec_print(cout, w, len - 1);
533 cout << endl;
534 }
535 r1 = Gg.AG_element_rank(get_e(), w, 1, len - 1);
536 get_Fp()->PG_element_rank_modified_lint(v, stride, len, r2);
537
538 N = Gg.nb_PG_elements(len - 1, get_p());
539 rk = r1 * N + r2;
540
541 FREE_int(w);
542 FREE_int(embedding);
543
544 return rk;
545}
546
548 int *v, int stride, int len, int rk)
549{
550 int i, j, idx, r1, r2, N;
551 int f_v = FALSE;
552 int *w;
553 int *embedding;
555
556 if (!f_chain_ring) {
557 cout << "finite_ring::PHG_element_unrank not a chain ring" << endl;
558 exit(1);
559 }
560 if (len <= 0) {
561 cout << "finite_ring::PHG_element_unrank len <= 0" << endl;
562 exit(1);
563 }
564
565 w = NEW_int(len - 1);
566 embedding = NEW_int(len - 1);
567
568 N = Gg.nb_PG_elements(len - 1, get_p());
569 r2 = rk % N;
570 r1 = (rk - r2) / N;
571
572 Gg.AG_element_unrank(get_e(), w, 1, len - 1, r1);
573 get_Fp()->PG_element_unrank_modified(v, stride, len, r2);
574
575 if (f_v) {
576 cout << "w=";
577 Int_vec_print(cout, w, len - 1);
578 cout << endl;
579 }
580
581 idx = PHG_element_normalize(v, stride, len);
582 for (i = 0, j = 0; i < len - 1; i++, j++) {
583 if (i == idx) {
584 j++;
585 }
586 embedding[i] = j;
587 }
588
589 for (i = 0; i < len - 1; i++) {
590 v[embedding[i] * stride] += w[i] * get_p();
591 }
592
593
594
595 FREE_int(w);
596 FREE_int(embedding);
597
598}
599
601{
602 int N1, N2;
604
605 if (!f_chain_ring) {
606 cout << "finite_ring::nb_PHG_elements not a chain ring" << endl;
607 exit(1);
608 }
609 N1 = Gg.nb_PG_elements(n, get_p());
610 N2 = Gg.nb_AG_elements(n, get_e());
611 return N1 * N2;
612}
613
614}}}
615
void PG_element_unrank_modified(int *v, int stride, int len, int a)
void finite_field_init(int q, int f_without_tables, int verbose_level)
void PG_element_rank_modified_lint(int *v, int stride, int len, long int &a)
various functions related to geometries
Definition: geometry.h:721
void AG_element_unrank(int q, int *v, int stride, int len, long int a)
long int AG_element_rank(int q, int *v, int stride, int len)
int Gauss_int(int *A, int f_special, int f_complete, int *base_cols, int f_P, int *P, int m, int n, int Pn, int verbose_level)
int PHG_element_normalize(int *v, int stride, int len)
int PHG_element_rank(int *v, int stride, int len)
void PHG_element_unrank(int *v, int stride, int len, int rk)
int PHG_element_normalize_from_front(int *v, int stride, int len)
#define Int_vec_print_integer_matrix(A, B, C, D)
Definition: foundations.h:690
#define FREE_int(p)
Definition: foundations.h:640
#define NEW_OBJECT(type)
Definition: foundations.h:638
#define FREE_OBJECT(p)
Definition: foundations.h:651
#define NEW_int(n)
Definition: foundations.h:625
#define Int_vec_print_integer_matrix_width(A, B, C, D, E, F)
Definition: foundations.h:691
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define Int_vec_print(A, B, C)
Definition: foundations.h:685
the orbiter library for the classification of combinatorial objects