00001
00002
00003
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #ifndef _CHOMP_HOMOLOGY_CHAINS_H_
00045 #define _CHOMP_HOMOLOGY_CHAINS_H_
00046
00047 #include "chomp/system/config.h"
00048 #include "chomp/system/textfile.h"
00049
00050 #include <iostream>
00051 #include <fstream>
00052 #include <cstdlib>
00053 #include <iomanip>
00054
00055 namespace chomp {
00056 namespace homology {
00057
00058
00059
00060
00061
00062 template <class euclidom>
00063 class chain;
00064
00065 template <class euclidom>
00066 class matrices;
00067
00068 template <class euclidom>
00069 class mmatrix;
00070
00071 template <class euclidom>
00072 class chaincomplex;
00073
00074 template <class euclidom>
00075 class chainmap;
00076
00077
00078 template <class euclidom>
00079 outputstream &show_homology (outputstream &out, const chain<euclidom> &c);
00080 template <class euclidom>
00081 std::ostream &show_homology (std::ostream &out, const chain<euclidom> &c);
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 #define CHAINFIXED 0
00092
00093 #ifndef CHAINFIXED
00094 #define CHAINFIXED 1
00095 #endif
00096
00100 template <class euclidom>
00101 class chain
00102 {
00103 public:
00105 chain ();
00106
00108 chain (const chain<euclidom> &c);
00109
00111 chain<euclidom> &operator = (const chain<euclidom> &c);
00112
00114 ~chain ();
00115
00118 int size () const;
00119
00121 bool empty () const;
00122
00126 euclidom getcoefficient (int n = -1) const;
00127
00130 int findnumber (int n) const;
00131
00134 euclidom coef (int i) const;
00135
00137 int num (int i) const;
00138
00141 bool contains_non_invertible () const;
00142
00149 int findbest (chain<euclidom> *table = NULL) const;
00150
00152 chain<euclidom> &add (int n, euclidom e);
00153
00155 chain<euclidom> &remove (int n);
00156
00161 chain<euclidom> &add (const chain<euclidom> &other,
00162 euclidom e, int number = -1,
00163 chain<euclidom> *table = NULL);
00164
00169 chain<euclidom> &swap (chain<euclidom> &other,
00170 int number = -1, int othernumber = -1,
00171 chain<euclidom> *table = NULL);
00172
00174 chain<euclidom> &take (chain<euclidom> &c);
00175
00178 chain<euclidom> &multiply (euclidom e, int number = -1);
00179
00182 outputstream &show (outputstream &out,
00183 const char *label = NULL) const;
00184
00187 std::ostream &show (std::ostream &out, const char *label = NULL) const;
00188
00189 private:
00191 int len;
00192
00197 union
00198 {
00199 struct
00200 {
00201 int *n;
00202 euclidom *e;
00203 } t;
00204 struct
00205 {
00206 #if CHAINFIXED
00207 int n [CHAINFIXED];
00208 euclidom e [CHAINFIXED];
00209 #else
00210 int *n;
00211 euclidom *e;
00212 #endif
00213 } x;
00214 };
00215
00217 chain<euclidom> &insertpair (int i, int n, euclidom e);
00218
00220 chain<euclidom> &removepair (int i);
00221
00223 chain<euclidom> &swapnumbers (int number1, int number2);
00224
00228 bool allocated () const;
00229
00230 };
00231
00232
00233
00234 template <class euclidom>
00235 inline bool chain<euclidom>::allocated () const
00236 {
00237 if (len <= static_cast<int> (CHAINFIXED))
00238 return false;
00239
00240
00241 else
00242 return true;
00243 }
00244
00245 template <class euclidom>
00246 inline chain<euclidom>::chain ()
00247 {
00248 len = 0;
00249 return;
00250 }
00251
00252 template <class euclidom>
00253 inline chain<euclidom>::chain (const chain<euclidom> &c)
00254 {
00255
00256 len = c. len;
00257
00258
00259 if (allocated ())
00260 {
00261 t. n = new int [len];
00262 t. e = new euclidom [len];
00263 if (!t. n || !t. e)
00264 throw "Not enough memory to create a chain copy.";
00265 for (int i = 0; i < len; ++ i)
00266 {
00267 t. n [i] = c. t. n [i];
00268 t. e [i] = c. t. e [i];
00269 }
00270 }
00271 else
00272 {
00273 for (int i = 0; i < len; ++ i)
00274 {
00275 x. n [i] = c. x. n [i];
00276 x. e [i] = c. x. e [i];
00277 }
00278 }
00279 return;
00280 }
00281
00282 template <class euclidom>
00283 inline chain<euclidom> &chain<euclidom>::operator =
00284 (const chain<euclidom> &c)
00285 {
00286
00287 if (allocated ())
00288 {
00289 delete [] t. n;
00290 delete [] t. e;
00291 }
00292
00293
00294 len = c. len;
00295
00296
00297 if (allocated ())
00298 {
00299 t. n = new int [len];
00300 t. e = new euclidom [len];
00301 if (!t. n || !t. e)
00302 throw "Not enough memory to create a chain copy =.";
00303 for (int i = 0; i < len; ++ i)
00304 {
00305 t. n [i] = c. t. n [i];
00306 t. e [i] = c. t. e [i];
00307 }
00308 }
00309 else
00310 {
00311 for (int i = 0; i < len; ++ i)
00312 {
00313 x. n [i] = c. x. n [i];
00314 x. e [i] = c. x. e [i];
00315 }
00316 }
00317 return *this;
00318 }
00319
00320 template <class euclidom>
00321 inline chain<euclidom>::~chain ()
00322 {
00323 if (allocated ())
00324 {
00325 delete [] t. n;
00326 delete [] t. e;
00327 }
00328 return;
00329 }
00330
00331 template <class euclidom>
00332 inline int chain<euclidom>::size () const
00333 {
00334 return len;
00335 }
00336
00337 template <class euclidom>
00338 inline bool chain<euclidom>::empty () const
00339 {
00340 return !len;
00341 }
00342
00343 template <class euclidom>
00344 euclidom chain<euclidom>::getcoefficient (int n) const
00345 {
00346 bool a = allocated ();
00347 const euclidom *tetab = a ? t. e : x. e;
00348 if (n < 0)
00349 {
00350 if (len > 0)
00351 return tetab [0];
00352 else
00353 {
00354 euclidom zero;
00355 zero = 0;
00356 return zero;
00357 }
00358 }
00359
00360 const int *tntab = a ? t. n : x. n;
00361 int i = 0;
00362 while ((i < len) && (tntab [i] < n))
00363 ++ i;
00364 if ((i >= len) || (tntab [i] != n))
00365 {
00366 euclidom zero;
00367 zero = 0;
00368 return zero;
00369 }
00370 return tetab [i];
00371 }
00372
00373 template <class euclidom>
00374 inline int chain<euclidom>::findnumber (int n) const
00375 {
00376 bool a = allocated ();
00377 const int *tntab = a ? t. n : x. n;
00378 for (int i = 0; i < len; ++ i)
00379 {
00380 if (tntab [i] == n)
00381 return i;
00382 else if (tntab [i] > n)
00383 return -1;
00384 }
00385 return -1;
00386 }
00387
00388 template <class euclidom>
00389 inline euclidom chain<euclidom>::coef (int i) const
00390 {
00391 if (i >= len)
00392 throw "Wrong coefficient requested from a chain.";
00393 return (allocated () ? t. e : x. e) [i];
00394 }
00395
00396 template <class euclidom>
00397 inline int chain<euclidom>::num (int i) const
00398 {
00399 if (i >= len)
00400 throw "Wrong number requested from a chain.";
00401 return (allocated () ? t. n : x. n) [i];
00402 }
00403
00404 template <class euclidom>
00405 inline bool chain<euclidom>::contains_non_invertible () const
00406 {
00407 if (allocated ())
00408 {
00409 for (int i = 0; i < len; ++ i)
00410 {
00411 if (t. e [i]. delta () > 1)
00412 return true;
00413 }
00414 }
00415 else
00416 {
00417 for (int i = 0; i < len; ++ i)
00418 {
00419 if (x. e [i]. delta () > 1)
00420 return true;
00421 }
00422 }
00423 return false;
00424 }
00425
00426 template <class euclidom>
00427 inline int chain<euclidom>::findbest (chain<euclidom> *table) const
00428 {
00429
00430 if (len <= 1)
00431 return (len - 1);
00432
00433
00434 int this_delta, best_delta = -1;
00435 int best_i = 0;
00436
00437
00438 bool a = allocated ();
00439 const int *tntab = a ? t. n : x. n;
00440 const euclidom *tetab = a ? t. e : x. e;
00441 int i;
00442 for (i = 0; i < len; ++ i)
00443 {
00444
00445 this_delta = tetab [i]. delta ();
00446
00447
00448
00449 if (!table && (this_delta == 1))
00450 return i;
00451
00452
00453 if (!i || (this_delta < best_delta))
00454 {
00455 best_delta = this_delta;
00456 best_i = i;
00457 }
00458 }
00459
00460
00461 if (!table)
00462 return best_i;
00463
00464
00465 int this_length, best_length =
00466 table [tntab [best_i]]. size ();
00467 for (i = best_i + 1; i < len; ++ i)
00468 {
00469 if (tetab [i]. delta () == best_delta)
00470 {
00471 this_length =
00472 table [tntab [i]]. size ();
00473 if (best_length > this_length)
00474 {
00475 best_length = this_length;
00476 best_i = i;
00477 }
00478 }
00479 }
00480
00481 return best_i;
00482 }
00483
00484
00485
00486 template <class euclidom>
00487 inline chain<euclidom> &chain<euclidom>::insertpair
00488 (int i, int n, euclidom e)
00489 {
00490
00491 bool a = allocated ();
00492
00493
00494 ++ len;
00495
00496
00497 bool na = allocated ();
00498
00499
00500 if (na)
00501 {
00502
00503 int *newntab = new int [len];
00504 euclidom *newetab = new euclidom [len];
00505 if (!newntab || !newetab)
00506 throw "Cannot add an element to a chain.";
00507
00508
00509 int *oldntab = a ? t. n : x. n;
00510 euclidom *oldetab = a ? t. e : x. e;
00511
00512
00513 int j;
00514 for (j = 0; j < i; ++ j)
00515 {
00516 newntab [j] = oldntab [j];
00517 newetab [j] = oldetab [j];
00518 }
00519 newntab [i] = n;
00520 newetab [i] = e;
00521 for (j = i + 1; j < len; ++ j)
00522 {
00523 newntab [j] = oldntab [j - 1];
00524 newetab [j] = oldetab [j - 1];
00525 }
00526
00527
00528 if (a)
00529 {
00530 delete [] t. n;
00531 delete [] t. e;
00532 }
00533
00534
00535 t. n = newntab;
00536 t. e = newetab;
00537 }
00538
00539
00540 else
00541 {
00542 for (int j = len - 1; j > i; -- j)
00543 {
00544 x. n [j] = x. n [j - 1];
00545 x. e [j] = x. e [j - 1];
00546 }
00547 x. n [i] = n;
00548 x. e [i] = e;
00549 }
00550
00551 return *this;
00552 }
00553
00554 template <class euclidom>
00555 inline chain<euclidom> &chain<euclidom>::removepair (int i)
00556 {
00557
00558 bool a = allocated ();
00559
00560
00561 if (len)
00562 -- len;
00563
00564
00565 bool na = allocated ();
00566
00567
00568 if (na)
00569 {
00570 int *newntab = new int [len];
00571 euclidom *newetab = new euclidom [len];
00572 if (!newntab || !newetab)
00573 throw "Cannot remove a pair from a chain.";
00574
00575
00576 int j;
00577 for (j = 0; j < i; ++ j)
00578 {
00579 newntab [j] = t. n [j];
00580 newetab [j] = t. e [j];
00581 }
00582 for (j = i; j < len; ++ j)
00583 {
00584 newntab [j] = t. n [j + 1];
00585 newetab [j] = t. e [j + 1];
00586 }
00587 delete [] t. n;
00588 delete [] t. e;
00589 t. n = newntab;
00590 t. e = newetab;
00591 }
00592
00593
00594 else
00595 {
00596 int *oldntab = a ? t. n : x. n;
00597 euclidom *oldetab = a ? t. e : x. e;
00598
00599
00600 int j;
00601 for (j = 0; a && (j < i); ++ j)
00602 {
00603 x. n [j] = oldntab [j];
00604 x. e [j] = oldetab [j];
00605 }
00606 for (j = i; j < len; ++ j)
00607 {
00608 x. n [j] = oldntab [j + 1];
00609 x. e [j] = oldetab [j + 1];
00610 }
00611
00612
00613 if (a)
00614 {
00615 delete [] oldntab;
00616 delete [] oldetab;
00617 }
00618 }
00619
00620 return *this;
00621 }
00622
00623 template <class euclidom>
00624 inline chain<euclidom> &chain<euclidom>::swapnumbers (int number1,
00625 int number2)
00626 {
00627
00628 if (number1 == number2)
00629 return *this;
00630
00631
00632 if (number1 > number2)
00633 {
00634 int tempnumber = number1;
00635 number1 = number2;
00636 number2 = tempnumber;
00637 }
00638
00639
00640 bool a = allocated ();
00641 int *tntab = a ? t. n : x. n;
00642 euclidom *tetab = a ? t. e : x. e;
00643
00644
00645 int i1 = 0, i2 = 0;
00646 while ((i1 < len) && (tntab [i1] < number1))
00647 ++ i1;
00648 while ((i2 < len) && (tntab [i2] < number2))
00649 ++ i2;
00650
00651
00652 if ((i1 < len) && (tntab [i1] == number1))
00653 {
00654
00655 if ((i2 < len) && (tntab [i2] == number2))
00656 swapelements (tetab [i1], tetab [i2]);
00657
00658 else
00659 {
00660 euclidom temp = tetab [i1];
00661 for (int i = i1 + 1; i < i2; ++ i)
00662 {
00663 tntab [i - 1] = tntab [i];
00664 tetab [i - 1] = tetab [i];
00665 }
00666 tntab [i2 - 1] = number2;
00667 tetab [i2 - 1] = temp;
00668 }
00669 }
00670
00671
00672 else if ((i2 < len) && (tntab [i2] == number2))
00673 {
00674 euclidom temp = tetab [i2];
00675 for (int i = i2; i > i1; -- i)
00676 {
00677 tntab [i] = tntab [i - 1];
00678 tetab [i] = tetab [i - 1];
00679 }
00680 tntab [i1] = number1;
00681 tetab [i1] = temp;
00682 }
00683
00684 return *this;
00685 }
00686
00687
00688
00689 template <class euclidom>
00690 inline chain<euclidom> &chain<euclidom>::add (int n, euclidom e)
00691 {
00692
00693 if (e == 0)
00694 return *this;
00695 bool a = allocated ();
00696 int *tntab = a ? t. n : x. n;
00697 euclidom *tetab = a ? t. e : x. e;
00698
00699
00700 int i = 0;
00701 while ((i < len) && (tntab [i] < n))
00702 ++ i;
00703
00704
00705 if ((i < len) && (tntab [i] == n))
00706 {
00707
00708 tetab [i] += e;
00709
00710
00711 if (tetab [i] == 0)
00712 return removepair (i);
00713
00714
00715 else
00716 return *this;
00717 }
00718
00719
00720 return insertpair (i, n, e);
00721
00722 }
00723
00724 template <class euclidom>
00725 chain<euclidom> &chain<euclidom>::remove (int n)
00726 {
00727 bool a = allocated ();
00728 int *tntab = a ? t. n : x. n;
00729
00730
00731 int i = 0;
00732 while ((i < len) && (tntab [i] < n))
00733 ++ i;
00734
00735
00736 if ((i < len) && (tntab [i] == n))
00737 return removepair (i);
00738
00739 return *this;
00740 }
00741
00742 template <class euclidom>
00743 inline chain<euclidom> &chain<euclidom>::add (const chain<euclidom> &other,
00744 euclidom e, int number, chain<euclidom> *table)
00745 {
00746
00747
00748 if ((e == 0) || !other. len)
00749 return *this;
00750
00751
00752 int tablen = len + other. len;
00753 int *bigntab = new int [tablen];
00754 euclidom *bigetab = new euclidom [tablen];
00755 if (!bigntab || !bigetab)
00756 throw "Not enough memory to add chains.";
00757
00758
00759
00760 int i = 0, j = 0, k = 0;
00761
00762
00763 bool a = allocated ();
00764 bool oa = other. allocated ();
00765 const int *tntab = a ? t. n : x. n;
00766 const euclidom *tetab = a ? t. e : x. e;
00767 const int *ontab = oa ? other. t. n : other. x. n;
00768 const euclidom *oetab = oa ? other. t. e : other. x. e;
00769
00770
00771 while ((i < len) || (j < other. len))
00772 {
00773 if (i >= len)
00774 {
00775 bigntab [k] = ontab [j];
00776 bigetab [k] = e * oetab [j ++];
00777 if (table)
00778 {
00779 table [bigntab [k]]. add (number,
00780 bigetab [k]);
00781 }
00782 ++ k;
00783 }
00784 else if ((j >= other. len) || (tntab [i] < ontab [j]))
00785 {
00786 bigntab [k] = tntab [i];
00787 bigetab [k ++] = tetab [i ++];
00788 }
00789 else if (tntab [i] > ontab [j])
00790 {
00791 bigntab [k] = ontab [j];
00792 bigetab [k] = e * oetab [j ++];
00793 if (table)
00794 {
00795 table [bigntab [k]]. add (number,
00796 bigetab [k]);
00797 }
00798 ++ k;
00799 }
00800 else
00801 {
00802 bigntab [k] = tntab [i];
00803 euclidom addelem = e * oetab [j ++];
00804 bigetab [k] = tetab [i ++] + addelem;
00805 euclidom zero;
00806 zero = 0;
00807 if (bigetab [k] != zero)
00808 {
00809 if (table)
00810 {
00811 table [bigntab [k]]. add (number,
00812 addelem);
00813 }
00814 ++ k;
00815 }
00816 else if (table)
00817 {
00818 table [bigntab [k]]. remove (number);
00819 }
00820 }
00821 }
00822
00823
00824 if (a && ((k != len) || (k == tablen)))
00825 {
00826 delete [] t. n;
00827 delete [] t. e;
00828 }
00829
00830
00831 if (a && (k == len) && (k != tablen))
00832 {
00833 for (int i = 0; i < len; ++ i)
00834 {
00835 t. n [i] = bigntab [i];
00836 t. e [i] = bigetab [i];
00837 }
00838 delete [] bigntab;
00839 delete [] bigetab;
00840 return *this;
00841 }
00842
00843 len = k;
00844
00845
00846 if (!allocated ())
00847 {
00848 for (int i = 0; i < len; ++ i)
00849 {
00850 x. n [i] = bigntab [i];
00851 x. e [i] = bigetab [i];
00852 }
00853 delete [] bigntab;
00854 delete [] bigetab;
00855 return *this;
00856 }
00857
00858
00859 if (len != tablen)
00860 {
00861 t. n = new int [len];
00862 t. e = new euclidom [len];
00863 if (!t. n || !t. e)
00864 throw "Cannot shorten a sum of chains.";
00865 for (int i = 0; i < len; ++ i)
00866 {
00867 t. n [i] = bigntab [i];
00868 t. e [i] = bigetab [i];
00869 }
00870 delete [] bigntab;
00871 delete [] bigetab;
00872 }
00873
00874
00875 else
00876 {
00877 t. n = bigntab;
00878 t. e = bigetab;
00879 }
00880
00881 return *this;
00882 }
00883
00884 template <class euclidom>
00885 inline chain<euclidom> &chain<euclidom>::swap (chain<euclidom> &other,
00886 int number, int othernumber, chain<euclidom> *table)
00887 {
00888
00889 bool a = allocated ();
00890 bool oa = other. allocated ();
00891
00892
00893 if (a && oa)
00894 {
00895 swapelements (t. n, other. t. n);
00896 swapelements (t. e, other. t. e);
00897 }
00898 else if (!a && !oa)
00899 {
00900
00901 int i;
00902
00903
00904 for (i = 0; (i < len) && (i < other. len); ++ i)
00905 {
00906 swapelements (x. n [i], other. x. n [i]);
00907 swapelements (x. e [i], other. x. e [i]);
00908 }
00909
00910
00911 for (i = len; i < other. len; ++ i)
00912 {
00913 x. n [i] = other. x. n [i];
00914 x. e [i] = other. x. e [i];
00915 }
00916 for (i = other. len; i < len; ++ i)
00917 {
00918 other. x. n [i] = x. n [i];
00919 other. x. e [i] = x. e [i];
00920 }
00921 }
00922 else if (a)
00923 {
00924 int *tempn = t. n;
00925 euclidom *tempe = t. e;
00926 for (int i = 0; i < other. len; ++ i)
00927 {
00928 x. n [i] = other. x. n [i];
00929 x. e [i] = other. x. e [i];
00930 }
00931 other. t. n = tempn;
00932 other. t. e = tempe;
00933 }
00934 else
00935 {
00936 int *tempn = other. t. n;
00937 euclidom *tempe = other. t. e;
00938 for (int i = 0; i < len; ++ i)
00939 {
00940 other. x. n [i] = x. n [i];
00941 other. x. e [i] = x. e [i];
00942 }
00943 t. n = tempn;
00944 t. e = tempe;
00945 }
00946
00947
00948 swapelements (len, other. len);
00949
00950 if (!table)
00951 return *this;
00952
00953
00954 int *tntab = oa ? t. n : x. n;
00955 int *ontab = a ? other. t. n : other. x. n;
00956 int i = 0, j = 0;
00957 while ((i < len) || (j < other. len))
00958 {
00959
00960 int n;
00961 if (i >= len)
00962 n = ontab [j ++];
00963 else if (j >= other. len)
00964 n = tntab [i ++];
00965 else if (tntab [i] < ontab [j])
00966 n = tntab [i ++];
00967 else if (ontab [j] < tntab [i])
00968 n = ontab [j ++];
00969 else
00970 {
00971 n = tntab [i ++];
00972 ++ j;
00973
00974
00975
00976 }
00977
00978
00979 table [n]. swapnumbers (othernumber, number);
00980 }
00981
00982 return *this;
00983 }
00984
00985 template <class euclidom>
00986 inline chain<euclidom> &chain<euclidom>::take (chain<euclidom> &c)
00987 {
00988
00989 if (allocated ())
00990 {
00991 delete [] t. n;
00992 delete [] t. e;
00993 }
00994
00995
00996 if (c. allocated ())
00997 {
00998 t. n = c. t. n;
00999 t. e = c. t. e;
01000 }
01001
01002
01003 else
01004 {
01005 for (int i = 0; i < c. len; ++ i)
01006 {
01007 x. n [i] = c. x. n [i];
01008 x. e [i] = c. x. e [i];
01009 }
01010 }
01011
01012
01013 len = c. len;
01014 c. len = 0;
01015
01016 return *this;
01017 }
01018
01019 template <class euclidom>
01020 inline chain<euclidom> &chain<euclidom>::multiply (euclidom e, int number)
01021 {
01022
01023 bool a = allocated ();
01024 int *tntab = a ? t. n : x. n;
01025 euclidom *tetab = a ? t. e : x. e;
01026
01027
01028 if (number >= 0)
01029 {
01030 for (int i = 0; i < len; ++ i)
01031 {
01032 if (tntab [i] == number)
01033 {
01034 if (e == 0)
01035 removepair (i);
01036 else
01037 {
01038 tetab [i] *= e;
01039
01040
01041 }
01042 return *this;
01043 }
01044 }
01045 }
01046
01047
01048 else if (e != 0)
01049 {
01050 for (int i = 0; i < len; ++ i)
01051 {
01052 tetab [i] *= e;
01053 if (tetab [i] == 0)
01054 removepair (i);
01055 }
01056 }
01057
01058
01059 else
01060 {
01061 if (a)
01062 {
01063 delete [] t. n;
01064 delete [] t. e;
01065 }
01066 len = 0;
01067 }
01068
01069 return *this;
01070 }
01071
01072 template <class euclidom>
01073 inline outputstream &chain<euclidom>::show (outputstream &out,
01074 const char *label) const
01075 {
01076 if (len <= 0)
01077 out << "0";
01078 bool a = allocated ();
01079 const int *tntab = a ? t. n : x. n;
01080 const euclidom *tetab = a ? t. e : x. e;
01081 for (int i = 0; i < len; ++ i)
01082 {
01083 euclidom e = tetab [i];
01084 int n = tntab [i] + 1;
01085
01086 if (e == 1)
01087 out << (i ? " + " : "") <<
01088 (label ? label : "") << n;
01089 else if (-e == 1)
01090 out << (i ? " - " : "-") <<
01091 (label ? label : "") << n;
01092 else
01093 out << (i ? " + " : "") << e << " * " <<
01094 (label ? label : "") << n;
01095 }
01096 return out;
01097 }
01098
01099 template <class euclidom>
01100 inline std::ostream &chain<euclidom>::show (std::ostream &out, const char *label) const
01101 {
01102 outputstream tout (out);
01103 show (tout, label);
01104 return out;
01105 }
01106
01107
01108
01111 template <class euclidom>
01112 inline std::ostream &operator << (std::ostream &out, const chain<euclidom> &c)
01113 {
01114 c. show (out);
01115 return out;
01116 }
01117
01120 template <class euclidom>
01121 inline std::istream &operator >> (std::istream &in, chain<euclidom> &c)
01122 {
01123 ignorecomments (in);
01124 int closing = readparenthesis (in);
01125
01126 ignorecomments (in);
01127 while (in. peek () != closing)
01128 {
01129
01130 euclidom e (1);
01131 in >> e;
01132
01133
01134 ignorecomments (in);
01135 if (in. peek () != '*')
01136 throw "The multiplication sign '*' while reading a chain.";
01137 in. get ();
01138
01139
01140 ignorecomments (in);
01141 int n;
01142 in >> n;
01143 -- n;
01144
01145
01146 if (e == 0)
01147 throw "A zero coefficient in a chain detected.";
01148
01149
01150 c. add (e, n);
01151
01152
01153 ignorecomments (in);
01154
01155
01156 if ((in. peek () == ',') || (in. peek () == '+'))
01157 {
01158 in. get ();
01159 ignorecomments (in);
01160 }
01161 }
01162
01163 if (closing != EOF)
01164 in. get ();
01165
01166 return in;
01167 }
01168
01169
01170
01171
01172
01173
01176 template <class element>
01177 class simplelist
01178 {
01179 public:
01181 simplelist ();
01182
01184 ~simplelist ();
01185
01187 void add (element &m);
01188
01190 void remove (element &m);
01191
01197 element *take ();
01198
01199 private:
01201 simplelist (const simplelist<element> &s)
01202 {
01203 throw "Copying constructor not implemented "
01204 "for a simple list.";
01205 return;
01206 }
01207
01209 simplelist<element> &operator = (const simplelist<element> &s)
01210 {
01211 throw "Operator = not implemented "
01212 "for a simple list.";
01213 return *this;
01214 }
01215
01217 int num;
01218
01220 int cur;
01221
01223 element **elem;
01224
01225 };
01226
01227
01228
01229 template <class element>
01230 inline simplelist<element>::simplelist (): num (0), cur (0), elem (NULL)
01231 {
01232 return;
01233 }
01234
01235 template <class element>
01236 inline simplelist<element>::~simplelist ()
01237 {
01238 if (elem)
01239 delete [] elem;
01240 return;
01241 }
01242
01243 template <class element>
01244 inline void simplelist<element>::add (element &m)
01245 {
01246 element **newelem = new element * [num + 1];
01247 for (int i = 0; i < num; ++ i)
01248 newelem [i] = elem [i];
01249 newelem [num ++] = &m;
01250 delete [] elem;
01251 elem = newelem;
01252 return;
01253 }
01254
01255 template <class element>
01256 inline void simplelist<element>::remove (element &m)
01257 {
01258 int pos = 0;
01259 while ((pos < num) && (elem [pos] != &m))
01260 ++ pos;
01261 -- num;
01262 while (pos < num)
01263 {
01264 elem [pos] = elem [pos + 1];
01265 ++ pos;
01266 }
01267 return;
01268 }
01269
01270 template <class element>
01271 inline element *simplelist<element>::take ()
01272 {
01273 if (cur >= num)
01274 {
01275 cur = 0;
01276 return NULL;
01277 }
01278 else
01279 {
01280 return elem [cur ++];
01281 }
01282 }
01283
01284
01285
01286
01287
01288
01292 template <class euclidom>
01293 class mmatrix
01294 {
01295 public:
01297 mmatrix ();
01298
01301 mmatrix (const mmatrix<euclidom> &m);
01302
01305 mmatrix<euclidom> &operator = (const mmatrix<euclidom> &s);
01306
01308 ~mmatrix ();
01309
01312 void define (int numrows, int numcols);
01313
01315 void identity (int size);
01316
01318 void add (int row, int col, const euclidom &e);
01319
01323 euclidom get (int row, int col) const;
01324
01326 const chain<euclidom> &getrow (int n) const;
01327
01329 const chain<euclidom> &getcol (int n) const;
01330
01332 int getnrows () const;
01333
01335 int getncols () const;
01336
01339 void addrow (int dest, int source, const euclidom &e);
01340
01343 void addcol (int dest, int source, const euclidom &e);
01344
01346 void swaprows (int i, int j);
01347
01349 void swapcols (int i, int j);
01350
01352 void multiplyrow (int n, const euclidom &e);
01353
01355 void multiplycol (int n, const euclidom &e);
01356
01362 int findrow (int req_elements = 1, int start = -1) const;
01363
01369 int findcol (int req_elements = 1, int start = -1) const;
01370
01375 int reducerow (int n, int preferred);
01376
01381 int reducecol (int n, int preferred);
01382
01386 void simple_reductions (bool quiet = false);
01387
01389 void simple_form (bool quiet = false);
01390
01392 void invert (void);
01393
01396 void multiply (const mmatrix<euclidom> &m1,
01397 const mmatrix<euclidom> &m2);
01398
01405 simplelist<mmatrix<euclidom> > dom_dom, dom_img, img_dom,
01406 img_img;
01407
01411 void submatrix (const mmatrix<euclidom> &matr,
01412 const chain<euclidom> &domain,
01413 const chain<euclidom> &range);
01414
01417 outputstream &show_hom_col (outputstream &out, int col,
01418 const chain<euclidom> &range,
01419 const char *txt = NULL) const;
01420
01423 std::ostream &show_hom_col (std::ostream &out, int col,
01424 const chain<euclidom> &range,
01425 const char *txt = NULL) const;
01426
01428 outputstream &showrowscols (outputstream &out,
01429 chain<euclidom> *table, int tablen,
01430 int first = 0, int howmany = 0,
01431 const char *label = NULL) const;
01432
01434 outputstream &showrows (outputstream &out, int first = 0,
01435 int howmany = 0, const char *label = "Row ") const;
01436
01438 std::ostream &showrows (std::ostream &out, int first = 0,
01439 int howmany = 0, const char *label = "Row ") const;
01440
01442 outputstream &showcols (outputstream &out, int first = 0,
01443 int howmany = 0, const char *label = "Col ") const;
01444
01446 std::ostream &showcols (std::ostream &out, int first = 0,
01447 int howmany = 0, const char *label = "Col ") const;
01448
01450 outputstream &showmap (outputstream &out,
01451 const char *maplabel = NULL,
01452 const char *xlabel = NULL, const char *ylabel = NULL)
01453 const;
01454
01456 std::ostream &showmap (std::ostream &out, const char *maplabel = NULL,
01457 const char *xlabel = NULL, const char *ylabel = NULL)
01458 const;
01459
01460 private:
01462 int nrows;
01463
01465 int ncols;
01466
01468 int allrows;
01469
01471 int allcols;
01472
01474 chain<euclidom> *rows;
01475
01477 chain<euclidom> *cols;
01478
01480 int findrowcol (int req_elements, int start, int which) const;
01481
01484 void increase (int numrows, int numcols);
01485
01487 void increaserows (int numrows);
01488
01491 void increasecols (int numcols);
01492
01493 };
01494
01495
01496
01497 template <class euclidom>
01498 inline mmatrix<euclidom>::mmatrix (): nrows (0), ncols (0),
01499 allrows (0), allcols (0), rows (NULL), cols (NULL)
01500 {
01501 return;
01502 }
01503
01504 template <class euclidom>
01505 inline mmatrix<euclidom>::~mmatrix ()
01506 {
01507 if (rows)
01508 delete [] rows;
01509 if (cols)
01510 delete [] cols;
01511 return;
01512 }
01513
01514 template <class euclidom>
01515 inline void mmatrix<euclidom>::define (int numrows, int numcols)
01516 {
01517
01518 if ((nrows > numrows) || (ncols > numcols))
01519 throw "Trying to define a matrix smaller than it really is";
01520
01521
01522 increase (numrows, numcols);
01523
01524
01525 nrows = numrows;
01526 ncols = numcols;
01527
01528 return;
01529 }
01530
01531 template <class euclidom>
01532 inline mmatrix<euclidom>::mmatrix (const mmatrix<euclidom> &m)
01533 {
01534 nrows = m.nrows;
01535 ncols = m.ncols;
01536 allrows = m.allrows;
01537 allcols = m.allcols;
01538
01539 rows = NULL;
01540 cols = NULL;
01541 if (m. allrows > 0)
01542 {
01543 chain<euclidom> *newrows = new chain<euclidom> [m. allrows];
01544 if (!newrows)
01545 throw "Not enough memory for matrix rows.";
01546 for (int i = 0; i < m. allrows; ++ i)
01547 newrows [i] = m. rows [i];
01548 rows = newrows;
01549 }
01550
01551 if (m. allcols > 0)
01552 {
01553 chain<euclidom> *newcols = new chain<euclidom> [m. allcols];
01554 if (!newcols)
01555 throw "Not enough memory for matrix columns.";
01556 for (int i = 0; i < m.allcols; ++ i)
01557 newcols [i] = m. cols [i];
01558 cols = newcols;
01559 }
01560 }
01561
01562 template <class euclidom>
01563 inline mmatrix<euclidom> &mmatrix<euclidom>::operator =
01564 (const mmatrix<euclidom> &m)
01565 {
01566
01567 if (rows)
01568 delete [] rows;
01569 if (cols)
01570 delete [] cols;
01571
01572 nrows = m. nrows;
01573 ncols = m. ncols;
01574 allrows = m. allrows;
01575 allcols = m. allcols;
01576
01577 rows = NULL;
01578 cols = NULL;
01579 if (m. allrows > 0)
01580 {
01581 chain<euclidom> *newrows = new chain<euclidom> [m. allrows];
01582 if (!newrows)
01583 throw "Not enough memory for matrix rows.";
01584 for (int i = 0; i < m. allrows; ++ i)
01585 newrows [i] = m. rows [i];
01586 rows = newrows;
01587 }
01588
01589 if (m. allcols > 0)
01590 {
01591 chain<euclidom> *newcols = new chain<euclidom> [m. allcols];
01592 if (!newcols)
01593 throw "Not enough memory for matrix columns.";
01594 for (int i = 0; i < m.allcols; ++ i)
01595 newcols [i] = m. cols [i];
01596 cols = newcols;
01597 }
01598
01599 return *this;
01600 }
01601
01602 template <class euclidom>
01603 inline void mmatrix<euclidom>::identity (int size)
01604 {
01605 if (!nrows && !ncols)
01606 increase (size, size);
01607 else if ((size > nrows) || (size > ncols))
01608 size = (nrows < ncols) ? nrows : ncols;
01609 for (int i = 0; i < size; ++ i)
01610 {
01611 euclidom one;
01612 one = 1;
01613 add (i, i, one);
01614 }
01615 return;
01616 }
01617
01618 template <class euclidom>
01619 inline void mmatrix<euclidom>::add (int row, int col, const euclidom &e)
01620
01621 {
01622 if (row < 0)
01623 throw "Incorrect row number.";
01624 if (col < 0)
01625 throw "Incorrect column number.";
01626 if (row >= nrows)
01627 {
01628 if (row >= allrows)
01629 increaserows (row + row / 2 + 1);
01630 nrows = row + 1;
01631 }
01632 if (col >= ncols)
01633 {
01634 if (col >= allcols)
01635 increasecols (col + col / 2 + 1);
01636 ncols = col + 1;
01637 }
01638 if (e == 0)
01639 return;
01640 cols [col]. add (row, e);
01641 rows [row]. add (col, e);
01642 return;
01643 }
01644
01645 template <class euclidom>
01646 inline euclidom mmatrix<euclidom>::get (int row, int col) const
01647
01648 {
01649 if ((row >= nrows) || (col >= ncols))
01650 {
01651 euclidom zero;
01652 zero = 0;
01653 return zero;
01654 }
01655 if (row >= 0)
01656 return rows [row]. getcoefficient (col);
01657 else if (col >= 0)
01658 return cols [col]. getcoefficient (row);
01659 else
01660 {
01661 euclidom zero;
01662 zero = 0;
01663 return zero;
01664 }
01665 }
01666
01667 template <class euclidom>
01668 inline const chain<euclidom> &mmatrix<euclidom>::getrow (int n) const
01669 {
01670 if ((n < 0) || (n >= nrows))
01671 throw "Incorrect row number.";
01672 return rows [n];
01673 }
01674
01675 template <class euclidom>
01676 inline const chain<euclidom> &mmatrix<euclidom>::getcol (int n) const
01677 {
01678 if ((n < 0) || (n >= ncols))
01679 throw "Incorrect column number.";
01680 return cols [n];
01681 }
01682
01683 template <class euclidom>
01684 inline int mmatrix<euclidom>::getnrows () const
01685 {
01686 return nrows;
01687 }
01688
01689 template <class euclidom>
01690 inline int mmatrix<euclidom>::getncols () const
01691 {
01692 return ncols;
01693 }
01694
01695 template <class euclidom>
01696 inline void mmatrix<euclidom>::addrow (int dest, int source,
01697 const euclidom &e)
01698 {
01699
01700 if ((dest < 0) || (dest >= nrows) || (source < 0) ||
01701 (source >= nrows))
01702 throw "Trying to add rows out of range.";
01703
01704
01705 rows [dest]. add (rows [source], e, dest, cols);
01706
01707
01708 mmatrix<euclidom> *m;
01709 while ((m = img_img. take ()) != NULL)
01710 if (m -> rows)
01711 m -> rows [dest]. add (m -> rows [source], e,
01712 dest, m -> cols);
01713
01714 while ((m = img_dom. take ()) != NULL)
01715 if (m -> cols)
01716 m -> cols [source]. add (m -> cols [dest], -e,
01717 source, m -> rows);
01718
01719 return;
01720 }
01721
01722 template <class euclidom>
01723 inline void mmatrix<euclidom>::addcol (int dest, int source,
01724 const euclidom &e)
01725 {
01726
01727 if ((dest < 0) || (dest >= ncols) || (source < 0) ||
01728 (source >= ncols))
01729 throw "Trying to add columns out of range.";
01730
01731
01732 cols [dest]. add (cols [source], e, dest, rows);
01733
01734
01735 mmatrix<euclidom> *m;
01736 while ((m = dom_dom. take ()) != NULL)
01737 if (m -> cols)
01738 m -> cols [dest]. add (m -> cols [source], e,
01739 dest, m -> rows);
01740
01741 while ((m = dom_img. take ()) != NULL)
01742 if (m -> rows)
01743 m -> rows [source]. add (m -> rows [dest], -e,
01744 source, m -> cols);
01745
01746 return;
01747 }
01748
01749 template <class euclidom>
01750 inline void mmatrix<euclidom>::swaprows (int i, int j)
01751 {
01752
01753 if (i == j)
01754 return;
01755
01756
01757 if ((i < 0) || (i >= nrows) || (j < 0) || (j >= nrows))
01758 throw "Trying to swap rows out of range.";
01759
01760
01761 rows [i]. swap (rows [j], i, j, cols);
01762
01763
01764 mmatrix<euclidom> *m;
01765 while ((m = img_img. take ()) != NULL)
01766 if ((m -> rows) && (m -> nrows))
01767 m -> rows [i]. swap (m -> rows [j], i, j, m -> cols);
01768
01769 while ((m = img_dom. take ()) != NULL)
01770 if ((m -> cols) && (m -> ncols))
01771 m -> cols [i]. swap (m -> cols [j], i, j, m -> rows);
01772
01773 return;
01774 }
01775
01776 template <class euclidom>
01777 inline void mmatrix<euclidom>::swapcols (int i, int j)
01778 {
01779
01780 if (i == j)
01781 return;
01782
01783
01784 if ((i < 0) || (i >= ncols) || (j < 0) || (j >= ncols))
01785 throw "Trying to swap cols out of range.";
01786
01787
01788 cols [i]. swap (cols [j], i, j, rows);
01789
01790
01791 mmatrix<euclidom> *m;
01792 while ((m = dom_dom. take ()) != NULL)
01793 if ((m -> cols) && (m -> ncols))
01794 m -> cols [i]. swap (m -> cols [j], i, j, m -> rows);
01795
01796 while ((m = dom_img. take ()) != NULL)
01797 if ((m -> rows) && (m -> nrows))
01798 m -> rows [i]. swap (m -> rows [j], i, j, m -> cols);
01799
01800 return;
01801 }
01802
01803 template <class euclidom>
01804 inline void mmatrix<euclidom>::multiplyrow (int n, const euclidom &e)
01805 {
01806
01807 chain<euclidom> &therow = rows [n];
01808
01809
01810 therow. multiply (e);
01811
01812
01813 for (int i = 0; i < therow. size (); ++ i)
01814 cols [therow. num (i)]. multiply (e, n);
01815
01816 return;
01817 }
01818
01819 template <class euclidom>
01820 inline void mmatrix<euclidom>::multiplycol (int n, const euclidom &e)
01821 {
01822
01823 chain<euclidom> &thecol = cols [n];
01824
01825
01826 thecol. multiply (e);
01827
01828
01829 for (int i = 0; i < thecol. size (); ++ i)
01830 rows [thecol. num (i)]. multiply (e, n);
01831
01832 return;
01833 }
01834
01835 template <class euclidom>
01836 inline int mmatrix<euclidom>::findrowcol (int req_elements, int start,
01837 int which) const
01838
01839 {
01840
01841 int i = start;
01842 int random_i = -1;
01843
01844
01845 int loopcounter = 0;
01846
01847
01848 if (start < 0)
01849 {
01850 i = random_i = std::rand () % (which ? nrows : ncols);
01851 loopcounter = 1;
01852 }
01853
01854
01855 int candidate = -1;
01856 int candidates_left = 3;
01857
01858
01859 if (which ? !ncols : !nrows)
01860 return (((req_elements > 0) ||
01861 (i >= (which ? nrows : ncols))) ? -1 : i);
01862
01863
01864 while (i < (which ? nrows : ncols))
01865 {
01866
01867 int l = (which ? rows : cols) [i]. size ();
01868 if ((req_elements >= 0) && (l >= req_elements))
01869 return i;
01870 else if ((req_elements < 0) && !l)
01871 {
01872 if (!candidates_left || !(which ? rows : cols) [i].
01873 contains_non_invertible ())
01874 return i;
01875 else
01876 {
01877 candidate = i;
01878 -- candidates_left;
01879 if (start < 0)
01880 {
01881 random_i = std::rand () %
01882 (which ? nrows : ncols);
01883 i = random_i - 1;
01884 loopcounter = 1;
01885 }
01886 }
01887 }
01888
01889
01890 if (++ i >= (which ? nrows : ncols))
01891 if (loopcounter --)
01892 i = 0;
01893
01894
01895
01896 if ((random_i >= 0) && !loopcounter && (i >= random_i))
01897 break;
01898 }
01899
01900
01901 return candidate;
01902 }
01903
01904 template <class euclidom>
01905 inline int mmatrix<euclidom>::findrow (int req_elements, int start) const
01906 {
01907 return findrowcol (req_elements, start, 1);
01908 }
01909
01910 template <class euclidom>
01911 inline int mmatrix<euclidom>::findcol (int req_elements, int start) const
01912 {
01913 return findrowcol (req_elements, start, 0);
01914 }
01915
01916 template <class euclidom>
01917 inline int mmatrix<euclidom>::reducerow (int n, int preferred)
01918 {
01919 if (n >= nrows)
01920 throw "Trying to reduce a row out of range.";
01921
01922 int the_other = -1;
01923
01924
01925 int len;
01926 while ((len = rows [n]. size ()) > 1)
01927 {
01928
01929 chain<euclidom> local (rows [n]);
01930
01931
01932 int best_i = local. findbest (cols);
01933
01934
01935 int preferred_i = (preferred < 0) ? -1 :
01936 local. findnumber (preferred);
01937
01938
01939
01940 if ((preferred_i >= 0) &&
01941 (local. coef (preferred_i). delta () ==
01942 local. coef (best_i). delta ()))
01943 best_i = preferred_i;
01944
01945
01946 the_other = local. num (best_i);
01947
01948
01949 for (int i = 0; i < len; ++ i)
01950 {
01951
01952 if (i == best_i)
01953 continue;
01954
01955
01956 euclidom quotient = local. coef (i) /
01957 local. coef (best_i);
01958
01959
01960 addcol (local. num (i), local. num (best_i),
01961 -quotient);
01962 }
01963 }
01964
01965 return the_other;
01966 }
01967
01968 template <class euclidom>
01969 inline int mmatrix<euclidom>::reducecol (int n, int preferred)
01970 {
01971 if (n >= ncols)
01972 throw "Trying to reduce a column out of range.";
01973
01974 int the_other = -1;
01975
01976
01977 int len;
01978 while ((len = cols [n]. size ()) > 1)
01979 {
01980
01981 chain<euclidom> local (cols [n]);
01982
01983
01984 int best_i = local. findbest (rows);
01985
01986
01987 int preferred_i = (preferred < 0) ? -1 :
01988 local. findnumber (preferred);
01989
01990
01991
01992 if ((preferred_i >= 0) &&
01993 (local. coef (preferred_i). delta () ==
01994 local. coef (best_i). delta ()))
01995 best_i = preferred_i;
01996
01997
01998 the_other = local. num (best_i);
01999
02000
02001 for (int i = 0; i < len; ++ i)
02002 {
02003
02004 if (i == best_i)
02005 continue;
02006
02007
02008 euclidom quotient = local. coef (i) /
02009 local. coef (best_i);
02010
02011
02012 addrow (local. num (i), local. num (best_i),
02013 -quotient);
02014 }
02015 }
02016
02017 return the_other;
02018 }
02019
02020 template <class euclidom>
02021 inline outputstream &mmatrix<euclidom>::showrowscols (outputstream &out,
02022 chain<euclidom> *table, int tablen, int first, int howmany,
02023 const char *label) const
02024 {
02025 if ((first < 0) || (first >= tablen))
02026 first = 0;
02027 if ((howmany <= 0) || (first + howmany > tablen))
02028 howmany = tablen - first;
02029 for (int i = 0; i < howmany; ++ i)
02030 out << (label ? label : "") << (first + i + 1) << ": " <<
02031 table [first + i] << '\n';
02032 out << '\n';
02033 return out;
02034 }
02035
02036 template <class euclidom>
02037 inline outputstream &mmatrix<euclidom>::showrows (outputstream &out,
02038 int first, int howmany, const char *label) const
02039 {
02040 return showrowscols (out, rows, nrows, first, howmany, label);
02041 }
02042
02043 template <class euclidom>
02044 inline std::ostream &mmatrix<euclidom>::showrows (std::ostream &out,
02045 int first, int howmany, const char *label) const
02046 {
02047 outputstream tout (out);
02048 showrows (tout, first, howmany, label);
02049 return out;
02050 }
02051
02052 template <class euclidom>
02053 inline outputstream &mmatrix<euclidom>::showcols (outputstream &out,
02054 int first, int howmany, const char *label) const
02055 {
02056 return showrowscols (out, cols, ncols, first, howmany, label);
02057 }
02058
02059 template <class euclidom>
02060 inline std::ostream &mmatrix<euclidom>::showcols (std::ostream &out,
02061 int first, int howmany, const char *label) const
02062 {
02063 outputstream tout (out);
02064 showcols (tout, first, howmany, label);
02065 return out;
02066 }
02067
02068 template <class euclidom>
02069 inline outputstream &mmatrix<euclidom>::showmap (outputstream &out,
02070 const char *maplabel, const char *xlabel, const char *ylabel) const
02071 {
02072 if (ncols <= 0)
02073 {
02074 if (maplabel && (maplabel [0] == '\t'))
02075 out << "\t0\n";
02076 else
02077 out << "0\n";
02078 }
02079 for (int i = 0; i < ncols; ++ i)
02080 {
02081 out << (maplabel ? maplabel : "f") << " (" <<
02082 (xlabel ? xlabel : "") << (i + 1) << ") = ";
02083 cols [i]. show (out, ylabel) << '\n';
02084 }
02085 return out;
02086 }
02087
02088 template <class euclidom>
02089 inline std::ostream &mmatrix<euclidom>::showmap (std::ostream &out,
02090 const char *maplabel, const char *xlabel, const char *ylabel) const
02091 {
02092 outputstream tout (out);
02093 showmap (tout, maplabel, xlabel, ylabel);
02094 return out;
02095 }
02096
02097 template <class euclidom>
02098 inline void mmatrix<euclidom>::simple_reductions (bool quiet)
02099 {
02100
02101
02102 if (!nrows || !ncols)
02103 return;
02104
02105
02106 long countreduced = 0;
02107 long count = 4 * ((nrows > ncols) ? ncols : nrows);
02108
02109
02110 int nr = std::rand () % nrows;
02111 int nr_count = 0;
02112 int nr_add = 0;
02113
02114
02115 while (count --)
02116 {
02117
02118 if ((rows [nr]. size () == 1) &&
02119 (rows [nr]. coef (0). delta () == 1) &&
02120 (cols [rows [nr]. num (0)]. size () > 1))
02121 {
02122 ++ countreduced;
02123 reducecol (rows [nr]. num (0), -1);
02124 }
02125
02126
02127 if (nr_count)
02128 -- nr_count;
02129 else
02130 {
02131 nr_add = ((std::rand () >> 2) + 171) % nrows;
02132 if (nr_add < 1)
02133 nr_add = 1;
02134 nr_count = 100;
02135 }
02136 nr += nr_add;
02137 if (nr >= nrows)
02138 nr -= nrows;
02139
02140
02141 if (!quiet && !(count % 373))
02142 scon << std::setw (12) << count <<
02143 "\b\b\b\b\b\b\b\b\b\b\b\b";
02144 }
02145
02146 if (!quiet)
02147 sout << countreduced << " +";
02148
02149 return;
02150 }
02151
02152 template <class euclidom>
02153 inline void mmatrix<euclidom>::simple_form (bool quiet)
02154 {
02155
02156 if (!nrows || !ncols)
02157 return;
02158
02159
02160 simple_reductions (quiet);
02161
02162
02163 long count = 0;
02164
02165
02166 int row, col, prev_row, prev_col;
02167
02168
02169 row = -1;
02170 col = findcol (2);
02171 prev_row = -1, prev_col = -1;
02172 if (col < 0)
02173 row = findrow (2);
02174
02175
02176 while ((row >= 0) || (col >= 0))
02177 {
02178
02179 while ((row >= 0) || (col >= 0))
02180 if (row >= 0)
02181 {
02182 col = reducerow (row, prev_col);
02183 prev_row = row;
02184 row = -1;
02185 }
02186 else if (col >= 0)
02187 {
02188 row = reducecol (col, prev_row);
02189 prev_col = col;
02190 col = -1;
02191 }
02192
02193
02194 ++ count;
02195 if (!quiet && !(count % 373))
02196 scon << std::setw (12) << count <<
02197 "\b\b\b\b\b\b\b\b\b\b\b\b";
02198
02199
02200 col = findcol (2);
02201 if (col < 0)
02202 row = findrow (2);
02203 }
02204
02205 if (!quiet)
02206 sout << " " << count << " reductions made. ";
02207
02208 return;
02209 }
02210
02211 template <class euclidom>
02212 inline void mmatrix<euclidom>::invert (void)
02213 {
02214
02215 if (nrows != ncols)
02216 throw "Trying to invert a non-square matrix.";
02217
02218
02219 if (!nrows)
02220 return;
02221
02222
02223 mmatrix<euclidom> m;
02224 m. identity (ncols);
02225
02226
02227
02228
02229 for (int col = 0; col < ncols; ++ col)
02230 {
02231
02232 int len = cols [col]. size ();
02233 if (len <= 0)
02234 {
02235 throw "Matrix inverting: Zero column found.";
02236 }
02237 int chosen = 0;
02238 while ((chosen < len) &&
02239 ((cols [col]. num (chosen) < col) ||
02240 (cols [col]. coef (chosen). delta () != 1)))
02241 {
02242 ++ chosen;
02243 }
02244 if (chosen >= len)
02245 {
02246 throw "Matrix inverting: "
02247 "No invertible element in a column.";
02248 }
02249
02250
02251 euclidom invcoef;
02252 invcoef = 1;
02253 invcoef = invcoef / cols [col]. coef (chosen);
02254 m. multiplyrow (cols [col]. num (chosen), invcoef);
02255 multiplyrow (cols [col]. num (chosen), invcoef);
02256
02257
02258 m. swaprows (col, cols [col]. num (chosen));
02259 swaprows (col, cols [col]. num (chosen));
02260
02261
02262 invcoef = -1;
02263 for (int i = 0; i < len; ++ i)
02264 {
02265 if (cols [col]. num (i) == col)
02266 continue;
02267 euclidom coef = invcoef * cols [col]. coef (i);
02268 m. addrow (cols [col]. num (i), col, coef);
02269 addrow (cols [col]. num (i), col, coef);
02270 -- i;
02271 -- len;
02272 }
02273 }
02274
02275
02276 for (int i = 0; i < ncols; ++ i)
02277 {
02278 cols [i]. take (m. cols [i]);
02279 rows [i]. take (m. rows [i]);
02280 }
02281
02282 return;
02283 }
02284
02285 template <class euclidom>
02286 inline void mmatrix<euclidom>::multiply (const mmatrix<euclidom> &m1,
02287 const mmatrix<euclidom> &m2)
02288 {
02289 if (m1. ncols != m2. nrows)
02290 throw "Trying to multiply matrices of wrong sizes.";
02291 int K = m1. ncols;
02292 define (m1. nrows, m2. ncols);
02293 for (int i = 0; i < nrows; ++ i)
02294 {
02295 for (int j = 0; j < ncols; ++ j)
02296 {
02297 euclidom e;
02298 e = 0;
02299 for (int k = 0; k < K; ++ k)
02300 e += m1. get (i, k) * m2. get (k, j);
02301 add (i, j, e);
02302 }
02303 }
02304 return;
02305 }
02306
02307 template <class euclidom>
02308 inline void mmatrix<euclidom>::submatrix (const mmatrix<euclidom> &matr,
02309 const chain<euclidom> &domain, const chain<euclidom> &range)
02310 {
02311 for (int i = 0; i < domain. size (); ++ i)
02312 {
02313 for (int j = 0; j < range. size (); ++ j)
02314 {
02315 euclidom e = matr. get (domain. num (i),
02316 range. num (j));
02317 if (!(e == 0))
02318 add (i, j, e);
02319 }
02320 }
02321
02322 return;
02323 }
02324
02325 template <class euclidom>
02326 inline outputstream &mmatrix<euclidom>::show_hom_col (outputstream &out,
02327 int col, const chain<euclidom> &range, const char *txt) const
02328 {
02329
02330 int j = 0;
02331
02332
02333 int first = 1;
02334
02335
02336 for (int i = 0; i < cols [col]. size (); ++ i)
02337 {
02338
02339 while ((j < range. size ()) &&
02340 (range. num (j) < cols [col]. num (i)))
02341 {
02342 ++ j;
02343 }
02344
02345
02346 if ((j < range. size ()) &&
02347 (range. num (j) == cols [col]. num (i)))
02348 {
02349 if (first)
02350 first = 0;
02351 else
02352 out << " + ";
02353 if (-cols [col]. coef (i) == 1)
02354 out << "-";
02355 else if (cols [col]. coef (i) != 1)
02356 out << cols [col]. coef (i) << " * ";
02357 if (txt)
02358 out << txt;
02359 out << (j + 1);
02360 }
02361 }
02362
02363
02364 if (first)
02365 out << 0;
02366
02367 return out;
02368 }
02369
02370 template <class euclidom>
02371 inline std::ostream &mmatrix<euclidom>::show_hom_col (std::ostream &out, int col,
02372 const chain<euclidom> &range, const char *txt) const
02373 {
02374 outputstream tout (out);
02375 show_hom_col (tout, col, range, txt);
02376 return out;
02377 }
02378
02379
02380
02381 template <class euclidom>
02382 inline void mmatrix<euclidom>::increase (int numrows, int numcols)
02383 {
02384 increaserows (numrows);
02385 increasecols (numcols);
02386 return;
02387 }
02388
02389 template <class euclidom>
02390 inline void mmatrix<euclidom>::increaserows (int numrows)
02391 {
02392 if (allrows >= numrows)
02393 return;
02394 chain<euclidom> *newrows = new chain<euclidom> [numrows];
02395 if (!newrows)
02396 throw "Not enough memory for matrix rows.";
02397 for (int i = 0; i < nrows; ++ i)
02398 newrows [i]. take (rows [i]);
02399 if (rows)
02400 delete [] rows;
02401 rows = newrows;
02402 allrows = numrows;
02403 return;
02404 }
02405
02406 template <class euclidom>
02407 inline void mmatrix<euclidom>::increasecols (int numcols)
02408 {
02409 if (allcols >= numcols)
02410 return;
02411 chain<euclidom> *newcols = new chain<euclidom> [numcols];
02412 if (!newcols)
02413 throw "Not enough memory for matrix columns.";
02414 for (int i = 0; i < ncols; ++ i)
02415 newcols [i]. take (cols [i]);
02416 if (cols)
02417 delete [] cols;
02418 cols = newcols;
02419 allcols = numcols;
02420
02421 return;
02422 }
02423
02424
02425
02428 template <class euclidom>
02429 inline std::ostream &operator << (std::ostream &out,
02430 const mmatrix<euclidom> &m)
02431 {
02432 return m. showcols (out);
02433 }
02434
02435
02436
02437
02438
02439
02444 template <class euclidom>
02445 class chaincomplex
02446 {
02447 public:
02451 chaincomplex (int d, int trace_generators = 0);
02452
02454 ~chaincomplex ();
02455
02460 void def_gen (int q, int n);
02461
02464 void add (int q, int m, int n, const euclidom &e);
02465
02468 euclidom get (int q, int row, int col) const;
02469
02471 const mmatrix<euclidom> &getboundary (int i) const;
02472
02474 int getnumgen (int i) const;
02475
02477 int dim () const;
02478
02481 const chain<euclidom> &gethomgen (int q, int i) const;
02482
02485 void simple_form (int which, bool quiet);
02486
02491 void simple_form (const int *level, bool quiet);
02492
02498 int simple_homology (chain<euclidom> &result, int which) const;
02499
02508 int simple_homology (chain<euclidom> *&result,
02509 const int *level = NULL) const;
02510
02514 void take_homology (const chain<euclidom> *hom_chain);
02515
02519 outputstream &show_homology (outputstream &out,
02520 const chain<euclidom> *hom,
02521 const int *level = NULL) const;
02522
02526 std::ostream &show_homology (std::ostream &out,
02527 const chain<euclidom> *hom,
02528 const int *level = NULL) const;
02529
02533 outputstream &show_generators (outputstream &out,
02534 const chain<euclidom> &list, int q) const;
02535
02539 std::ostream &show_generators (std::ostream &out,
02540 const chain<euclidom> &list, int q) const;
02541
02543 outputstream &compute_and_show_homology (outputstream &out,
02544 chain<euclidom> *&hom, const int *level = NULL);
02545
02547 std::ostream &compute_and_show_homology (std::ostream &out,
02548 chain<euclidom> *&hom, const int *level = NULL);
02549
02552 friend class chainmap<euclidom>;
02553
02554 private:
02556 chaincomplex (const chaincomplex<euclidom> &m)
02557 {throw "Copying constructor not implemented "
02558 "for a chain complex.";}
02559
02561 chaincomplex<euclidom> &operator =
02562 (const chaincomplex<euclidom> &s)
02563 {throw "Operator = not implemented "
02564 "for a chain complex."; return *this;}
02565
02567 int len;
02568
02571 mmatrix<euclidom> *boundary;
02572
02575 mmatrix<euclidom> *generators;
02576
02579 int *generators_initialized;
02580
02583 int *numgen;
02584
02585 };
02586
02587
02588
02589 template <class euclidom>
02590 inline chaincomplex<euclidom>::chaincomplex (int d, int trace_generators)
02591 {
02592
02593 len = (d >= 0) ? (d + 1) : 0;
02594
02595
02596 boundary = len ? new mmatrix<euclidom> [len] : NULL;
02597
02598
02599 generators = (trace_generators && len) ?
02600 new mmatrix<euclidom> [len] : NULL;
02601 if (generators)
02602 generators_initialized = new int [len];
02603 else
02604 generators_initialized = NULL;
02605
02606
02607 numgen = len ? new int [len] : NULL;
02608
02609
02610 for (int i = 0; i < len; ++ i)
02611 {
02612 numgen [i] = -1;
02613 if (i < len - 1)
02614 boundary [i]. dom_img. add (boundary [i + 1]);
02615 if (i > 0)
02616 boundary [i]. img_dom. add (boundary [i - 1]);
02617 if (generators)
02618 {
02619 boundary [i]. dom_dom. add (generators [i]);
02620 if (i > 0)
02621 boundary [i]. img_dom. add
02622 (generators [i - 1]);
02623 generators_initialized [i] = 0;
02624 }
02625 }
02626
02627 return;
02628 }
02629
02630 template <class euclidom>
02631 inline chaincomplex<euclidom>::~chaincomplex ()
02632 {
02633 if (boundary)
02634 delete [] boundary;
02635 if (generators)
02636 delete [] generators;
02637 if (numgen)
02638 delete [] numgen;
02639 if (generators_initialized)
02640 delete [] generators_initialized;
02641 return;
02642 }
02643
02644 template <class euclidom>
02645 inline void chaincomplex<euclidom>::def_gen (int q, int n)
02646 {
02647 if ((q < 0) || (q >= len))
02648 return;
02649
02650 if (numgen [q] < n)
02651 numgen [q] = n;
02652
02653 if (q == 0)
02654 boundary [0]. define (0, numgen [q]);
02655 if ((q > 0) && (numgen [q - 1] >= 0))
02656 boundary [q]. define (numgen [q - 1], numgen [q]);
02657 if ((q < dim ()) && (numgen [q + 1] >= 0))
02658 boundary [q + 1]. define (numgen [q], numgen [q + 1]);
02659
02660 return;
02661 }
02662
02663 template <class euclidom>
02664 inline void chaincomplex<euclidom>::add (int q, int m, int n,
02665 const euclidom &e)
02666 {
02667 if ((q <= 0) || (q >= len))
02668 throw "Trying to add a boundary for dimension out of range";
02669
02670 if (numgen [q] <= n)
02671 numgen [q] = n + 1;
02672 if (numgen [q - 1] <= m)
02673 numgen [q - 1] = m + 1;
02674
02675 boundary [q]. add (m, n, e);
02676 return;
02677 }
02678
02679 template <class euclidom>
02680 inline euclidom chaincomplex<euclidom>::get (int q, int row, int col) const
02681 {
02682 if ((q <= 0) || (q >= len))
02683 throw "Boundary coefficient out of range from chain cplx.";
02684
02685 return boundary [q]. get (row, col);
02686 }
02687
02688 template <class euclidom>
02689 inline const mmatrix<euclidom> &chaincomplex<euclidom>::getboundary (int i)
02690 const
02691 {
02692 if ((i <= 0) || (i >= len))
02693 throw "Boundary matrix out of range from chain complex.";
02694
02695 return boundary [i];
02696 }
02697
02698 template <class euclidom>
02699 inline int chaincomplex<euclidom>::getnumgen (int i) const
02700 {
02701 if ((i < 0) || (i >= len))
02702
02703 return 0;
02704
02705 if (numgen [i] < 0)
02706 return 0;
02707 else
02708 return numgen [i];
02709 }
02710
02711 template <class euclidom>
02712 inline int chaincomplex<euclidom>::dim () const
02713 {
02714 return len - 1;
02715 }
02716
02717 template <class euclidom>
02718 inline const chain<euclidom> &chaincomplex<euclidom>::gethomgen (int q,
02719 int i) const
02720 {
02721 if ((q < 0) || (q >= len))
02722 throw "Level for homology generators out of range.";
02723 if (!generators_initialized [q])
02724 throw "Trying to get non-existent homology generators.";
02725 return generators [q]. getcol (i);
02726 }
02727
02728 template <class euclidom>
02729 inline void chaincomplex<euclidom>::simple_form (int which, bool quiet)
02730 {
02731
02732
02733
02734
02735 if (generators)
02736 {
02737 if (!generators_initialized [which])
02738 generators [which]. identity (numgen [which]);
02739 generators_initialized [which] = 1;
02740 if ((which > 0) && (!generators_initialized [which - 1]))
02741 {
02742 generators [which - 1]. identity
02743 (numgen [which - 1]);
02744 generators_initialized [which - 1] = 1;
02745 }
02746 }
02747
02748
02749 if (which > 0)
02750 {
02751 int n = boundary [which]. getnrows ();
02752 mmatrix<euclidom> &other = boundary [which - 1];
02753 if (other. getncols () < n)
02754 other. define (other. getnrows (), n);
02755 }
02756 if (which < len - 1)
02757 {
02758 int n = boundary [which]. getncols ();
02759 mmatrix<euclidom> &other = boundary [which + 1];
02760 if (other. getnrows () < n)
02761 other. define (n, other. getncols ());
02762 }
02763
02764
02765 if (!quiet && which)
02766 sout << "Reducing D_" << which << ": ";
02767 boundary [which]. simple_form (quiet);
02768 if (!quiet && which)
02769 sout << '\n';
02770
02771 return;
02772 }
02773
02774 template <class euclidom>
02775 inline void chaincomplex<euclidom>::simple_form (const int *level,
02776 bool quiet)
02777 {
02778 for (int i = len - 1; i >= 0; -- i)
02779 {
02780 if (!level || level [i] || (i && level [i - 1]))
02781 simple_form (i, quiet);
02782 }
02783 return;
02784 }
02785
02786 template <class euclidom>
02787 inline int chaincomplex<euclidom>::simple_homology (chain<euclidom> &result,
02788 int which) const
02789 {
02790 int g = boundary [which]. findcol (-1, 0);
02791 while (g >= 0)
02792 {
02793 euclidom e;
02794 if (which == dim ())
02795 e = 0;
02796 else
02797 e = boundary [which + 1]. get (g, -1);
02798 if (e == 0)
02799 {
02800 e = 1;
02801 result. add (g, e);
02802 }
02803 else if (e. delta () > 1)
02804 result. add (g, e. normalized ());
02805 g = boundary [which]. findcol (-1, g + 1);
02806 }
02807
02808 return which;
02809 }
02810
02811 template <class euclidom>
02812 inline int chaincomplex<euclidom>::simple_homology (chain<euclidom> *&result,
02813 const int *level) const
02814 {
02815
02816 if (!len)
02817 {
02818 result = NULL;
02819 return dim ();
02820 }
02821
02822 result = new chain<euclidom> [len];
02823 if (!result)
02824 throw "Not enough memory to create homology chains.";
02825
02826 for (int q = 0; q < len; ++ q)
02827 {
02828 if (!level || level [q])
02829 simple_homology (result [q], q);
02830 }
02831
02832 return dim ();
02833 }
02834
02835 template <class euclidom>
02836 inline void chaincomplex<euclidom>::take_homology
02837 (const chain<euclidom> *hom_chain)
02838 {
02839 if (!hom_chain)
02840 return;
02841 for (int q = 0; q < len; ++ q)
02842 def_gen (q, hom_chain [q]. size ());
02843 return;
02844 }
02845
02846 template <class euclidom>
02847 inline outputstream &chaincomplex<euclidom>::show_homology
02848 (outputstream &out, const chain<euclidom> *hom, const int *level)
02849 const
02850 {
02851 int max_level = len - 1;
02852 while ((max_level >= 0) && !hom [max_level]. size ())
02853 -- max_level;
02854 ++ max_level;
02855 for (int q = 0; q < max_level; ++ q)
02856 {
02857 if (!level || level [q])
02858 {
02859 out << "H_" << q << " = ";
02860 chomp::homology::show_homology (out, hom [q]);
02861 out << '\n';
02862 }
02863 }
02864 return out;
02865 }
02866
02867 template <class euclidom>
02868 inline std::ostream &chaincomplex<euclidom>::show_homology (std::ostream &out,
02869 const chain<euclidom> *hom, const int *level) const
02870 {
02871 outputstream tout (out);
02872 show_homology (tout, hom, level);
02873 return out;
02874 }
02875
02876 template <class euclidom>
02877 inline outputstream &chaincomplex<euclidom>::show_generators
02878 (outputstream &out, const chain<euclidom> &list, int q) const
02879 {
02880 if (!generators || (q < 0) || (q >= len))
02881 return out;
02882 for (int i = 0; i < list. size (); ++ i)
02883 out << gethomgen (q, list. num (i)) << '\n';
02884 return out;
02885 }
02886
02887 template <class euclidom>
02888 inline std::ostream &chaincomplex<euclidom>::show_generators (std::ostream &out,
02889 const chain<euclidom> &list, int q) const
02890 {
02891 outputstream tout (out);
02892 show_generators (tout, list, q);
02893 return out;
02894 }
02895
02896 template <class euclidom>
02897 inline outputstream &chaincomplex<euclidom>::compute_and_show_homology
02898 (outputstream &out, chain<euclidom> *&hom, const int *level)
02899 {
02900 simple_form (level, false);
02901 simple_homology (hom, level);
02902 show_homology (out, hom, level);
02903 return out;
02904 }
02905
02906 template <class euclidom>
02907 inline std::ostream &chaincomplex<euclidom>::compute_and_show_homology
02908 (std::ostream &out, chain<euclidom> *&hom, const int *level)
02909 {
02910 outputstream tout (out);
02911 compute_and_show_homology (tout, hom, level);
02912 return out;
02913 }
02914
02915
02916
02918 template <class euclidom>
02919 inline std::ostream &operator << (std::ostream &out,
02920 const chaincomplex<euclidom> &c)
02921 {
02922 out << "chain complex" << '\n';
02923 out << "max dimension " << c. dim () << '\n';
02924 out << "dimension 0: " << c. getnumgen (0) << '\n';
02925 for (int i = 1; i <= c. dim (); ++ i)
02926 {
02927 out << "dimension " << i << ": " << c. getnumgen (i) << '\n';
02928 for (int j = 0; j < c. getnumgen (i); ++ j)
02929 {
02930 if (c. getboundary (i). getcol (j). size ())
02931 {
02932 out << "\t# " << (j + 1) << " = " <<
02933 c. getboundary (i). getcol (j) <<
02934 '\n';
02935 }
02936 }
02937 }
02938 return out;
02939 }
02940
02941
02942
02943
02944
02945
02949 template <class euclidom>
02950 class chainmap
02951 {
02952 public:
02955 chainmap (const chaincomplex<euclidom> &domain,
02956 const chaincomplex<euclidom> &range);
02957
02959 chainmap (const chainmap<euclidom> &c);
02960
02962 chainmap<euclidom> &operator = (const chainmap<euclidom> &c);
02963
02965 ~chainmap ();
02966
02968 int dim () const;
02969
02971 const mmatrix<euclidom> &operator [] (int i) const;
02972
02975 void add (int q, int m, int n, euclidom e);
02976
02978 void invert (void);
02979
02982 void compose (const chainmap<euclidom> &m1,
02983 const chainmap<euclidom> &m2);
02984
02988 outputstream &show (outputstream &out,
02989 const char *maplabel = "f", const char *xtxt = NULL,
02990 const char *ytxt = NULL, const int *level = NULL) const;
02991
02995 std::ostream &show (std::ostream &out,
02996 const char *maplabel = "f", const char *xtxt = NULL,
02997 const char *ytxt = NULL, const int *level = NULL) const;
02998
03002 void take_homology (const chainmap<euclidom> &m,
03003 const chain<euclidom> *hom_domain,
03004 const chain<euclidom> *hom_range);
03005
03009 outputstream &show_homology (outputstream &out,
03010 const chain<euclidom> *hom_domain,
03011 const chain<euclidom> *hom_range, const int *level = NULL,
03012 const char *xtxt = NULL, const char *ytxt = NULL) const;
03013
03017 std::ostream &show_homology (std::ostream &out,
03018 const chain<euclidom> *hom_domain,
03019 const chain<euclidom> *hom_range,
03020 const int *level = NULL,
03021 const char *xtxt = NULL, const char *ytxt = NULL)
03022 const;
03023
03024 private:
03026 int len;
03027
03029 mmatrix<euclidom> *map;
03030
03031 };
03032
03033
03034
03035 template <class euclidom>
03036 inline chainmap<euclidom>::chainmap (const chaincomplex<euclidom> &domain,
03037 const chaincomplex<euclidom> &range)
03038 {
03039
03040 len = domain. len;
03041 if (range. len < domain. len)
03042 len = range. len;
03043
03044
03045 if (len)
03046 map = new mmatrix<euclidom> [len];
03047 else
03048 map = NULL;
03049
03050 for (int i = 0; i < len; ++ i)
03051 {
03052
03053 map [i]. define (range. getnumgen (i),
03054 domain. getnumgen (i));
03055
03056
03057 domain. boundary [i]. dom_dom. add (map [i]);
03058 range. boundary [i]. dom_img. add (map [i]);
03059 if (i < domain. len - 1)
03060 domain. boundary [i + 1]. img_dom. add (map [i]);
03061 if (i < range. len - 1)
03062 range. boundary [i + 1]. img_img. add (map [i]);
03063 }
03064
03065 return;
03066 }
03067
03068 template <class euclidom>
03069 inline chainmap<euclidom>::chainmap (const chainmap<euclidom> &c)
03070 {
03071 len = c. len;
03072 if (len)
03073 map = new mmatrix<euclidom> [len];
03074 else
03075 map = 0;
03076
03077 for (int i = 0; i < len; ++ i)
03078 map [i] = c. map [i];
03079
03080 return;
03081 }
03082
03083 template <class euclidom>
03084 inline chainmap<euclidom> &chainmap<euclidom>::operator =
03085 (const chainmap<euclidom> &c)
03086 {
03087 if (map)
03088 delete [] map;
03089
03090 len = c. len;
03091 if (len)
03092 map = new mmatrix<euclidom> [len];
03093 else
03094 map = 0;
03095
03096 for (int i = 0; i < len; ++ i)
03097 map [i] = c. map [i];
03098
03099 return;
03100 }
03101
03102 template <class euclidom>
03103 inline chainmap<euclidom>::~chainmap ()
03104 {
03105 if (map)
03106 delete [] map;
03107 return;
03108 }
03109
03110 template <class euclidom>
03111 inline int chainmap<euclidom>::dim () const
03112 {
03113 return len - 1;
03114 }
03115
03116 template <class euclidom>
03117 inline const mmatrix<euclidom> &chainmap<euclidom>::operator [] (int i) const
03118 {
03119
03120
03121 return map [i];
03122 }
03123
03124 template <class euclidom>
03125 inline void chainmap<euclidom>::add (int q, int m, int n, euclidom e)
03126 {
03127 map [q]. add (m, n, e);
03128 return;
03129 }
03130
03131 template <class euclidom>
03132 inline void chainmap<euclidom>::take_homology (const chainmap<euclidom> &m,
03133 const chain<euclidom> *hom_domain, const chain<euclidom> *hom_range)
03134 {
03135 if (!hom_domain || !hom_range)
03136 return;
03137
03138 for (int q = 0; q < len; ++ q)
03139 {
03140 int dlen = hom_domain [q]. size ();
03141 const chain<euclidom> &r = hom_range [q];
03142 int rlen = r. size ();
03143 map [q]. define (rlen, dlen);
03144
03145 for (int i = 0; i < dlen; ++ i)
03146 {
03147
03148 int x = hom_domain [q]. num (i);
03149
03150
03151 const chain<euclidom> &img = m [q]. getcol (x);
03152
03153
03154 int j = 0;
03155 for (int k = 0; k < img. size (); ++ k)
03156 {
03157
03158 while ((j < rlen) &&
03159 (r. num (j) < img. num (k)))
03160 ++ j;
03161
03162
03163 if ((j < rlen) &&
03164 (r. num (j) == img. num (k)))
03165 map [q]. add (j, i, img. coef (k));
03166 }
03167 }
03168 }
03169 return;
03170 }
03171
03172 template <class euclidom>
03173 inline void chainmap<euclidom>::invert (void)
03174 {
03175 for (int q = 0; q < len; ++ q)
03176 map [q]. invert ();
03177 return;
03178 }
03179
03180 template <class euclidom>
03181 inline void chainmap<euclidom>::compose (const chainmap<euclidom> &m1,
03182 const chainmap<euclidom> &m2)
03183 {
03184 for (int q = 0; q < len; ++ q)
03185 map [q]. multiply (m1. map [q], m2. map [q]);
03186 return;
03187 }
03188
03189 template <class euclidom>
03190 inline outputstream &chainmap<euclidom>::show (outputstream &out,
03191 const char *maplabel, const char *xtxt, const char *ytxt,
03192 const int *level) const
03193 {
03194 for (int q = 0; q < len; ++ q)
03195 {
03196 if (level && !level [q])
03197 continue;
03198 out << "Dim " << q << ":";
03199 map [q]. showmap (out, maplabel, xtxt, ytxt);
03200 }
03201 return out;
03202 }
03203
03204 template <class euclidom>
03205 inline std::ostream &chainmap<euclidom>::show (std::ostream &out,
03206 const char *maplabel, const char *xtxt, const char *ytxt,
03207 const int *level) const
03208 {
03209 outputstream tout (out);
03210 show (tout, maplabel, xtxt, ytxt, level);
03211 return out;
03212 }
03213
03214 template <class euclidom>
03215 inline outputstream &chainmap<euclidom>::show_homology (outputstream &out,
03216 const chain<euclidom> *hom_domain,
03217 const chain<euclidom> *hom_range, const int *level,
03218 const char *xtxt, const char *ytxt) const
03219 {
03220 int max_len = len - 1;
03221 while ((max_len >= 0) && !hom_domain [max_len]. size ())
03222 -- max_len;
03223 ++ max_len;
03224 for (int q = 0; q < max_len; ++ q)
03225 {
03226 if (!level || level [q])
03227 {
03228 out << "Dim " << q << ":";
03229 int hlen = hom_domain [q]. size ();
03230 if (!hlen)
03231 out << "\t0" << '\n';
03232 for (int i = 0; i < hlen; ++ i)
03233 {
03234 out << "\tf (";
03235 if (xtxt)
03236 out << xtxt;
03237 out << (i + 1) << ") = ";
03238 map [q]. show_hom_col (out,
03239 hom_domain [q]. num (i),
03240 hom_range [q], ytxt);
03241 out << '\n';
03242 }
03243 }
03244 }
03245 return out;
03246 }
03247
03248 template <class euclidom>
03249 inline std::ostream &chainmap<euclidom>::show_homology (std::ostream &out,
03250 const chain<euclidom> *hom_domain,
03251 const chain<euclidom> *hom_range, const int *level,
03252 const char *xtxt, const char *ytxt) const
03253 {
03254 outputstream tout (out);
03255 show_homology (tout, hom_domain, hom_range, level, xtxt, ytxt);
03256 return out;
03257 }
03258
03259
03260
03262 template <class euclidom>
03263 inline std::ostream &operator << (std::ostream &out,
03264 const chainmap<euclidom> &m)
03265 {
03266 out << "chain map" << '\n';
03267 for (int i = 0; i <= m. dim (); ++ i)
03268 {
03269 out << "dimension " << i << '\n';
03270 for (int j = 0; j < m [i]. getncols (); ++ j)
03271 {
03272 if (m [i]. getcol (j). size ())
03273 {
03274 out << "\t# " << (j + 1) << " = " <<
03275 m [i]. getcol (j) << '\n';
03276 }
03277 }
03278 }
03279 return out;
03280 }
03281
03282
03283
03284
03285
03286
03289 template <class euclidom>
03290 inline outputstream &show_homology (outputstream &out,
03291 const chain<euclidom> &c)
03292 {
03293 int countfree = 0;
03294 bool writeplus = false;
03295 for (int i = 0; i < c. size (); ++ i)
03296 {
03297 if (c. coef (i). delta () == 1)
03298 ++ countfree;
03299 else
03300 {
03301 out << (writeplus ? " + " : "") <<
03302 euclidom::ringsymbol () << "_" <<
03303 c. coef (i);
03304 writeplus = true;
03305 }
03306
03307 if (countfree && ((i == c. size () - 1) ||
03308 (c. coef (i + 1). delta () != 1)))
03309 {
03310 out << (writeplus ? " + " : "") <<
03311 euclidom::ringsymbol ();
03312 if (countfree > 1)
03313 out << "^" << countfree;
03314 countfree = 0;
03315 writeplus = true;
03316 }
03317 }
03318
03319
03320 if (!c. size ())
03321 out << "0";
03322
03323 return out;
03324 }
03325
03328 template <class euclidom>
03329 inline std::ostream &show_homology (std::ostream &out,
03330 const chain<euclidom> &c)
03331 {
03332 outputstream tout (out);
03333 show_homology (tout, c);
03334 return out;
03335 }
03336
03337
03338 }
03339 }
03340
03341 #endif // _CHOMP_HOMOLOGY_CHAINS_H_
03342
03344