1 /*=================================================================*/
2 /*=   calc.h                                                      =*/
3 /*=   header file for calculation routines for treekin            =*/
4 /*=                                                               =*/
5 /*=     (c) Michael Thomas Wolfinger, W. Andreas Svrcek-Seiler    =*/
6 /*=                  {mtw,svrci}@tbi.univie.ac.at                 =*/
7 /*=                             treekin                           =*/
8 /*=================================================================*/
9 
10 #ifndef _CALC_H_
11 #define _CALC_H_
12 
13 /* If we use autoconf.  */
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17 
18 #include <cstdlib>
19 #include <cmath>
20 #include <algorithm> /* fill_n */
21 #include <set>
22 #include <queue>
23 #include <vector>
24 #include <errno.h>
25 #include <assert.h>
26 
27 #include "mxccm.h"      /* functions for eigen-problems stolen from ccmath */
28 #include "globals.h"
29 #include "barparser.h"
30 #include "calcpp.h"
31 #include "bardata.h"
32 #include "exp_matrix.h"
33 
34 template<typename T>
35 class Calc {
36   int dim;
37   double _kT;
38   T *evals;
39   T *evecs;
40   T *_sqrPI;  /* left constant array */
41   T *sqrPI_;  /* right constant array */
42   T *D;       /* matrix with degree of degeneracy */
43   char Aname[30];
44 
45   Globals *_globalParameters;
46   treekin_options *_opt;
47   int _lmins;
48   SubInfo *_E;
49   Mxccm mxccm;
50   std::vector<int> reorganize; /* reorganize array (so if LM 0 1 3 were reachable and 2 not, reorganize will contain r[0]=0 r[1]=1 r[2]=3), so r[x] = old position of x */
51 
52   Calccpp *solver;
53 
54 private:
55   T *MxMethodeA(BarData *Data);
56 
57 
58   /*T *MxMethodeFULL(T *); */
59   T *MxMethodeINPUT(BarData *Data,
60                     T *);
61 
62 
63   T  max_saddle(int     i,
64                 int     j,
65                 BarData *Data);
66 
67 
68   void    print_settings(void);
69 
70 
71   char *time_stamp(void);
72 
73 
74   void    MxDoDegeneracyStuff(void);
75 
76 
77   void    MxBinWrite(T          *Mx,
78                      const char what[],
79                      char       c);
80 
81 
82   int     MxBinRead(T           **Mx,
83                     const char  what[],
84                     char        c);
85 
86 
87   void    MxASCIIWrite(T          *Mx,
88                        const char *asciifile);
89 
90 
91   void    MxASCIIWriteV(T           *Mx,
92                         const char  *asciifile);
93 
94 
95   void    MxKotzOutMathematica(T *Mx);
96 
97 
98   void    MxSortEig(T *evals,
99                     T *evecs);
100 
101 
102   void    MxEVLapackSym(T *U);
103 
104 
105   void    MxEVLapackNonSym(T *U);
106 
107 
108   void    MxFixevecs(T *,
109                      T *);
110 
111 
112   void    MxFixevecsAbsorb(T *,
113                            T *);
114 
115 
116   void    MxDiagHelper(T *P8);
117 
118 
119   void norm2(T *mx);
120 
121 
122   int *MxErgoEigen(T    *U,
123                    int  dim);
124 
125 
126 public:
127   Calc(Globals  *globalParameters,
128        SubInfo  *E,
129        int      dim);
130   ~Calc();
131 
132   /**
133    * check for ergodicity
134    */
135   int MxEgro(T    **U,
136              T    **p0,
137              int  dim);
138 
139 
140   void PrintDummy(T *line);
141 
142 
143   /**
144    * print probabilities (adds zero (non-ergodic) columns)
145    * returns sum of these probabilities
146    */
147   T PrintProb(T       *line,
148               int     dim,
149               double  time);
150 
151 
152   T PrintProbFull(T       *line,
153                   int     dim,
154                   double  time,
155                   int     lmins);
156 
157 
158   T PrintProbNR(T       *line,
159                 int     dim,
160                 double  time);
161 
162 
163   void *MxNew(size_t size);
164 
165 
166   void MxGetSpace(T **p8);
167 
168 
169   T *MxBar2Matrix(BarData *Data,
170                   T *);
171 
172 
173   void MxEqDistr(BarData  *Data,
174                  T        **p8);
175 
176 
177   void MxEqDistrFULL(SubInfo  *E,
178                      T        *p8);
179 
180 
181   void MxDiagonalize(T  *U,
182                      T  **_S,
183                      T  *PI);
184 
185 
186   void MxRecover(T  **_S,
187                  T  *P8);
188 
189 
190   void MxStartVec(T **p0);
191 
192 
193   int ConvergenceReached(T    *p8,
194                          T    *pt,
195                          int  dim,
196                          int  full);
197 
198 
199   void MxIterate(T  *p0,
200                  T  *p8,
201                  T  *S);
202 
203 
204   void MxMemoryCleanUp(void);
205 
206 
207   int MxExponent(T  *p0,
208                  T  *p8,
209                  T  *U);
210 
211 
212   void MxFPT(T    *U,
213              T    *p8,
214              FILE *out);
215 
216 
217   void MxEqDistrFromLinSys(T  *U,
218                            T  **p8);
219 
220 
221   void MxEqDistrFromDetailedBalance(T *U,
222                                     T **p8);
223 
224 
225   void MxFPTSimple(T *U);
226 
227 
228   T *MxFPTOneState(T    *U,
229                    int  state);
230 
231 
232   /* not used! (just for past testing) */
233   T  MxFPTRandom(T    *P,
234                  T    *U,
235                  int  src,
236                  int  dst,
237                  int  packets);
238 
239 
240   void MxFPTRnd(T   *U,
241                 int packets);
242 
243 
244   void MxFPrint(T           *mx,
245                 const char  *name,
246                 char        c,
247                 FILE        *out,
248                 int         pure);
249 
250 
251   void MxPrint(T          *mx,
252                const char *name,
253                char       c);
254 };
255 
256 template<typename T>
Calc(Globals * globalParameters,SubInfo * E,int d)257 Calc<T>::Calc(Globals *globalParameters,
258               SubInfo *E,
259               int     d)
260 {
261   _globalParameters = globalParameters;
262   _opt              = &globalParameters->opt;
263   _lmins            = globalParameters->lmins;
264   _E                = E;
265   _kT               = 0.00198717 * (273.15 + _opt->T);
266 
267   evals   = NULL;
268   evecs   = NULL;
269   _sqrPI  = NULL;   /* left constant array */
270   sqrPI_  = NULL;   /* right constant array */
271   D       = NULL;
272   dim     = d;
273   solver  = new Calccpp(_opt, _E);
274 }
275 
276 
277 template<typename T>
~Calc()278 Calc<T>::~Calc()
279 {
280   delete solver;
281 }
282 
283 
284 template<typename T>
285 int
MxEgro(T ** Up,T ** p0p,int dim)286 Calc<T>::MxEgro(T   **Up,
287                 T   **p0p,
288                 int dim)
289 {
290   /* aliases */
291   T   *U  = *Up;
292   T   *p0 = *p0p;
293 
294   /* lokalize first non-empty state */
295   int first = 0;
296 
297   while (p0[first] == (T)0.0)
298     first++;
299 
300   /* make set of all non-empty states */
301   std::set<int>   set_ergo;
302   std::queue<int> que_ergo;
303 
304   set_ergo.insert(first);
305   que_ergo.push(first);
306 
307   /* fill the sets of non-empty states */
308   while (!que_ergo.empty() && (int)set_ergo.size() < dim) {
309     int to_do = que_ergo.front();
310     que_ergo.pop();
311 
312     /* collect contingency */
313     for (int i = 0; i < dim; i++) {
314       if (i == to_do)
315         continue;
316 
317       if (U[i * dim + to_do] > (T)0.0 && (int)set_ergo.count(i) == 0) {
318         set_ergo.insert(i);
319         que_ergo.push(i);
320       }
321     }
322   }
323 
324   /* check ergodicity */
325   if ((int)set_ergo.size() == dim) {
326     return dim;                              /* all ok */
327   } else {
328     int i = first + 1;
329     while (i < dim) {
330       if (p0[i] > (T)0.0 && set_ergo.count(i) == 0) {
331         /* disconnected :( */
332         fprintf(stderr,
333                 "ERROR: Matrix is non-ergodic and initial populations are disconected!! Exiting...\n");
334         exit(-1);
335       }
336 
337       i++;
338     }
339 
340     /* fill helper reorganize array */
341     reorganize.resize(set_ergo.size());
342     i = 0;
343     for (std::set<int>::iterator it = set_ergo.begin(); it != set_ergo.end(); it++)
344       reorganize[i++] = *it;
345 
346     /* reorganize matrix */
347     for (int i = 0; i < (int)set_ergo.size(); i++)
348       for (int j = 0; j < (int)set_ergo.size(); j++)
349         U[i * set_ergo.size() + j] = U[reorganize[i] * dim + reorganize[j]];
350 
351     dim = set_ergo.size();
352     /**Up = (T*)realloc(U, dim*dim*sizeof(T)); */
353     *Up = new T[dim * dim];
354     std::copy_n(U, dim * dim, *Up);
355     delete[] U;
356     U = *Up;
357 
358     /* reorganize p0 */
359     for (int i = 0; i < (int)set_ergo.size(); i++)
360       p0[i] = p0[reorganize[i]];
361     /**p0p = (T*)realloc(p0, dim*sizeof(T)); */
362     *p0p = new T[dim];
363     std::copy_n(p0, dim, *p0p);
364     delete[] p0;
365     p0 = *p0p;
366 
367     if (!_opt->quiet)
368       fprintf(stderr, "WARNING: Matrix is non-ergodic! Decreasing dimension to %d.\n", dim);
369 
370     /*MxPrint(U, "Ergodic U", 'm'); */
371 
372     if (dim == 1) {
373       PrintDummy(p0);
374       return dim;
375     }
376   }
377 
378   /* return new reduced dimension of the inputmatrix. */
379   return dim;
380 }
381 
382 
383 template<typename T>
384 void
PrintDummy(T * line)385 Calc<T>::PrintDummy(T *line)
386 {
387   print_settings();
388   PrintProb(line, 1, _opt->t0);
389   PrintProb(line, 1, _opt->t8);
390 }
391 
392 
393 template<typename T>
394 T
PrintProbFull(T * line,int dim,double time,int lmins)395 Calc<T>::PrintProbFull(T      *line,
396                        int    dim,
397                        double time,
398                        int    lmins)
399 {
400   /* for full process: */
401   std::vector<T> ptFULL(lmins, 0.0);
402 
403   if (reorganize.size() == 0)
404     for (int i = 0; i < dim; i++)
405       ptFULL[_E[i].ag] += line[i];
406   else
407     for (int i = 0; i < dim; i++)
408       ptFULL[_E[reorganize[i]].ag] += line[i];
409 
410   /* sum first */
411   T check = 0.0;
412   for (int i = 0; i < lmins; i++) {
413     if (ptFULL[i] < -0.01) {
414       fprintf(stderr,
415               "prob of lmin %i at time %e has become negative: %e \n",
416               i + 1,
417               time,
418               (double)ptFULL[i]);
419       if (_opt->num_err == 'H')
420         exit(EXIT_FAILURE);
421       else if (_opt->num_err == 'R')
422         ptFULL[i] = 0.0;
423     }
424 
425     /* map individual structure -> gradient basins */
426     check += abs(ptFULL[i]);
427   }
428 
429   /* check for overall propability */
430   if (((check - 1.) < -0.05) || ((check - 1.) > 0.05)) {
431     fprintf(stderr, "overall probability at time %e is %e != 1.0 %s!\n", time, (double)check,
432             (_opt->num_err == 'R' ? "rescaling" : "exiting"));
433     if (_opt->num_err == 'H' || check == 0.0)
434       exit(EXIT_FAILURE);
435   }
436 
437   /* print: */
438   printf("%22.20e ", time);
439   for (int i = 0; i < lmins; i++) {
440     if (_opt->num_err == 'R')
441       printf("%e ", (double)(T)(abs(ptFULL[i]) / check));
442     else
443       printf("%e ", (double)(T)abs(ptFULL[i]));
444   }
445   printf("\n");
446 
447   return check;
448 }
449 
450 
451 template<typename T>
452 T
PrintProbNR(T * line,int dim,double time)453 Calc<T>::PrintProbNR(T      *line,
454                      int    dim,
455                      double time)
456 {
457   T check = 0.0;
458 
459   /* summ first */
460   for (int i = 0; i < dim; i++) {
461     if (line[i] < -0.01) {
462       fprintf(stderr, "prob of lmin %i at time %e has become negative: %e \n", i + 1, time,
463               line[i]);
464       if (_opt->num_err == 'H')
465         exit(EXIT_FAILURE);
466       else if (_opt->num_err == 'R')
467         line[i] = 0.0;
468     }
469 
470     /* map individual structure -> gradient basins */
471     check += abs(line[i]);
472   }
473 
474   /* check for overall propability */
475   if (((check - 1.) < -0.05) || ((check - 1.) > 0.05)) {
476     fprintf(stderr, "overall probability at time %e is %e != 1.0 %s!\n", time, check,
477             (_opt->num_err == 'R' ? "rescaling" : "exiting"));
478     if (_opt->num_err == 'H' || check == 0.0)
479       exit(EXIT_FAILURE);
480   }
481 
482   /* print */
483   printf("%22.20e ", time);
484   for (int i = 0; i < dim; i++) {
485     if (_opt->num_err == 'R')
486       printf("%e ", abs(line[i]) / check);
487     else
488       printf("%e ", abs(line[i]));
489   }
490 
491   printf("\n");
492 
493   return check;
494 }
495 
496 
497 template<typename T>
498 T
PrintProb(T * line,int dim,double time)499 Calc<T>::PrintProb(T      *line,
500                    int    dim,
501                    double time)
502 {
503   T check = (T)0.0;
504 
505   /* sum it up */
506   for (int i = 0; i < dim; i++) {
507     if (line[i] < -0.01) {
508       fprintf(stderr,
509               "prob of lmin %i at time %e has become negative: %e \n",
510               i + 1,
511               time,
512               (double)line[i]);
513       if (_opt->num_err == 'H')
514         exit(EXIT_FAILURE);
515       else if (_opt->num_err == 'R')
516         line[i] = 0.0;
517     }
518 
519     check += abs(line[i]);
520   }
521 
522   /* check for overall probability */
523   if (((check - 1.) < -0.05) || ((check - 1.) > 0.05)) {
524     fprintf(stderr, "overall probability at time %e is %e != 1.0 %s!\n", time, (double)check,
525             (_opt->num_err == 'R' && (double)check != 0.0 ? "rescaling" : "exiting"));
526     if (_opt->num_err == 'H' || check == 0.0)
527       exit(EXIT_FAILURE);
528   }
529 
530   /* print finally: */
531   printf("%22.20e ", time);
532   if (reorganize.size() == 0) {
533     for (int i = 0; i < dim; i++) {
534       /* map individual structure -> gradient basins */
535       if (_opt->num_err == 'R')
536         printf("%e ", (double)(T)(abs(line[i]) / check));
537       else
538         printf("%e ", (double)(T)abs(line[i]));
539     }
540   } else {
541     int j = 0;
542     for (int i = 0; i < dim; i++) {
543       if (j > (int)reorganize.size() || reorganize[j] != i) {
544         printf("%e ", 0.0);
545       } else {
546         if (_opt->num_err == 'R')
547           printf("%e ", (double)(T)(abs(line[j]) / check));
548         else
549           printf("%e ", (double)(T)abs(line[j]));
550 
551         j++;
552       }
553     }
554   }
555 
556   printf("\n");
557 
558   return check;
559 }
560 
561 
562 template<typename T>
563 int *
MxErgoEigen(T * U,int dim)564 Calc<T>::MxErgoEigen(T    *U,
565                      int  dim)
566 {
567   int               count = 1;
568   std::vector<bool> reached(dim, false);
569 
570   reached[0] = true;
571 
572   std::queue<int>   que_ergo;
573   que_ergo.push(0);
574 
575   /* fill the sets of non-empty states */
576   while (!que_ergo.empty() && count < dim) {
577     int to_do = que_ergo.front();
578     que_ergo.pop();
579 
580     /* collect contingency */
581     for (int i = 0; i < dim; i++) {
582       if (i == to_do)
583         continue;
584 
585       if ((double)U[i * dim + to_do] != 0.0 && (double)U[to_do * dim + i] != 0.0 && !reached[i]) {
586         reached[i] = true;
587         que_ergo.push(i);
588         count++;
589       }
590     }
591   }
592 
593   /* return the array of unreached states: */
594   if (dim == count)
595     return NULL;
596 
597   int *result = (int *)malloc(dim * sizeof(int));
598   for (int i = 0; i < dim; i++)
599     result[i] = (reached[i] ? 1 : 0);
600   return result;
601 }
602 
603 
604 /*==*/
605 template<typename T>
606 T *
MxBar2Matrix(BarData * Data,T * R)607 Calc<T>::MxBar2Matrix(BarData *Data,
608                       T       *R)
609 {
610   T *U = NULL;
611 
612   if (_opt->want_degenerate)
613     MxDoDegeneracyStuff();
614 
615   switch (_opt->method) {
616     case 'A':
617       U = MxMethodeA(Data);
618       break;
619     /*
620      * case 'F':
621      * U = MxMethodeFULL(R);
622      * break;
623      */
624     case 'I':
625       U = MxMethodeINPUT(Data, R);
626       break;
627     default:
628       fprintf(stderr,
629               "ERROR in MxBar2Matrix(): No handler 4 method %c\n", _opt->method);
630       exit(EXIT_FAILURE);
631   }
632   if (_opt->dumpU) {
633     MxASCIIWrite(U, "U.txt");
634     MxBinWrite(U, "U", 'm');
635   }
636 
637   return U;
638 }
639 
640 
641 /*==*/
642 template<typename T>
643 void
MxGetSpace(T ** p8)644 Calc<T>::MxGetSpace(T **p8)
645 {
646   *p8 = new T[dim];
647   std::fill_n(*p8, dim, 0.);
648   evals = new T[dim];
649   std::fill_n(evals, dim, 0.);
650   evecs = new T[dim * dim];
651   std::fill_n(evecs, dim, 0.);
652   assert(evals != NULL);
653   assert(evecs != NULL);
654   assert(p8 != NULL);
655 
656   if (!_opt->absrb) {
657     _sqrPI = new T[dim * dim];
658     std::fill_n(_sqrPI, dim * dim, 0.);
659     sqrPI_ = new T[dim * dim];
660     std::fill_n(sqrPI_, dim * dim, 0.);
661   }
662 }
663 
664 
665 /*==*/
666 template<typename T>
667 void
MxStartVec(T ** p0)668 Calc<T>::MxStartVec(T **p0)
669 {
670   int i;
671   T   *pzero = new T[dim];
672 
673   std::fill_n(pzero, dim, 0.0);
674   if (_opt->pini) {
675     for (i = 1; i < (int)*_opt->pini; i += 2)
676       pzero[(int)_opt->pini[i] - 1] = (T)_opt->pini[i + 1];
677     /* -1 because our lmins start with 1, not with 0 (as Data does ) */
678   } else {
679     /* all into first state... */
680     pzero[0] = 1.0;
681   }
682 
683   if (_opt->want_verbose)
684     MxPrint(pzero, "p0", 'v');
685 
686   *p0 = pzero;
687 }
688 
689 
690 /*==*/
691 /* calculate equilibrium distribution */
692 template<typename T>
693 void
MxEqDistr(BarData * Data,T ** p8)694 Calc<T>::MxEqDistr(BarData  *Data,
695                    T        **p8)
696 {
697   int i;
698   T   Z = 0.;
699 
700   if (_opt->absrb) {
701     for (i = 0; i < dim; i++)
702       (*p8)[i] = 0.;
703     (*p8)[dim - 1] = 1.0; /* last entry is the 'new' absorbing state */
704   } else {
705     double mfe = Data[0].energy;
706     for (i = 0; i < dim; i++)
707       Z += exp(-((Data[i].energy - mfe) / _kT));
708     for (i = 0; i < dim; i++)
709       (*p8)[i] = exp(-((Data[i].energy - mfe) / _kT));
710   }
711 
712   /* now normalize the new p8 */
713   for (i = 0; i < dim; i++)
714     *(*p8 + i) *= 1.0 / Z; /*sumsq; */
715 
716   if (_opt->want_verbose)
717     MxPrint(*p8, "p8", 'v');
718 
719   return;
720 }
721 
722 
723 /*==*/
724 template<typename T>
725 void
MxEqDistrFULL(SubInfo * E,T * p8)726 Calc<T>::MxEqDistrFULL(SubInfo  *E,
727                        T        *p8)
728 {
729   int i;
730   T   Z = 0.;
731 
732   if (_opt->absrb) {
733     for (i = 0; i < dim; i++)
734       p8[i] = 0.;
735     p8[_opt->absrb - 1] = 1.;
736   } else {
737     for (i = 0; i < dim; i++)
738       Z += exp(-E[i].energy / _kT);
739     for (i = 0; i < dim; i++)
740       p8[i] = (T)(exp(-E[i].energy / _kT) / Z);
741   }
742 
743   if (_opt->want_verbose)
744     MxPrint(p8, "p8", 'v');
745 
746   return;
747 }
748 
749 
750 template<typename T>
751 void
MxEqDistrFromLinSys(T * U,T ** p8)752 Calc<T>::MxEqDistrFromLinSys(T  *U,
753                              T  **p8)
754 {
755   int i, j, n, nrhs, nfo, *ipiv = NULL;
756   T   *A = NULL, *B = NULL;
757 
758   if (_opt->absrb) {
759     for (i = 0; i < dim; i++)
760       *(*p8 + i) = 0.;
761     *(*p8 + (dim - 1)) = 1.0; /* last entry is the 'new' absorbing state */
762   } else {
763     n     = dim - 1;
764     A     = new T[n * n];
765     B     = new T[n];
766     ipiv  = (int *)malloc(n * sizeof(int));
767     nrhs  = 1;
768 
769     if (_opt->want_verbose)
770       MxPrint(U, "U", 'm');
771 
772     for (i = 1; i <= n; i++)                                                                  /* all except first row */
773       for (j = 1; j <= n; j++)
774         A[n * (i - 1) + (j - 1)] = U[dim * i + j] - (i == j && _opt->useplusI ? 1.0 : 0.0);   /*U-I=Q */
775     for (n = 0, i = 1; i < dim; i++, n++)
776       B[n] = -U[dim * i];
777     dim = n;
778     mxccm.trnm(A, n);
779 
780     if (_opt->want_verbose)
781       MxPrint(A, "A in MxEqDistrFromLinSys", 'm');
782 
783     if (_opt->want_verbose)
784       MxPrint(B, "B in MxEqDistrFromLinSys", 'v');
785 
786     /*DGESV computes the solution to a real system of linear equations A * X = B */
787     solver->Mx_Dgesv(&n, &nrhs, A, &n, ipiv, B, &n, &nfo);
788 
789     if (nfo != 0) {
790       fprintf(stderr,
791               "dgesv exited with value %d (Cannot compute the equilibrium distribution) - check if the rates have good dimension(you have probably reached the numerical precision of treekin)\n",
792               nfo);
793       /*/ TODO switch to compute from detailed balance */
794       exit(EXIT_FAILURE);
795     }
796 
797     if (_opt->want_verbose)
798       MxPrint(B, "X in MxEqDistrFromLinSys", 'v');
799 
800     dim     = n + 1;
801     *p8[0]  = 1.;
802     for (i = 1; i < dim; i++)
803       *(*p8 + i) = B[i - 1];
804 
805     if (_opt->want_verbose)
806       MxPrint(*p8, "p8 in MxEqDistrFromLinSys before norm", 'v');
807 
808     /* now check if all are > 0.0 */
809     for (i = dim - 1; i != 0; i--) {
810       if ((*p8)[i] < 0.0) {
811         if (i == 0)
812           exit(EXIT_FAILURE);
813 
814         fprintf(stderr,
815                 "Warning: p8[%5d] is negative (%e), setting it to a nearby value (%e)\n",
816                 i + 1,
817                 (*p8)[i],
818                 (i == dim - 1 ? (*p8)[i - 1] : (*p8)[i + 1]));
819         (*p8)[i] = abs((i == dim - 1 ? (*p8)[i - 1] : (*p8)[i + 1]));
820       }
821 
822       if ((*p8)[i] == 0.0) {
823         fprintf(stderr,
824                 "Warning: p8[%5d] is zero (%e), setting it to a minimum value (%e)\n",
825                 i + 1,
826                 (*p8)[i],
827                 1e-20);
828         (*p8)[i] = 1e-20;
829       }
830     }
831 
832     /* now make the vector stochastic (sum = 1.0) */
833     T sum = 0.0;
834     for (i = 0; i < dim; i++)
835       sum += (*p8)[i];
836     for (i = 0; i < dim; i++)
837       (*p8)[i] /= sum;
838 
839     delete[] A;
840     delete[] B;
841     free(ipiv);
842   }
843 
844   if (_opt->want_verbose)
845     MxPrint(*p8, "p8", 'v');
846 }
847 
848 
849 /*==*/
850 template<typename T>
851 void
MxDiagonalize(T * U,T ** _S,T * P8)852 Calc<T>::MxDiagonalize(T  *U,
853                        T  **_S,
854                        T  *P8)
855 {
856   int i, j;
857   T   *tmpMx = NULL;
858 
859   if (_opt->dumpMathematica == 1)
860     MxKotzOutMathematica(U);
861 
862   if (!_opt->absrb) {
863     if (_opt->want_verbose)
864       MxPrint(U, "input U", 'm');
865 
866     tmpMx = new T[dim * dim];
867     /*if (_opt->want_verbose) MxPrint (P8, "P8", 'v'); */
868     MxDiagHelper(P8);
869     mxccm.mmul(tmpMx, _sqrPI, U, dim);
870     if (_opt->want_verbose)
871       MxPrint(_sqrPI, "_sqrPI", 'm');
872 
873     if (_opt->want_verbose)
874       MxPrint(tmpMx, "tmpMx = _sqrPI*U", 'm');
875 
876     if (_opt->want_verbose)
877       MxPrint(sqrPI_, "sqrPI_", 'm');
878 
879     /*memset(U,0,dim*dim*sizeof(T)); */
880     fill_n(U, dim * dim, 0);
881     mxccm.mmul(U, tmpMx, sqrPI_, dim);
882     if (_opt->want_verbose)
883       MxPrint(U, "U = _sqrPI*U*sqrPI_ (this should be symmetric, but still uncorrected)", 'm');
884 
885     delete[] tmpMx;
886 
887     /* correct for numerical errors -- ensure U is symmetric */
888     T err = 0.0;  /* accumulated error */
889     for (i = 0; i < dim; i++) {
890       for (j = i; j < dim; j++) {
891         T err_inc = (T)(abs((U[dim * i + j] + U[dim * j + i]) / 2 - U[dim * i + j]));
892         /*if (std::isnan(err_inc)) {
893          * fprintf(stderr, "%d %d\n", i,j);
894          * }*/
895         err += err_inc;
896         if (std::isnan((double)err_inc))
897           fprintf(stderr, "Weird rates! r(%5d,%5d)=(%e, %e)\n", i, j, (double)U[dim * i + j],
898                   (double)U[dim * j + i]);
899 
900         /*exit(-1); */
901 
902         U[dim * i + j] = (T)((U[dim * i + j] + U[dim * j + i]) / 2.);
903         /*U[dim*i+j] = std::sqrt(U[dim*i+j]*U[dim*j+i]); */
904         U[dim * j + i] = U[dim * i + j];
905       }
906     }
907     if (std::isnan((double)err)
908         ) {
909       fprintf(stderr,
910               "Rates are not good -- check your rates (maybe the equilibrium was not computed correctly? rerun with --equil-file or -v set)!!!... (%Lf)\n",
911               (long double)err);
912       exit(-1);
913     }
914 
915     if (!_opt->quiet)
916       fprintf(stderr, "Corrected numerical error: %e (%e per number)\n", (double)err,
917               (double)(T)(err / (T)(dim * dim)));
918 
919     if (_opt->want_verbose)
920       MxPrint(U, "force symmetrized U", 'm');
921   }
922 
923   /* get eigenv* */
924   if (_opt->absrb) {
925     MxEVLapackNonSym(U);
926   } else {
927     switch (_opt->mlapackMethod) {
928 #if defined(WITH_MLAPACK_GMP)
929       case MLAPACK_GMP:
930         solver->MxEV_Mlapack_Sym_gmp((const mpf_class *)U,
931                                    dim,
932                                    (mpf_class *)evals,
933                                    (mpf_class *)evecs,
934                                    _opt->mlapackMethod_Bits);
935         break;
936 #endif
937 #if defined(WITH_MLAPACK_QD)
938       case MLAPACK_QD:
939         solver->MxEV_Mlapack_Sym_qd((const qd_real *)U, dim, (qd_real *)evals, (qd_real *)evecs);
940         break;
941 #endif
942 #if defined(WITH_MLAPACK_MPFR)
943       case MLAPACK_MPFR:
944         solver->MxEV_Mlapack_Sym_mpfr((const mpfr::mpreal *)U, dim, (mpfr::mpreal *)evals,
945                                     (mpfr::mpreal *)evecs, _opt->mlapackMethod_Bits);
946         break;
947 #endif
948 #if defined(WITH_MLAPACK___FLOAT128)
949       case MLAPACK_FLOAT128:
950         solver->MxEV_Mlapack_Sym_float128((const __float128 *)U, dim, (__float128 *)evals,
951                                         (__float128 *)evecs);
952         break;
953 #endif
954 #if defined(WITH_MLAPACK_LD)
955       case MLAPACK_LD:
956         solver->MxEV_Mlapack_Sym_longdouble((const long double *)U, dim, (long double *)evals,
957                                           (long double *)evecs);
958         break;
959 #endif
960 #if defined(WITH_MLAPACK_DD)
961       case MLAPACK_DD:
962         solver->MxEV_Mlapack_Sym_dd((const dd_real *)U, dim, (dd_real *)evals, (dd_real *)evecs);
963         break;
964 #endif
965 #if defined(WITH_MLAPACK_DOUBLE)
966       case MLAPACK_DOUBLE:
967         solver->MxEV_Mlapack_Sym_double((const double *)U, dim, (double *)evals, (double *)evecs);
968         break;
969 #endif
970       default:
971         /*default standard lapack */
972         MxEVLapackSym(U);
973         break;
974     }
975   }
976 
977   MxSortEig(evals, evecs);
978 
979   if (_opt->want_verbose) {
980     MxPrint(evecs, "Eigenvectors of U (LAPACK)", 'm');
981     MxPrint(evals, "Eigenvalues of U (LAPACK)", 'v');
982   }
983 
984   /* check for ergodicity of eigenvectors (if not ergodic, then not all the space can be reached) */
985   int *reachable = MxErgoEigen(evecs, dim);
986   if (reachable) {
987     fprintf(stderr,
988             "WARNING: Eigenvector matrix is non-ergodic (unreachable states from 1st state):");
989     for (i = 0; i < dim; i++)
990       if (!reachable[i])
991         fprintf(stderr, " %4d", i + 1);
992 
993     fprintf(stderr,
994             "\n         the overall probability can start to decrease if this state(s) is(are) populated!!!");
995 
996     free(reachable);
997     /*exit(EXIT_FAILURE); */
998   }
999 
1000   if (!_opt->quiet) {
1001     if ((T)abs(evals[0] - ((_opt->useplusI) ? 1. : 0.)) > (T)10 * _opt->FEPS) {
1002       fprintf(stderr,
1003               "WARNING largest eigenvalue is %g, see evals.txt and evecs.txt\n",
1004               (double)evals[0]);
1005       MxASCIIWriteV(evals, "evals.txt");
1006       MxASCIIWrite(evecs, "evecs.txt");
1007     }
1008   }
1009 
1010   /* fix evals[0] to be 0 (or 1.0) */
1011   if (_opt->useplusI)
1012     evals[0] = 1.0;
1013   else
1014     evals[0] = 0.0;
1015 
1016   /* check if we have only one eval = 0 / eval = 1 */
1017   i = 0;
1018   if (_opt->useplusI)
1019     while (evals[i] >= 1.0)
1020       evals[i++] = 1.0;
1021   else
1022     while (evals[i] >= 0.0)
1023       evals[i++] = 0.0;
1024 
1025   if (i > 1)
1026     fprintf(stderr,
1027             "WARNING: There are multiple evals=%d.0 (%4d) (multiple population traps -- maybe we compute crap)\n",
1028             _opt->useplusI ? 1 : 0,
1029             i);
1030 
1031   if (_opt->absrb)
1032     MxFixevecsAbsorb(evecs, evals);
1033 
1034   /*  else */
1035   /*  MxFixevecs(evecs,evals); / * so far it's not helping ... * / */
1036 
1037   *_S = evecs;
1038   if (_opt->dumpX) {
1039     MxASCIIWriteV(evals, "evals.txt");
1040     exit(EXIT_SUCCESS);
1041   }
1042 
1043   if (_opt->wrecover) {
1044     MxBinWrite(evals, "evals", 'v');
1045     MxBinWrite(evecs, "evecs", 'm');
1046     MxASCIIWriteV(evals, "evals.txt");
1047     MxASCIIWrite(evecs, "evecs.txt");
1048     if (_opt->want_verbose) {
1049       T   *CL; /*, *tmpMx; ? */
1050       int i, j;
1051       CL = new T[dim * dim];
1052       mxccm.mmul(CL, sqrPI_, evecs, dim);
1053       MxASCIIWrite(CL, "evecR.txt");
1054       fprintf(stderr, "Sums of EVs of rate matrix R\n");
1055       for (i = 0; i < dim; i++) {
1056         T sum, sum2, sum3;
1057         sum = sum2 = sum3 = 0.;
1058         for (j = 0; j < dim; j++)
1059           sum += CL[dim * j + i];
1060         fprintf(stderr, "%d %15.8g  ", i, (double)sum);
1061       }
1062       fprintf(stderr, "\n");
1063       delete[] CL;/*free(CL); */
1064     }
1065   }
1066 
1067   /* compensate for the +I matrix */
1068   if (_opt->useplusI)
1069     for (i = 0; i < dim; i++)
1070       evals[i] -= 1.0;                                           /* compensate 4 translation of matrix U */
1071 }
1072 
1073 
1074 /*==*/
1075 template<typename T>
1076 void
MxDiagHelper(T * P8)1077 Calc<T>::MxDiagHelper(T *P8)
1078 {
1079   int i, j;
1080 
1081   for (i = 0; i < dim; i++) {
1082     j                   = i;
1083     sqrPI_[dim * i + j] = (T)std::sqrt(P8[i]);              /* pos right */
1084     _sqrPI[dim * i + j] = (T)(1.0 / (sqrPI_[dim * i + j])); /* neg left */
1085   }
1086 }
1087 
1088 
1089 /*==*/
1090 template<typename T>
1091 void
MxRecover(T ** _S,T * P8)1092 Calc<T>::MxRecover(T  **_S,
1093                    T  *P8)
1094 {
1095   MxDiagHelper(P8);
1096   delete[] evecs;
1097   delete[] evals;
1098 
1099   if (MxBinRead(&evecs, "evecs", 'm') != dim) {
1100     fprintf(stderr, "ERROR: MxBinRead() returns wrong dimension for evecs\n");
1101     exit(EXIT_FAILURE);
1102   }
1103 
1104   if (MxBinRead(&evals, "evals", 'v') != dim) {
1105     fprintf(stderr, "ERROR: MxBinRead() returns wrong dimension for evals\n");
1106     exit(EXIT_FAILURE);
1107   }
1108 
1109   *_S = evecs;
1110   if (_opt->want_verbose) {
1111     MxPrint(evals, "MxRecover: Eigenvalues", 'v');
1112     MxPrint(evecs, "MxRecover: Eigenvectors", 'm');
1113   }
1114 
1115   return;
1116 }
1117 
1118 
1119 template<class T>
1120 int
ConvergenceReached(T * p8,T * pt,int dim,int full)1121 Calc<T>::ConvergenceReached(T   *p8,
1122                             T   *pt,
1123                             int dim,
1124                             int full)
1125 {
1126   int pdiff_counter = 0;
1127 
1128   full = (full ? 1 : 0);
1129   /* now check if we have converged yet */
1130   for (int i = 0; i < dim; i++) {
1131     if (abs(p8[i] - pt[i]) >= 0.000001) {
1132       pdiff_counter++;
1133       break;
1134     }
1135   }
1136 
1137   if (pdiff_counter < 1) /* all mins' pdiff lies within threshold */
1138     return 1;
1139 
1140   pdiff_counter = 0;
1141   /* end check of convergence */
1142   return false;
1143 }
1144 
1145 
1146 /**
1147  * @param S which comes into this function contains the (right)
1148  * eigenvectors calculated by LAPACK
1149  */
1150 template<typename T>
1151 void
MxIterate(T * p0,T * p8,T * S)1152 Calc<T>::MxIterate(T  *p0,
1153                    T  *p8,
1154                    T  *S)
1155 {
1156   /*  solve following equation 4 various times
1157    ***** NON-ABSORBING CASE: ******
1158    *****p(t)    = sqrPI_ * S * exp(time * EV) * St * _sqrPI * p(0)
1159    *****CL      = sqrPI_ * S
1160    *****CR      = St * _sqrPI
1161    *****tmpVec  = CR * p(0)
1162    *****tmpVec2 = exp(time * EV) * tmpVec
1163    *****p(t)    = CL * tmpVec2
1164    ******* ABSORBING CASE: *******
1165    *******p(t)    = S * exp(time * EV) * S_inv * p(0)
1166    *******tmpVec  = S_inv * p(0)
1167    *******tmpVec2 = exp(time * EV) *tmpVec
1168    *******p(t)    = S * tmpVec2
1169    */
1170   int i, count = 0;
1171   T   time, check = 0.;
1172   T   *CL = NULL, *CR, *exptL, *tmpVec, *tmpVec2, *pt, *St, *pdiff;
1173   T   *ptFULL = NULL; /* prob dist 4 of the effective lmins of the tree at time t */
1174   T   *p8FULL = NULL; /* equ dist 4 gradient basins, full process */
1175 
1176   tmpVec = new T[dim];
1177   std::fill_n(tmpVec, dim, 0.);
1178   tmpVec2 = new T[dim];
1179   std::fill_n(tmpVec2, dim, 0.);
1180   pt = new T[dim];
1181   std::fill_n(pt, dim, 0.);
1182   size_t dimSquared = dim * dim;
1183   exptL = new T[dimSquared];
1184   std::fill_n(exptL, dimSquared, 0.);
1185   if (_opt->method == 'F') {
1186     size_t fullSize = _lmins + 1;
1187     ptFULL = new T[fullSize];
1188     std::fill_n(ptFULL, fullSize, 0.);
1189     p8FULL = new T[fullSize];
1190     std::fill_n(p8FULL, fullSize, 0.);
1191     pdiff = new T[fullSize];
1192     std::fill_n(pdiff, fullSize, 0.);
1193   } else {
1194     pdiff = new T[dim];
1195   }
1196 
1197   if (!_opt->absrb) {
1198     /* NON-absorbing case */
1199     CL  = new T[dim * dim];
1200     CR  = new T[dim * dim];
1201     St  = new T[dim * dim];
1202     mxccm.mcopy(St, S, dim * dim);
1203     mxccm.trnm(St, dim); /* transpose S (same as invert(S) ('cause of symmetry) minv(St, dim); )*/
1204     mxccm.mmul(CL, sqrPI_, S, dim);
1205     mxccm.mmul(CR, St, _sqrPI, dim);
1206     mxccm.vmul(tmpVec, CR, p0, dim);
1207 
1208     /* test CL*CR = I */
1209     if (_opt->want_verbose) {
1210       T *testMx, *tvec;
1211       testMx  = new T[dim * dim];
1212       tvec    = new T[dim];
1213       mxccm.mmul(testMx, CL, CR, dim);
1214       MxPrint(testMx, "CL*CR should be I", 'm');
1215       delete[] testMx;
1216       MxPrint(tmpVec, "CR*p0 should start with 1", 'v');
1217       mxccm.vmul(tvec, _sqrPI, p0, dim);
1218       mxccm.vmul(tmpVec2, St, tvec, dim);
1219       MxPrint(tmpVec2, "CR*p0 should start with 1", 'v');
1220       MxPrint(CL, "CL", 'm');
1221       MxPrint(CR, "CR", 'm');
1222       delete[] tvec;
1223     }
1224 
1225     delete[] St;
1226     delete[] CR;
1227   } else {
1228     /* absorbing case */
1229     T *S_inv = new T[dim * dim];
1230     mxccm.mcopy(S_inv, S, dim * dim);
1231     mxccm.minv(S_inv, dim, _opt->FEPS);
1232     if (_opt->want_verbose)
1233       MxPrint(evals, "evals in MxIterate", 'v');
1234 
1235     mxccm.vmul(tmpVec, S_inv, p0, dim);
1236     delete[] S_inv;
1237   }
1238 
1239   if (_opt->method == 'F') {
1240     /* calculate equilibrium distribution once */
1241     for (i = 0; i < dim; i++)
1242       p8FULL[_E[i].ag] += p8[i];
1243     for (i = 0; i < _lmins; i++)
1244       check += abs(p8FULL[i]);
1245     if (((check - 1.) < -0.1) || ((check - 1.) > 0.1)) {
1246       fprintf(stderr, "overall equilibrium probability is %e != 1. !\n", (double)check);
1247       if (_opt->num_err == 'H' || check == 0.0) {
1248         exit(EXIT_FAILURE);
1249       } else if (_opt->num_err == 'R') {
1250         for (i = 0; i < dim; i++)
1251           p8[i] /= check;
1252         check = 1.0;
1253       }
1254     }
1255   }
1256 
1257   check = 0.;
1258 
1259   /* solve fundamental equation */
1260   print_settings();
1261   if (_opt->t0 == 0.0) {
1262     if (_opt->method == 'F')
1263       PrintProbFull(p0, dim, 0.0, _lmins);
1264     else
1265       PrintProb(p0, dim, 0.0);
1266 
1267     _opt->t0 = _globalParameters->TZERO;
1268   }
1269 
1270   T underflow[dim], tt;
1271   for (i = 0; i < dim; i++)
1272     underflow[i] = 0.0;
1273 
1274   /* iterate */
1275   T inc = _opt->t0;
1276   T t8  = _opt->t8;
1277   for (tt = inc; tt < _opt->t8 + inc; inc *= _opt->tinc, tt += inc) {
1278     if (tt > _opt->t8) {
1279       tt  = _opt->t8;
1280       t8  = 0;
1281     }
1282 
1283     time = tt;
1284     for (i = 0; i < dim; i++) {
1285       errno               = 0;
1286       exptL[dim * i + i]  = (T)exp(time / _opt->times * evals[i]);
1287       if ((errno == ERANGE || std::isnan((double)exptL[dim * i + i])
1288            ) && underflow[i] == 0.0) {
1289         /*if (_opt->warnings) fprintf(stderr, "WARNING: underflow occured on %dth state at time %g -- exp(%g * %g) = %g\n", i+1, time/_opt->times, time/_opt->times, evals[i], exptL[dim*i+i]); */
1290         /*         the overall probability can start to decrease if this state is still populated!!!\n         p_%d(%g) = %g, so it seems this %s\n", i+1, time/_opt->times, time/_opt->times, evals[i], exptL[dim*i+i], i+1, time/_opt->times, pt[i], pt[i]>0.1?"is DEFINITELLY BAD":(pt[i]>0.001?"is POTENTIALLY BAD":"SHOULD BE OK")); */
1291         underflow[i] = (T)(time / _opt->times);
1292         /*exit(EXIT_FAILURE); */
1293       }
1294     }
1295     mxccm.vmul(tmpVec2, exptL, tmpVec, dim);
1296     if (!_opt->absrb)
1297       mxccm.vmul(pt, CL, tmpVec2, dim);
1298     else
1299       mxccm.vmul(pt, S, tmpVec2, dim);
1300 
1301     /*if (count%100 == 0) {
1302      * fprintf(stderr, "Time: %g\n", time/_opt->times);
1303      * MxPrint(tmpVec2, "tmpVec2", 'v');
1304      * MxPrint(pt, "pt", 'v');
1305      * }*/
1306 
1307     count++;  /* # of iterations */
1308 
1309     if (_opt->method == 'F') {
1310       /*memset(ptFULL, 0, (_lmins+1)*sizeof(T)); //replaced by c++ style. */
1311       fill_n(ptFULL, _lmins + 1, 0);
1312       for (i = 0; i < dim; i++)
1313         ptFULL[_E[i].ag] += pt[i];
1314     }
1315 
1316     /* print probabilities with respect to corrected ergodicity */
1317     if (_opt->method == 'F')
1318       check = PrintProbFull(pt, dim, time, _lmins);
1319     else
1320       check = PrintProb(pt, dim, time);
1321 
1322     /*PrintProbNR(p8FULL, lmins, -1); */
1323     int reached;
1324     if (_opt->method == 'F')
1325       reached = ConvergenceReached(p8FULL, ptFULL, _lmins, 1);
1326     else
1327       reached = ConvergenceReached(p8, pt, dim, 0);
1328 
1329     fflush(stdout);
1330     if (reached)
1331       break;
1332   }
1333 
1334   /* print underflow: */
1335   if (_opt->warnings) {
1336     for (i = 0; i < dim; i++)
1337       if (underflow[i] > 0.0)
1338         fprintf(stderr, "underflow %5d at time %12g", i + 1, (double)underflow[i]);
1339   }
1340 
1341   if (time < _opt->t8) {
1342     if (_opt->method == 'F')
1343       PrintProbFull(pt, dim, _opt->t8, _lmins);
1344     else
1345       PrintProb(pt, dim, _opt->t8);
1346   }
1347 
1348   printf("# of iterations: %d\n", count);
1349 
1350   /*** end solve fundamental equation ***/
1351 
1352   if (_opt->method == 'F') {
1353     delete[] ptFULL;
1354     delete[] p8FULL;
1355     delete[] _E;
1356   }
1357 
1358   /*free(evals); */
1359   delete[] exptL;
1360   delete[] CL;
1361   delete[] tmpVec;
1362   delete[] tmpVec2;
1363   delete[] pdiff;
1364   delete[] pt;
1365 }
1366 
1367 
1368 /*==*/
1369 template<typename T>
1370 T *
MxMethodeA(BarData * Data)1371 Calc<T>::MxMethodeA(BarData *Data)
1372 {
1373   /***************************************/
1374   /*           |       E_s           |   */
1375   /*           \   ____________      /   */
1376   /*            \  |   /\     |     /    */
1377   /*             \ |  /  \    |    /     */
1378   /*              \| /    \   |   /      */
1379   /*               \/      \  |  /       */
1380   /*               i        \ | /        */
1381   /*                         \/          */
1382   /*                         j           */
1383   /*                       -beta(E_s-E_j) */
1384   /*  rate:  j->i:  prop  e               */
1385   /*                       -beta(E_s-E_i) */
1386   /*         i->j   prop  e               */
1387   /****************************************/
1388 
1389   int i, j, real_abs = 0;
1390   T   m_saddle, Zabs, abs_rate;
1391 
1392   T   *U = new T[dim * dim];
1393 
1394   for (i = 0; i < dim; i++) {
1395     for (j = i + 1; j < dim; j++) {
1396       m_saddle = max_saddle(i, j, Data);
1397 
1398       T tmp_ji  = (T)(1.0 * exp(-(m_saddle - Data[j].energy) / _kT));
1399       T tmp_ij  = (T)(1.0 * exp(-(m_saddle - Data[i].energy) / _kT));
1400       /* rate j -> i */
1401       U[dim * i + j] = tmp_ji;
1402       /* rate i -> j */
1403       U[dim * j + i] = tmp_ij;
1404     }
1405   }
1406 
1407   if (_opt->absrb) {
1408     /*==== absorbing  states ====*/
1409     dim++;
1410     fprintf(stderr, "dim increased to %i\n", dim);
1411     T *tmpU = new T[dim * dim];
1412     real_abs = _opt->absrb; /* the original absorbing lmin */
1413     real_abs--;
1414     _opt->absrb = dim;      /* the 'new' abs state = last row/column of rate matrix */
1415     fprintf(stderr, "new absorbing lmin is: %i\n", _opt->absrb);
1416     Zabs      = (T)(exp((-Data[real_abs].energy) / _kT));
1417     abs_rate  = (T)(exp((-Data[real_abs].energy) / _kT) / Zabs);
1418 
1419     for (i = 0; i < (dim - 1); i++) {
1420       /* all except the last row */
1421       for (j = 0; j < (dim - 1); j++)
1422         tmpU[dim * i + j] = U[(dim - 1) * i + j];
1423       tmpU[(dim - 1) * j + (dim - 1)] = 0.;
1424     }
1425     for (j = 0; j < dim; j++) /* last row */
1426       tmpU[dim * (dim - 1) + j] = 0.;
1427     tmpU[dim * (dim - 1) + real_abs] = abs_rate;
1428     delete[] U; /*free(U); */
1429     U = tmpU;
1430     if (_opt->want_verbose)
1431       MxPrint(U, "aufgeblasene Matrix", 'm');
1432   }  /*== end absorbing states ==*/
1433 
1434   /* set diagonal elements to 0 */
1435   for (i = 0; i < dim; i++)
1436     U[dim * i + i] = 0.;
1437   for (j = 0; j < dim; j++) {
1438     T tmp = 0.00;
1439     /* calculate column sum */
1440     for (i = 0; i < dim; i++)
1441       tmp += U[dim * i + j];
1442     U[dim * j + j] = (T)(-tmp); /* make U a stochastic matrix */
1443     if (_opt->useplusI)
1444       U[dim * j + j] += 1.0;
1445   }
1446   if (_opt->want_verbose)
1447     MxPrint(U, "U with Methode A", 'm');
1448 
1449   return U;
1450 }
1451 
1452 
1453 /*==*/
1454 #if 0
1455 template<typename T>
1456 T *
1457 Calc<T>::MxMethodeFULL(T *R)
1458 {
1459   int i, j;
1460 
1461   delete[] D;       /*free(D); */
1462 
1463   if (_opt->absrb)  /*==== absorbing  states ====*/
1464     for (i = 0; i < dim; i++)
1465       R[dim * i + (_opt->absrb - 1)] = 0.;
1466 
1467   /*== end absorbing states ==*/
1468 
1469   /* set diagonal elements  to 0 */
1470   for (i = 0; i < dim; i++)
1471     R[dim * i + i] = 0.;
1472   for (j = 0; j < dim; j++) {
1473     T tmp = 0.00;
1474     /* calculate column sum */
1475     for (i = 0; i < dim; i++)
1476       tmp += R[dim * i + j];
1477     R[dim * j + j] = (T)(-tmp); /* make U a stochastic matrix */
1478     if (_opt->useplusI)
1479       R[dim * j + j] += 1.0;
1480   }
1481 
1482   if (_opt->want_verbose)
1483     MxPrint(R, "R with Methode F", 'm');
1484 
1485   return R;
1486 }
1487 
1488 
1489 #endif
1490 
1491 /*==*/
1492 template<typename T>
1493 T *
MxMethodeINPUT(BarData * Data,T * Input)1494 Calc<T>::MxMethodeINPUT(BarData *Data,
1495                         T       *Input)
1496 {
1497   int i, j;
1498   T   *U = NULL, Zabs, abs_rate;
1499 
1500   if (_opt->want_verbose)
1501     MxPrint(Input, "Input Matrix", 'm');
1502 
1503   if (_opt->absrb) {
1504     /*==== absorbing  states ====*/
1505     dim++;
1506     fprintf(stderr, "dim increased to %i\n", dim);
1507     U               = new T[dim * dim]; /*(T *) MxNew(dim*dim*sizeof(T)); */
1508     _opt->real_abs  = _opt->absrb;      /* the original absorbing lmin */
1509     _opt->real_abs--;
1510     _opt->absrb = dim;                  /* the 'new' abs state = last row/column of rate matrix */
1511     fprintf(stderr, "new absorbing lmin is: %i\n", _opt->absrb);
1512     Zabs      = exp((-Data[_opt->real_abs].FGr) / _kT);
1513     abs_rate  = (T)(exp((-Data[_opt->real_abs].energy) / _kT) / Zabs);
1514 
1515     for (i = 0; i < (dim - 1); i++) {
1516       /* all except the last row */
1517       for (j = 0; j < (dim - 1); j++)
1518         U[dim * i + j] = Input[(dim - 1) * i + j];
1519       U[(dim - 1) * j + (dim - 1)] = 0.;
1520     }
1521     for (j = 0; j < dim; j++) /* last row */
1522       U[dim * (dim - 1) + j] = 0.;
1523     U[dim * (dim - 1) + _opt->real_abs] = abs_rate;
1524     /*   if(_opt->want_verbose) MxPrint(U, "aufgeblasene Matrix", 'm'); */
1525   }      /*== end absorbing states ==*/
1526   else {
1527     /*== non-absorbing states ==*/
1528     U = new T[dim * dim]; /*(T *) MxNew(dim*dim*sizeof(T)); */
1529     /*memcpy(U, Input, dim*dim*sizeof(T)); */
1530     std::copy(Input, Input + dim * dim, U);
1531   }      /*== end non-absorbing states ==*/
1532 
1533   /* diagonal elements */
1534   for (i = 0; i < dim; i++)
1535     U[dim * i + i] = 0.0;
1536   /*fprintf(stderr, "dim is %i\n", dim); */
1537   for (i = 0; i < dim; i++) {
1538     T tmp = 0.00;
1539     /* calculate column sum */
1540     for (j = 0; j < dim; j++)
1541       tmp += U[dim * j + i];
1542     U[dim * i + i] = (T)(-tmp);   /* make U a stochastic matrix U = Q+I ?? */
1543     if (_opt->useplusI)
1544       U[dim * i + i] += 1.0;
1545   }
1546 
1547   /*  // normalize each column to sum=1
1548    * for (i = 0; i < dim; i++) {
1549    *  double tmp = 0.00;
1550    *  for(j = 0; j < dim; j++) tmp += U[dim*j+i];
1551    *  for(j = 0; j < dim; j++) U[dim*j+i] /= tmp;
1552    * }*/
1553 
1554 
1555   if (_opt->want_verbose)
1556     MxPrint(U, "U with Methode I", 'm');
1557 
1558   delete[] Input;
1559   return U;
1560 }
1561 
1562 
1563 /*==*/
1564 template<typename T>
1565 T
max_saddle(int i,int j,BarData * Data)1566 Calc<T>::max_saddle(int     i,
1567                     int     j,
1568                     BarData *Data)
1569 {
1570   int tmp;
1571 
1572   if (Data[i].number > Data[j].father) {
1573     /* exchange i & j */
1574     tmp = i;
1575     i   = j;
1576     j   = tmp;
1577   }
1578 
1579   if (Data[i].number == Data[j].father) {
1580     return (T)(Data[j].energy + Data[j].ediff);
1581   } else {
1582     if ((Data[j].energy + Data[j].ediff) >
1583         max_saddle((Data[j].father - 1), (Data[i].number - 1), Data))
1584       return Data[j].energy + Data[j].ediff;
1585     else
1586       return max_saddle((Data[j].father - 1), (Data[i].number - 1), Data);
1587   }
1588 }
1589 
1590 
1591 template<typename T>
1592 void
MxFPrint(T * mx,const char * name,char c,FILE * out,int pure)1593 Calc<T>::MxFPrint(T           *mx,
1594                   const char  *name,
1595                   char        c,
1596                   FILE        *out,
1597                   int         pure)
1598 {
1599   int k, l;
1600 
1601   switch (c) {
1602     case 'm':  /* square matrix */
1603       if (!pure)
1604         fprintf(out, "%s:\n", name);
1605 
1606       for (k = 0; k < dim; k++) {
1607         for (l = 0; l < dim; l++)
1608           fprintf(out, "%15.7g ", (double)mx[dim * k + l]);
1609         fprintf(out, "\n");
1610       }
1611       if (!pure)
1612         fprintf(out, "---\n");
1613 
1614       break;
1615     case 'v':
1616       if (!pure)
1617         fprintf(out, "%s:\n", name);
1618 
1619       for (k = 0; k < dim; k++)
1620         fprintf(out, "%15.7g ", (double)mx[k]);
1621       if (!pure)
1622         fprintf(out, "\n---\n");
1623       else
1624         fprintf(out, "\n");
1625 
1626       break;
1627     default:
1628       fprintf(out, "ERROR MxPrint(): no handler 4 type %c\n", c);
1629   }
1630 }
1631 
1632 
1633 /**
1634  * print matrix stored in ccmath-format
1635  */
1636 template<typename T>
1637 void
MxPrint(T * mx,const char * name,char c)1638 Calc<T>::MxPrint(T          *mx,
1639                  const char *name,
1640                  char       c)
1641 {
1642   MxFPrint(mx, name, c, stderr, 0);
1643 }
1644 
1645 
1646 /*==*/
1647 template<typename T>
1648 void
norm2(T * mx)1649 Calc<T>::norm2(T *mx)
1650 {
1651   /* normalize columns of matrix mx */
1652   /* (to euclidean norm 1)*/
1653   int i, j;
1654   T   sumsq;
1655   T   mxValue;
1656 
1657   for (j = 0; j < dim; j++) {
1658     sumsq = 0.0;
1659     for (i = 0; i < dim; i++) {
1660       mxValue = mx[dim * i + j];
1661       sumsq   += mxValue * mxValue;
1662     }
1663     if (sumsq > 0.0)
1664       sumsq = (T)(1. / std::sqrt(sumsq));
1665 
1666     for (i = 0; i < dim; i++)
1667       mx[dim * i + j] *= sumsq;
1668   }
1669   return;
1670 }
1671 
1672 
1673 /*#define abs(x) ((x)>0.0?(x):(-x)) */
1674 
1675 /*==*/
1676 template<typename T>
1677 void
MxFixevecsAbsorb(T * evecs,T * evals)1678 Calc<T>::MxFixevecsAbsorb(T *evecs,
1679                           T *evals)
1680 /* evecs: eigenvectors columns, dimension N   */
1681 /* since the sum over each non-absorbing      */
1682 /* column must vanish, replace the            */
1683 /* problematic evecs with linear combinations */
1684 /* satisfying that criterion                  */
1685 /* rationale: with 1^T a row vector of 1s      */
1686 /* Q=S*exp(L)*inv(S)                          */
1687 /* 1^T*Q = 1^T  (probabilities sum up to 1)   */
1688 /* 1^T*S*exp(L) = 1^T*S                       */
1689 {
1690   int i, j, maxind, abscount;
1691   T   maxent, csum;
1692 
1693   /* assume sorted evals        */
1694   /* and an absorbing state     */
1695   /* im the 1st evec=1st column */
1696 
1697   /* take care of possibly more than one abs. state*/
1698   /* all abs. states have been *assigned* eigenvalue one */
1699   /* for each of them, set the largest component of the */
1700   /* eigenvectors to one, all others to zero */
1701   abscount = 0;
1702   for (i = 0; i < dim; i++) {
1703     if (evals[i] == 1.0) {
1704       abscount++;
1705       maxent  = 0.;
1706       maxind  = 0;
1707       for (j = 0; j < dim; j++) {
1708         if ((T)(abs(evecs[dim * j + i])) > maxent) {
1709           maxent  = (T)(abs(evecs[dim * j + i]));
1710           maxind  = j;
1711         }
1712       }
1713       evecs[dim * maxind + i] = 1.0;
1714       for (j = 0; j < dim; j++) {
1715         if (j == maxind)
1716           continue;
1717 
1718         evecs[dim * j + i] = 0.0;
1719       }
1720     }
1721   }
1722 
1723   /* repair messed non abs. eigenvectors */
1724   /* using all abs. states equally */
1725   /* using all abs. states equally */
1726   for (j = abscount; j < dim; j++) {
1727     T mu = 0.;
1728     for (i = 0; i < dim; i++)
1729       mu += evecs[dim * i + j];
1730     for (i = 0; i < abscount; i++)
1731       evecs[dim * i + j] -= mu / (T)abscount;
1732   }
1733 
1734   if (_opt->want_verbose) {
1735     MxPrint(evals, "evals_complete", 'v');
1736     MxPrint(evecs, "evecs_complete", 'm');
1737     fflush(stdout);
1738     fflush(stderr);
1739   }
1740 
1741   norm2(evecs);
1742 
1743   if (_opt->want_verbose) {
1744     MxPrint(evals, "evals_complete", 'v');
1745     MxPrint(evecs, "evecs_complete", 'm');
1746     fflush(stdout);
1747     fflush(stderr);
1748   }
1749 
1750   if (_opt->want_verbose) {
1751     fprintf(stderr, "colsums: ");
1752     for (i = 0; i < dim; i++) {
1753       csum = 0.0;
1754       for (j = 0; j < dim; j++)
1755         csum += evecs[dim * j + i];
1756       fprintf(stderr, "%g ", (double)csum);
1757     }
1758     fprintf(stderr, "\n");
1759   }
1760 
1761   if (_opt->absrb && (abscount > 1)) {
1762     int i, j;
1763     if (!_opt->quiet)
1764       fprintf(stderr, "\nWARNING: found %d additional absorbing state(s): ", abscount - 1);
1765 
1766     for (i = 1; i < dim; i++) {
1767       if (evals[i] == 1.) {
1768         for (j = 0; j < dim; j++)
1769           if (evecs[dim * j + i] == 1.)
1770             fprintf(stderr, " %5d", j + 1);
1771       }
1772     }
1773     fprintf(stderr, "\n");
1774   }
1775 
1776   fflush(stderr);
1777 }
1778 
1779 
1780 template<typename T>
1781 void
MxFixevecs(T * evecs,T * evals)1782 Calc<T>::MxFixevecs(T *evecs,
1783                     T *evals)
1784 /* Component sum of eigenvectors of M has to be zero, except for largest eigenvalue
1785  * Strategy to enforce this property:
1786  * transform evecs (eigenvectors of the symmertic Matrix U)
1787  * back into space of the Rate Matrix M. With S the Matrix of eigenvectors,
1788  * we compute
1789  *
1790  *     V = sqrPI_ * S
1791  *
1792  *     V_0 should be the equilibrium vector, i.e.
1793  *     V[0,j]>0 and   Sum_j V[0,j] =1
1794  *
1795  *     foreach V_i, i>0, compute d = Sum_j V[i,j]
1796  *     and V_i = V_i - d*V_0
1797  *
1798  * Now transform the vectors back into the space of the symmetric matrix U
1799  *
1800  *     S = _sqrPI * V
1801  */
1802 {
1803   int i, j;
1804   T   *V, sum, sum0;
1805 
1806   V = new T[dim * dim]; /*(T *) MxNew (dim*dim*sizeof(T)); */
1807   mxccm.mmul(V, sqrPI_, evecs, dim);
1808 
1809   if (_opt->want_verbose)
1810     MxPrint(V, "Eigenvectors of rate matrix M, before Fixevecs", 'm');
1811 
1812   fprintf(stderr, "Sums of EVs of rate matrix R before fixing\n");
1813   for (i = 0; i < dim; i++) {
1814     T sum;
1815     sum = 0.;
1816     for (j = 0; j < dim; j++)
1817       sum += V[dim * j + i];
1818     fprintf(stderr, "%15.8g   ", i, sum);
1819   }
1820   fprintf(stderr, "\n");
1821 
1822   sum0  = 0.;
1823   i     = 0;
1824   for (j = 0; j < dim; j++) {
1825     /*    if (V[dim*j+i]<0) { */
1826     /*  if (!_opt->quiet) */
1827     /*  fprintf(stderr, "correcting negative equilib probability for state p[%d]=%g\n",j,V[dim*j+i]); */
1828     /*      V[dim*j+i]=0; */
1829     /*} */
1830     sum0 += V[dim * j + i];
1831   }
1832   /* for (j=0; j<dim; j++) */
1833   /*   V[dim*j+i] /= sum; */
1834 
1835   for (i = 1; i < dim; i++) {
1836     sum = 0.;
1837     for (j = 0; j < dim; j++)
1838       sum += V[dim * j + i];
1839     for (j = 0; j < dim; j++)
1840       V[dim * j + i] -= sum / sum0 * V[dim * j + 0];
1841   }
1842 
1843   fprintf(stderr, "Sums of EVs of rate matrix R after fixing\n");
1844   for (i = 0; i < dim; i++) {
1845     T sum;
1846     sum = 0.;
1847     for (j = 0; j < dim; j++)
1848       sum += V[dim * j + i];
1849     fprintf(stderr, "%15.8g   ", i, (double)sum);
1850   }
1851   fprintf(stderr, "\n");
1852 
1853   mxccm.mmul(evecs, _sqrPI, V, dim);
1854 
1855   norm2(evecs);
1856 
1857   if (_opt->want_verbose)
1858     MxPrint(evecs, "Eigenvectors of symmetric matrix U, after Fixevecs", 'm');
1859 
1860   delete[] V; /*free(V); */
1861 }
1862 
1863 
1864 /**
1865  * sort evecs,eval
1866  */
1867 template<typename T>
1868 void
MxSortEig(T * evals,T * evecs)1869 Calc<T>::MxSortEig(T  *evals,
1870                    T  *evecs)
1871 {
1872   int i, j, k;
1873   T   p;
1874 
1875   for (i = 0; i < dim; i++) {
1876     p = evals[k = i];
1877     for (j = i + 1; j < dim; j++)
1878       if (evals[j] >= p)
1879         p = evals[k = j];
1880 
1881     if (k != i) {
1882       evals[k]  = evals[i];
1883       evals[i]  = p;
1884       for (j = 0; j < dim; j++) {
1885         p                   = evecs[dim * j + i];
1886         evecs[dim * j + i]  = evecs[dim * j + k];
1887         evecs[dim * j + k]  = p;
1888       }
1889     }
1890   }
1891 }
1892 
1893 
1894 /*==*/
1895 template<typename T>
1896 void
MxBinWrite(T * Mx,const char what[],char c)1897 Calc<T>::MxBinWrite(T           *Mx,
1898                     const char  what[],
1899                     char        c)
1900 {
1901   int         i, j, len = -1;
1902   FILE        *BINOUT = NULL;
1903   char        *wosis = NULL, *binfile = NULL;
1904   const char  *suffix = "bin";
1905 
1906   /*size_t info; */
1907 
1908   wosis = (char *)what;
1909   if (_opt->basename == NULL)
1910     len = strlen(suffix) + strlen(wosis) + 4;
1911   else
1912     len = strlen(_opt->basename) + strlen(wosis) + strlen(suffix) + 4;
1913 
1914   binfile = (char *)calloc(len, sizeof(char));
1915   assert(binfile != NULL);
1916   if (_opt->basename != NULL) {
1917     strcpy(binfile, _opt->basename);
1918     strcat(binfile, ".");
1919     strcat(binfile, wosis);
1920     strcat(binfile, ".");
1921     strcat(binfile, suffix);
1922   } else {
1923     /* this should not happen */
1924     strcpy(binfile, wosis);
1925     strcat(binfile, ".");
1926     strcat(binfile, suffix);
1927   }
1928 
1929   if (!_opt->quiet)
1930     fprintf(stderr, "MxBinWrite: writing %s to %s\n", wosis, binfile);
1931 
1932   BINOUT = fopen(binfile, "w");
1933   if (!BINOUT) {
1934     fprintf(stderr, "ERROR: could not open file pointer for binary outfile %s\n", binfile);
1935     exit(EXIT_FAILURE);
1936   }
1937 
1938   /* first write dim to file */
1939   fwrite(&dim, sizeof(int), 1, BINOUT);
1940   switch (c) {
1941     case 'm': /* write matrix entries */
1942       for (i = 0; i < dim; i++)
1943         for (j = 0; j < dim; j++) {
1944           double val = (double)Mx[dim * i + j];
1945           fwrite(&val, sizeof(double), 1, BINOUT);
1946           /*if (!_opt->quiet) fprintf(stderr, "\n"); */
1947         }
1948       break;
1949     case 'v': /* write vector entries */
1950       for (i = 0; i < dim; i++) {
1951         double val = (double)Mx[i];
1952         fwrite(&val, sizeof(double), 1, BINOUT);
1953         /*fprintf(stderr, "\n"); */
1954       }
1955       break;
1956     default:
1957       fprintf(stderr, "ERROR MxBinWrite(): no handler for type %c\n", c);
1958       exit(EXIT_FAILURE);
1959   }
1960   fclose(BINOUT);
1961   /*  if(binfile) free(binfile); */
1962 }
1963 
1964 
1965 /*==*/
1966 template<typename T>
1967 int
MxBinRead(T ** Mx,const char what[],char c)1968 Calc<T>::MxBinRead(T          **Mx,
1969                    const char what[],
1970                    char       c)
1971 {
1972   int         dimension = 0, len = -1;
1973   FILE        *BININ = NULL;
1974   char        *wosis = NULL, *binfile = NULL;
1975   const char  *suffix = "bin";
1976   double      *data   = NULL;
1977   int         ref;
1978 
1979   /*size_t info; */
1980 
1981   wosis = (char *)what;
1982   if (_opt->basename == NULL)
1983     len = strlen(suffix) + strlen(wosis) + 4;
1984   else
1985     len = strlen(_opt->basename) + strlen(wosis) + strlen(suffix) + 4;
1986 
1987   binfile = (char *)calloc(len, sizeof(char));
1988   assert(binfile != NULL);
1989   if (_opt->basename != NULL) {
1990     strcpy(binfile, _opt->basename);
1991     strcat(binfile, ".");
1992     strcat(binfile, wosis);
1993     strcat(binfile, ".");
1994     strcat(binfile, suffix);
1995   } else {
1996     /* this should not happen */
1997     strcpy(binfile, wosis);
1998     strcat(binfile, ".");
1999     strcat(binfile, suffix);
2000   }
2001 
2002   fprintf(stderr, "MxBinRead: reading %s from %s\n", wosis, binfile);
2003   BININ = fopen(binfile, "r+");
2004   if (!BININ) {
2005     fprintf(stderr, "ERROR: could not open file pointer for\
2006     binary infile %s\n", binfile);
2007     exit(EXIT_FAILURE);
2008   }
2009 
2010   /* read dimension from file */
2011   ref = fread(&dimension, sizeof(int), 1, BININ);
2012   size_t numberOfValues;
2013   switch (c) {
2014     /* read data */
2015     case 'm':
2016       numberOfValues  = dimension * dimension;
2017       data            = (double *)calloc(numberOfValues, sizeof(double));
2018       ref             = fread((void *)data, sizeof(double), numberOfValues, BININ);
2019       break;
2020     case 'v':
2021       numberOfValues  = dimension;
2022       data            = (double *)calloc(numberOfValues, sizeof(double));
2023       ref             = fread(data, sizeof(double), numberOfValues, BININ);
2024       break;
2025     default:
2026       fprintf(stderr, "ERROR MxBinRead(): no handler for type %c\n", c);
2027       exit(EXIT_FAILURE);
2028   }
2029 
2030   T *convertedValues = new T[numberOfValues]; /*(T *)calloc(numberOfValues, sizeof(T)); */
2031   for (size_t i = 0; i < numberOfValues; i++)
2032     convertedValues[i] = (T)data[i];
2033 
2034   *Mx = convertedValues;
2035   fclose(BININ);
2036   free(binfile);
2037   return dimension;
2038 }
2039 
2040 
2041 /*==*/
2042 
2043 template<typename T>
2044 inline
2045 void
MxASCIIWrite(T * Mx,const char * asciifile)2046 Calc<T>::MxASCIIWrite(T           *Mx,
2047                       const char  *asciifile)
2048 {
2049   int   i, j;
2050   FILE  *ASCIIOUT;
2051 
2052   ASCIIOUT = fopen(asciifile, "w");
2053   if (!ASCIIOUT) {
2054     fprintf(stderr, "could not open file pointer 4 ASCII outfile\n");
2055     exit(EXIT_FAILURE);
2056   }
2057 
2058   for (i = 0; i < dim; i++) {
2059     for (j = 0; j < dim; j++)
2060       fprintf(ASCIIOUT, "%15.10g ", (double)Mx[dim * j + i]);
2061     fprintf(ASCIIOUT, "\n");
2062   }
2063   if (!_opt->quiet)
2064     fprintf(stderr, "matrix written to ASCII file\n");
2065 
2066   fclose(ASCIIOUT);
2067 }
2068 
2069 
2070 template<typename T>
2071 inline
2072 void
MxASCIIWriteV(T * Mx,const char * asciifile)2073 Calc<T>::MxASCIIWriteV(T          *Mx,
2074                        const char *asciifile)
2075 {
2076   int   i;
2077   FILE  *ASCIIOUT;
2078 
2079   ASCIIOUT = fopen(asciifile, "w");
2080   if (!ASCIIOUT) {
2081     fprintf(stderr, "could not open file pointer 4 ASCII outfile\n");
2082     exit(EXIT_FAILURE);
2083   }
2084 
2085   for (i = 0; i < dim; i++)
2086     fprintf(ASCIIOUT, "%15.10g ", (double)Mx[i]);
2087   if (!_opt->quiet)
2088     fprintf(stderr, "vector written to ASCII file\n");
2089 
2090   fclose(ASCIIOUT);
2091 }
2092 
2093 
2094 /*==*/
2095 
2096 template<typename T>
2097 int
MxExponent(T * p0,T * p8,T * U)2098 Calc<T>::MxExponent(T *p0,
2099                     T *p8,
2100                     T *U)
2101 {
2102   ExpMatrix em;
2103 
2104   int       i, j, pdiff_counter = 0, count = 0;
2105   T         x, tt, time, *Uexp, *Umerk, *pt, *pdiff, check = 0.;
2106 
2107   Umerk = new T[dim * dim]; /*(T *) MxNew (dim*dim*sizeof(T)); */
2108   Uexp  = new T[dim * dim]; /*(T *) MxNew (dim*dim*sizeof(T)); */
2109   pt    = new T[dim];       /*(T *) MxNew (dim*sizeof(T)); */
2110   pdiff = new T[dim];       /*(T *) MxNew (dim*sizeof(T)); */
2111 
2112   /*memcpy(Umerk, U, dim*dim*sizeof(T)); */
2113   std::copy(U, U + dim * dim, Umerk);/*U to Umerk */
2114 
2115   /* solve fundamental equation */
2116   if (_opt->t0 == 0.0) {
2117     if (_opt->method == 'F')
2118       PrintProbFull(p0, dim, 0.0, _lmins);
2119     else
2120       PrintProb(p0, dim, 0.0);
2121 
2122     _opt->t0 = _globalParameters->TZERO;
2123   }
2124 
2125   for (i = 0; i < dim; i++)
2126     U[(dim + 1) * i] -= 1;
2127   print_settings();
2128   for (tt = _opt->t0; tt < _opt->t8 * _opt->tinc; tt *= _opt->tinc) {
2129     time = (tt < _opt->t8) ? tt : (T)_opt->t8;
2130     /*memcpy(U, Umerk, dim*dim*sizeof(T)); */
2131     std::copy(Umerk, Umerk + dim * dim, U);/* Umerk to U; */
2132     for (i = 0; i < dim * dim; i++)
2133       U[i] *= time;
2134     em.padexp(U, Uexp, dim, 30, _opt->FEPS);
2135     x = 0.;
2136     for (j = 0; j < dim * dim; j++)
2137       x += Uexp[j];
2138     for (j = 0; j < dim * dim; j++)
2139       Uexp[j] *= (T)dim / x;
2140     mxccm.vmul(pt, Uexp, p0, dim);
2141     /* check convergence */
2142     for (i = 0; i < dim; i++) {
2143       pdiff[i] = (T)(p8[i] - pt[i]);
2144       if (abs(pdiff[i]) >= 0.0001)
2145         pdiff_counter++;
2146     }
2147     if (pdiff_counter < 1)
2148       break;
2149 
2150     pdiff_counter = 0.;
2151     /* end check convergence */
2152     check = 0.;
2153     printf("%e ", (double)time); /* print p(t) to stdout */
2154     for (i = 0; i < dim; i++) {
2155       if (pt[i] < -0.00001) {
2156         fprintf(stderr, "prob of lmin %i has become negative!\n", i + 1);
2157         exit(EXIT_FAILURE);
2158       }
2159 
2160       printf("%e ", (double)(T)abs(pt[i])); /*abs for mlapack */
2161       check += abs(pt[i]);
2162     }
2163     printf("\n");
2164 
2165     count++; /* # of iterations */
2166 
2167     if (((check - 1.) < -0.01) || ((check - 1.) > 0.01)) {
2168       fprintf(stderr,
2169               "overall probability at time %e is %e != 1.0 %s!\n",
2170               (double)time,
2171               (double)check,
2172               (_opt->num_err == 'R' ? "rescaling" : "exiting"));
2173       if (_opt->num_err == 'H') {
2174         /*clean up before writing error. */
2175         delete[] Uexp;
2176         delete[] pt;
2177         delete[] pdiff;
2178         delete[] Umerk;
2179         return 1;
2180         /*exit(EXIT_FAILURE); //Exit in main. */
2181       }
2182     }
2183 
2184     fill_n(pt, dim, 0);
2185     fill_n(pdiff, dim, 0);
2186     fill_n(Uexp, dim * dim, 0);
2187     /*fill_n(U, dim*dim, 0); */
2188   }
2189   printf("# of iterations: %d\n", count);
2190   delete[] Uexp;
2191   delete[] pt;
2192   delete[] pdiff;
2193   delete[] Umerk;
2194 
2195   return 0;
2196 }
2197 
2198 
2199 /*==*/
2200 template<typename T>
2201 void
MxFPT(T * U,T * p8,FILE * out)2202 Calc<T>::MxFPT(T    *U,
2203                T    *p8,
2204                FILE *out)
2205 {
2206   int i, j;
2207 
2208   /*fprintf(stderr, "in MxFPT\n"); */
2209   /*if(_opt->want_verbose) MxPrint (U,"U" , 'm'); */
2210   T   *Z = NULL, *M = NULL;
2211 
2212   /*MxPrint(U, "U mxfpt", 'm'); */
2213 
2214   if (_opt->absrb) {
2215     Z = new T[(dim - 1) * (dim - 1)];
2216 
2217     int i, j, nrhs, nfo, *ipiv = NULL;
2218     T   *B = new T[(dim - 1)];
2219 
2220     for (i = 0; i < dim - 1; i++)
2221       B[i] = 1.0;
2222 
2223     for (i = 0; i < dim - 1; i++)
2224       for (j = 0; j < dim - 1; j++)
2225         Z[(dim - 1) * i + j] = (T)((i == j && _opt->useplusI ? 1.0 : 0.0) - U[dim * i + j]); /* I-U = -Q  (U is transposed) without absorbing state*/
2226 
2227 
2228     ipiv  = (int *)malloc((dim - 1) * sizeof(int));
2229     nrhs  = 1;
2230 
2231     int n = dim - 1;
2232     /*DGESV computes the solution to a real system of linear equations A * X = B (I think A must be transposed) */
2233     solver->Mx_Dgesv(&n, &nrhs, Z, &n, ipiv, B, &n, &nfo);
2234 
2235     /* fix non-zero in real absorbing state */
2236     for (i = 0; i < dim - 1; i++)
2237       B[i] -= B[_opt->real_abs];
2238     dim--;
2239     MxFPrint(B, "Absorbing times: ", 'v', out, out != stderr);
2240     dim++;
2241 
2242     delete[] B;
2243     delete[] Z;
2244     free(ipiv);
2245   } else {
2246     /* non-absorbing case */
2247     Z = new T[dim * dim];
2248 
2249     for (i = 0; i < dim; i++)
2250       for (j = 0; j < dim; j++)
2251         Z[dim * i + j] = (T)((i == j && _opt->useplusI ? 1.0 : 0.0) - U[dim * j + i] + p8[j]); /* I-U+W = W-Q  (U is transposed)*/
2252 
2253 
2254     /*if(_opt->want_verbose) MxPrint (Z,"I-U+W" , 'm'); */
2255     mxccm.minv(Z, dim, _opt->FEPS);
2256     /*if(_opt->want_verbose)MxPrint (Z,"Fundamental matrix Z=inv(I-U+W)" , 'm'); */
2257 
2258     M = new T[dim * dim];
2259     for (i = 0; i < dim; i++)
2260       for (j = 0; j < dim; j++)
2261         M[dim * i + j] = (T)((Z[dim * j + j] - Z[dim * i + j]) / p8[j]);
2262 
2263     MxFPrint(M,
2264              "First passage times (i-th row, j-th column represents fpt from i-th to j-th state)",
2265              'm',
2266              out,
2267              out != stderr);
2268     delete[] M;
2269     delete[] Z;
2270   }
2271 }
2272 
2273 
2274 /*==*/
2275 
2276 template<typename T>
2277 void
MxKotzOutMathematica(T * Mx)2278 Calc<T>::MxKotzOutMathematica(T *Mx)
2279 {
2280   int         i, j;
2281   FILE        *MATHEMATICA_OUT  = NULL;
2282   const char  *mathematica_file = "mxMat.txt";
2283 
2284   MATHEMATICA_OUT = fopen(mathematica_file, "w");
2285   if (!MATHEMATICA_OUT) {
2286     fprintf(stderr, "could not open file pointer 4 Matematica outfile\n");
2287     exit(EXIT_FAILURE);
2288   }
2289 
2290   fprintf(MATHEMATICA_OUT, "{");
2291   for (i = 0; i < dim; i++) {
2292     fprintf(MATHEMATICA_OUT, "{");
2293     for (j = 0; j < dim; j++) {
2294       if (j != (dim - 1))
2295         fprintf(MATHEMATICA_OUT, "%25.22f, ", (double)Mx[dim * j + i]);
2296       else
2297         fprintf(MATHEMATICA_OUT, "%25.22f}", (double)Mx[dim * j + i]);
2298     }
2299     if (i != (dim - 1))
2300       fprintf(MATHEMATICA_OUT, ",\n");
2301     else
2302       fprintf(MATHEMATICA_OUT, "}\n");
2303   }
2304   fclose(MATHEMATICA_OUT);
2305 }
2306 
2307 
2308 template<typename T>
2309 T *
MxFPTOneState(T * U,int state)2310 Calc<T>::MxFPTOneState(T    *U,
2311                        int  state)
2312 {
2313   if (state >= dim) {
2314     fprintf(stderr, "State %d does not exist (--fpt %d)", state + 1, state + 1);
2315     return NULL;
2316   }
2317 
2318   int i, j, nrhs, nfo;
2319   int *ipiv = NULL;
2320   int n = dim - 1;
2321   T   *A = NULL, *B = NULL;
2322   A = new T[n * n];
2323   B = new T[dim];
2324 
2325   /* A = Q(infinetisimal generator) = U^T-I with state-th column and row deleted (U is transposed!) */
2326   for (i = 0; i < n; i++) {
2327     for (j = 0; j < n; j++) {
2328       int ui  = (i >= state ? i + 1 : i);
2329       int uj  = (j >= state ? j + 1 : j);
2330       A[n * i + j] = (T)(U[dim * ui + uj] - (i == j && _opt->useplusI ? 1.0 : 0.0));
2331     }
2332   }
2333 
2334   for (i = 0; i < n; i++)
2335     B[i] = -1.0;
2336 
2337   /*
2338    * dim--;
2339    * MxPrint(A, "A", 'm');
2340    * MxPrint(B, "B", 'v');
2341    * dim++;
2342    */
2343 
2344   ipiv  = (int *)malloc(n * sizeof(int));
2345   nrhs  = 1;
2346 
2347   /*DGESV computes the solution to a real system of linear equations A * X = B (I think A must be transposed), solution goes to B */
2348   solver->Mx_Dgesv(&n, &nrhs, A, &n, ipiv, B, &n, &nfo);
2349 
2350   for (i = dim - 1; i > state; i--)
2351     B[i] = B[i - 1];
2352   B[state] = 0.0;
2353 
2354   delete[] A;
2355   free(ipiv);
2356   return B;
2357 }
2358 
2359 
2360 template<typename T>
2361 inline
2362 void
MxFPTSimple(T * U)2363 Calc<T>::MxFPTSimple(T *U)
2364 {
2365   int i, j;
2366 
2367   fprintf(stderr, "in MxFTPSimple\n");
2368   T   *M = new T[dim * dim];
2369   T   *B;
2370   int p_done = 0;
2371 
2372   for (i = 0; i < dim; i++) {
2373     /* calculate to one state and add it to global matrix */
2374     B = MxFPTOneState(U, i);
2375     for (j = 0; j < dim - 1; j++)
2376       M[dim * j + i] = B[j];
2377     delete[] B; /*free(B); */
2378     /* print progress */
2379     if (i * 100 / dim >= p_done) {
2380       p_done = i * 100 / dim;
2381       fprintf(stderr, "%d%%\n", p_done);
2382     }
2383   }
2384 
2385   MxPrint(M, "FPT", 'm');
2386 
2387   delete[] M;
2388 }
2389 
2390 
2391 template<typename T>
2392 inline
2393 void
MxFPTRnd(T * U,int packets)2394 Calc<T>::MxFPTRnd(T   *U,
2395                   int packets)
2396 {
2397   srand(time(NULL));
2398   T   *P = NULL, *M = NULL;
2399 
2400   P = (T *)malloc(dim * dim * sizeof(T));
2401 
2402   int i, j;
2403 
2404   for (i = 0; i < dim; i++) {
2405     for (j = 0; j < dim; j++)
2406       /*if (i==j) P[dim*i+j] */
2407       P[dim * i + j] = U[dim * j + i] / (1.0 - U[dim * i + i]);
2408     P[dim * i + i] = 0.0;
2409   }
2410 
2411   /*MxPrint(U, "U", 'm'); */
2412   /*#MxPrint(P, "P", 'm'); */
2413 
2414   if (!_opt->absrb) {
2415     /* ergodic option */
2416     M = (T *)malloc(dim * dim * sizeof(T));
2417     for (i = 0; i < dim; i++) {
2418       for (j = 0; j < dim; j++) {
2419         M[dim * i + j] = MxFPTRandom(P, U, i, j, packets);
2420         fprintf(stderr, "x");
2421       }
2422       fprintf(stderr, "\n");
2423     }
2424 
2425     MxPrint(M, "M (random)", 'm');
2426   } else {
2427     /* absorbing option */
2428     M = (T *)malloc(dim * sizeof(T));
2429     for (i = 0; i < dim; i++)
2430       M[i] = MxFPTRandom(P, U, i, dim - 1, packets);
2431 
2432     MxPrint(M, "M (random)", 'v');
2433   }
2434 
2435   free(M);
2436   free(P);
2437 }
2438 
2439 
2440 template<typename T>
2441 T
MxFPTRandom(T * P,T * U,int src,int dst,int packets)2442 Calc<T>::MxFPTRandom(T    *P,
2443                      T    *U,
2444                      int  src,
2445                      int  dst,
2446                      int  packets)
2447 {
2448   if (src == dst)
2449     return 0.0;
2450 
2451   T   wtime = 0.0;
2452   int i, j;
2453   for (i = 0; i < packets; i++) {
2454     int curr  = src;
2455     T   time  = 0.0;
2456     while (curr != dst) {
2457       time += 1 / (1.0 - U[dim * curr + curr]);
2458       T next = random() / (T)RAND_MAX;
2459       j = 0;
2460       while (next > 0.0 && j < dim) {
2461         next -= P[dim * curr + j];
2462         j++;
2463       }
2464       j--;
2465       curr = j;
2466     }
2467     /*fprintf(stderr, "time to consume %f\n", time); */
2468     wtime += time;
2469   }
2470   return wtime / (T)packets;
2471 }
2472 
2473 
2474 template<typename T>
2475 void
MxEVLapackSym(T * U)2476 Calc<T>::MxEVLapackSym(T *U)
2477 {
2478   /*   extern void dsyev_(char *jobz, char *uplo, int *n, double *A,int *lda, */
2479   /*         double *w, double *work, int *lwork, int *info); */
2480   T abstol;
2481 
2482   abstol = _opt->FEPS;
2483 
2484   if (_opt->want_verbose)
2485     fprintf(stderr, "FEPS precision %20.10g\n", (double)abstol);
2486 
2487   T   *work = NULL, vl, vu;                                                         /* unused or inputs */
2488   int il, iu, m, lwork, liwork, *iwork = NULL, *ifail = NULL, *isuppz = NULL, nfo;  /* unused or inputs */
2489   lwork   = dim * (dim + 26);
2490   liwork  = 10 * dim;
2491   work    = (T *)malloc(lwork * sizeof(T));
2492   iwork   = (int *)malloc(liwork * sizeof(int));
2493   ifail   = (int *)malloc(dim * sizeof(int));
2494   isuppz  = (int *)malloc(2 * dim * sizeof(int));
2495 
2496   /*if (!_opt->useplusI) for (il=0; il<dim; il++) U[il*dim+il]-=1.0; */
2497 
2498   /* works only with: dim, U, evals, evecs */
2499   solver->Mx_Dsyevx("V", "A", "U", &dim, U, &dim, &vl, &vu, &il, &iu,
2500                     &abstol, &m, evals, evecs, &dim, work, &lwork, iwork,
2501                     ifail, &nfo);
2502   /*
2503    #if 1
2504    * dsyevx_("V", "A", "U",&dim, U, &dim, &vl, &vu, &il, &iu,
2505    * &abstol, &m, evals, evecs, &dim, work, &lwork, iwork,
2506    * ifail, &nfo);
2507    #else
2508    * dsyevr_("V", "A", "U",&dim, U, &dim, &vl, &vu, &il, &iu,
2509    * &abstol, &m, evals, evecs, &dim, isuppz, work, &lwork, iwork,
2510    * &liwork, &nfo);
2511    #endif
2512    */
2513 
2514   /*dsyev_("V","U",&dim, S, &dim, evals, work, &lwork, &nfo); */
2515   /*MxPrint(evecs, "Eigenvectors (bad)", 'm'); */
2516   /*MxPrint(evals, "Eigenvalues (bad)", 'v'); */
2517   if (nfo != 0) {
2518     fprintf(stderr,
2519             "dsyevx exited with value %d (val=%20.10g) (Cannot compute eigenvalues) Try to:\n - lower --feps value (try --feps=-1.0)\n - try using --useplusI option (sometimes the eigenvalues are better computed like that)\n",
2520             nfo,
2521             (double)evals[nfo - 1]);
2522     for (il = 0; il < dim; il++)
2523       fprintf(stderr, "%20.10g ", (double)evecs[nfo * dim + il]);
2524     fprintf(stderr, "\n");
2525 
2526     fprintf(stderr, "\n");
2527     exit(EXIT_FAILURE);
2528   }
2529 
2530   /*if (!_opt->useplusI) for (il=0; il<dim; il++) U[il*dim+il]+=1.0; */
2531 
2532   free(work);
2533   free(iwork);
2534   free(ifail);
2535   free(isuppz);
2536 
2537   /* transpose output */
2538   mxccm.trnm(evecs, dim);
2539 }
2540 
2541 
2542 template<typename T>
2543 void
MxEVLapackNonSym(T * origU)2544 Calc<T>::MxEVLapackNonSym(T *origU)
2545 /* input: matrix origU, space for (right)evec-matrix S, */
2546 /* since fortran sucks, we transpose the input matrix   */
2547 /* and still want the right eigenvectors                */
2548 /* matrix of right eigenvecs is transposed  to have */
2549 /* the j-th evec in column c */
2550 {
2551   T   *evals_re = NULL, *evals_im = NULL, *scale = NULL;
2552   T   *rconde = NULL, *rcondv = NULL, *work = NULL, abnrm;
2553   int one, ilo, ihi, lwork, *iwork, nfo;
2554   /*int dimx2; */
2555   /* for sorting */
2556   int i;
2557 
2558   dim = dim + 500;
2559   one = 1;
2560   /*dimx2 = 2*dim; */
2561   lwork = dim * (dim + 6);
2562 
2563   evals_re  = new T[dim];
2564   evals_im  = new T[dim];
2565   scale     = new T[dim];
2566   rconde    = new T[dim];
2567   rcondv    = new T[dim];
2568   work      = new T[lwork];
2569   iwork     = new int[2 * (dim - 2)];
2570   dim       = dim - 500;
2571   if ((evals_re && evals_im && scale && rconde &&
2572        rcondv && work && iwork) == 0) {
2573     fprintf(stderr, "no space for temporary lapack arrays!\n");
2574     exit(EXIT_FAILURE);
2575   }
2576 
2577   /* instead of more fiddling, we transpose the input */
2578   mxccm.trnm(origU, dim);
2579 
2580   T *tmpNull = NULL;
2581   solver->Mx_Dgeevx("B", "N", "V", "V", &dim, origU, &dim, evals_re, evals_im, tmpNull, &one,
2582                     evecs, &dim, &ilo, &ihi, scale, &abnrm, rconde, rcondv, work,
2583                     &lwork, iwork, &nfo);
2584 
2585   for (i = 0; i < dim; i++)
2586     evals[i] = evals_re[i];
2587   for (i = 0; i < dim; i++)
2588     if ((evals_re[i] != 0.0) && abs(evals_im[i] / evals_re[i]) > _opt->FEPS)
2589       fprintf(stderr, "eigenvalue %d is %g + i*%g, which is somewhat complex\n",
2590               i, (double)evals_re[i], (double)evals_im[i]);
2591 
2592   /*transpose output*/
2593   mxccm.trnm(evecs, dim);
2594 
2595   delete[] evals_re;
2596   delete[] evals_im;
2597   delete[] scale;
2598   delete[] rconde;
2599   delete[] rcondv;
2600   delete[] work;
2601   delete[] iwork;
2602 }
2603 
2604 
2605 template<typename T>
2606 inline
2607 void
MxEqDistrFromDetailedBalance(T * U,T ** p8)2608 Calc<T>::MxEqDistrFromDetailedBalance(T *U,
2609                                       T **p8)
2610 {
2611   T   *res = *p8;
2612   int *done;
2613   int count = 1; /* num of solved states */
2614   int i     = 0;
2615   int j     = 1;
2616   int k;
2617 
2618   done = new int[dim];
2619   std::fill_n(done, dim, 0);
2620 
2621   for (k = 1; k < dim; k++)
2622     res[k] = 0.0;
2623   res[0] = 1.0;
2624 
2625   /* while there are unsolved states */
2626   while (count != dim) {
2627     for (j = 1; j < dim; j++) {
2628       if (res[j] > (T)0.)
2629         continue;
2630 
2631       if (U[dim * i + j] > (T)0.0) {
2632         if (U[dim * j + i] == (T)0.0) {
2633           fprintf(stderr, "Local balance is unsatisfiable at U[%d][%d]=%f\n", i, j,
2634                   (double)U[dim * i + j]);
2635           exit(EXIT_FAILURE);
2636         }
2637 
2638         /* local balance */
2639         T tmp = U[dim * j + i];
2640         tmp     *= res[i];
2641         tmp     /= U[dim * i + j];
2642         res[j]  = tmp;
2643         count++;
2644         if (res[j] > (T)1. || res[j] <= (T)0.) {
2645           fprintf(stderr, "Weird eqilibrium pop for state %d", j);
2646           MxPrint(res, "p8 (local balance)", 'v');
2647         }
2648       }
2649     }
2650     done[i] = 1;
2651     for (i = 1; i < dim; i++)
2652       if ((!done[i]) && (res[i] > (T)0.))
2653         break;
2654 
2655     if (i == dim && count < dim) {
2656       fprintf(stderr, "non-ergodic chain\n");
2657       MxPrint(res, "p8 (local balance)", 'v');
2658       exit(EXIT_FAILURE);
2659     }
2660   }
2661 
2662   delete[] done;
2663 
2664   /* now make the vector stochastic (sum = 1.0) */
2665   T sum = 0.0;
2666   for (i = 0; i < dim; i++)
2667     sum += res[i];
2668   for (i = 0; i < dim; i++)
2669     res[i] /= sum;
2670 
2671   MxPrint(res, "p8 (detailed balance)", 'v');
2672 }
2673 
2674 
2675 /*==*/
2676 template<typename T>
2677 void *
MxNew(size_t size)2678 Calc<T>::MxNew(size_t size)
2679 {
2680   void *mx = NULL;
2681 
2682   if ((mx = (void *)calloc(1, size)) == NULL)
2683     fprintf(stderr, "ERROR: new_martix() allocation failed\n");
2684 
2685   return mx;
2686 }
2687 
2688 
2689 /*==*/
2690 template<typename T>
2691 void
MxMemoryCleanUp(void)2692 Calc<T>::MxMemoryCleanUp(void)
2693 {
2694   if (_opt->sequence)
2695     free(_opt->sequence);
2696 
2697   if (_opt->basename)
2698     free(_opt->basename);
2699 
2700   if (_opt->fpt_file)
2701     free(_opt->fpt_file);
2702 
2703   delete[] _sqrPI;
2704   delete[] sqrPI_;
2705   delete[]evecs;
2706   delete[]evals;
2707 }
2708 
2709 
2710 /*==*/
2711 template<typename T>
2712 void
print_settings(void)2713 Calc<T>::print_settings(void)
2714 {
2715   printf(
2716     "# Date: %s"
2717     "# Sequence: %s\n"
2718     "# Method: %c\n"
2719     "# Start time: %.2f\n"
2720     "# Stop time: %.2f\n"
2721     "# Temperature: %.2f\n",
2722     time_stamp(),
2723     _opt->sequence,
2724     _opt->method,
2725     _opt->t0,
2726     _opt->t8,
2727     _opt->T
2728     );
2729   if (_opt->basename != NULL)
2730     printf("# Basename: %s\n", _opt->basename);
2731   else
2732     printf("# Basename: <stdin>\n");
2733 
2734   if (_opt->tinc)
2735     printf("# Time increment: %.2f\n", _opt->tinc);
2736   else
2737     printf("# Time increment: %.2f \n", _opt->tinc);
2738 
2739   if (_opt->want_degenerate == 1)
2740     printf("# Degeneracy:  on\n");
2741   else
2742     printf("# Degeneracy:  off\n");
2743 
2744   if (_opt->absrb < 1)
2745     printf("# Absorbing state: none\n");
2746   else
2747     printf("# Absorbing state: %d\n", _opt->absrb);
2748 
2749   if (_opt->n > 0)
2750     printf("# States limit: %d\n", _opt->n);
2751   else
2752     printf("# States limit: till EOF\n");
2753 }
2754 
2755 
2756 /*==*/
2757 template<typename T>
2758 char *
time_stamp(void)2759 Calc<T>::time_stamp(void)
2760 {
2761   time_t cal_time;
2762 
2763   cal_time = time(NULL);
2764   return ctime(&cal_time);
2765 }
2766 
2767 
2768 /*==*/
2769 template<typename T>
2770 void
MxDoDegeneracyStuff(void)2771 Calc<T>::MxDoDegeneracyStuff(void)
2772 {
2773   int           i, j, b, nr, current, numsad = 1, count = 0;
2774   TypeDegSaddle *saddle = NULL;
2775 
2776   numsad = Barparser::ParseSaddleFile(&saddle);
2777   /* loop over all elements of structure-array saddle: */
2778   /* first we fill the upper triangle */
2779   for (count = 0; count < numsad; count++) {
2780     current = 1;
2781     nr      = saddle[count].list[0];
2782     /* only for saddles with a cc >= 1  AND those which connect at least 2 lmins */
2783     if (saddle[count].cc >= 1 && nr >= 2 && !(saddle[count].cc == 1 && nr == 2)) {
2784       while (current < nr) {
2785         for (b = current + 1; b <= nr; b++) {
2786           /* skip in case a lmin which we don't see is connected by */
2787           /* the saddle (because we can only see --max x lmins) */
2788           if (saddle[count].list[current] > dim || saddle[count].list[b] > dim) {
2789             current++;
2790             continue;
2791           }
2792 
2793           /* FIRST: we consider the size of the cc the saddle belongs to */
2794           if (saddle[count].cc > 1) {
2795             D[dim * (saddle[count].list[current] - 1) +
2796               (saddle[count].list[b] - 1)] += (saddle[count].cc - 1);
2797             fprintf(stderr, "transition between %3d - %3d: adding %2d  cc\n",
2798                     saddle[count].list[current], saddle[count].list[b], saddle[count].cc - 1);
2799             /* -1 because if the size of cc == 1 there's nothing special */
2800             /* about it, i.e. there is just one saddle */
2801           }
2802 
2803           /* SECOND: we consider that the saddle connects several lmins */
2804           if (nr > 2) {
2805             D[dim * (saddle[count].list[current] - 1) + (saddle[count].list[b] - 1)] += 1;
2806             fprintf(stderr, "transition betweed %3d - %3d: adding  1 deg_saddle\n",
2807                     saddle[count].list[current], saddle[count].list[b]);
2808             /* -1 because matrix starts with0, NOT with 1 */
2809           }
2810         }
2811         current++;
2812       }
2813     }
2814   }
2815 
2816   for (i = 0; i < dim; i++) {
2817     /* make matrix symmetric */
2818     for (j = 0; j < dim; j++)
2819       if (i != j)
2820         D[dim * j + i] = D[dim * i + j];
2821   }
2822   if (_opt->want_verbose) {
2823     sprintf(Aname, "%s", "D (degeneracies)");
2824     MxPrint(D, Aname, 'm');
2825   }
2826 
2827   free(saddle);
2828 }
2829 
2830 
2831 #endif
2832 
2833 /* End of file */
2834