MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
MarkovSolver.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 ** This program is part of 'MOOSE', the
3 ** Messaging Object Oriented Simulation Environment.
4 ** Copyright (C) 2003-2011 Upinder S. Bhalla. and NCBS
5 ** It is made available under the terms of the
6 ** GNU Lesser General Public License version 2.1
7 ** See the file COPYING.LIB for the full notice.
8 **********************************************************************/
9 
10 #include <float.h> //Needed for DBL_MAX and DBL_MIN
11 #include "header.h"
12 #include "MatrixOps.h"
13 
14 #include "VectorTable.h"
15 #include "../builtins/Interpol2D.h"
16 #include "MarkovRateTable.h"
17 
18 #include "MarkovSolverBase.h"
19 #include "MarkovSolver.h"
20 
22 {
24  //DestFinfos
26 
27  static DestFinfo process( "process",
28  "Handles process call",
30 
31  static DestFinfo reinit( "reinit",
32  "Handles reinit call",
34 
35  static Finfo* processShared[] =
36  {
37  &process, &reinit
38  };
39 
40  static SharedFinfo proc( "proc",
41  "This is a shared message to receive Process message from the"
42  "scheduler. The first entry is a MsgDest for the Process "
43  "operation. It has a single argument, ProcInfo, which "
44  "holds lots of information about current time, thread, dt and"
45  "so on. The second entry is a MsgDest for the Reinit "
46  "operation. It also uses ProcInfo.",
47  processShared, sizeof( processShared ) / sizeof( Finfo* )
48  );
49 
50 
51  static Finfo* markovSolverFinfos[] =
52  {
53  &proc, //SharedFinfo
54  };
55 
56  static Dinfo < MarkovSolver > dinfo;
57  static Cinfo markovSolverCinfo(
58  "MarkovSolver",
60  markovSolverFinfos,
61  sizeof( markovSolverFinfos ) / sizeof( Finfo* ),
62  &dinfo
63  );
64 
65  return &markovSolverCinfo;
66 }
67 
69 
71 {
72  ;
73 }
74 
76 {
77  ;
78 }
79 
81  unsigned int degreeIndex )
82 {
83  Matrix *expQ;
84  Matrix *U, *VplusU, *VminusU, *invVminusU, *Qpower;
85  vector< unsigned int >* swaps = new vector< unsigned int >;
86  unsigned int n = Q1->size();
87  unsigned int degree = mCandidates[degreeIndex];
88  double *padeCoeffs = NULL;
89  Matrix *V = matAlloc(n);
90 
91  //Vector of Matrix pointers. Each entry is an even power of Q.
92  vector< Matrix* > QevenPowers;
93 
94  //Selecting the right coefficient array.
95  switch (degree)
96  {
97  case 13:
98  padeCoeffs = b13;
99  break;
100 
101  case 9:
102  padeCoeffs = b9;
103  break;
104 
105  case 7:
106  padeCoeffs = b7;
107  break;
108 
109  case 5:
110  padeCoeffs = b5;
111  break;
112 
113  case 3:
114  padeCoeffs = b3;
115  break;
116  }
117 
118 
120  //Q2 = Q^2 is computed for all degrees.
121  //Q4 = Q^4 = Q^2 * Q^2 is computed when degree = 5,7,9,13.
122  //Q6 = Q^6 = Q^4 * Q^2 is computed when degree = 7,9,13.
123  //Q8 = Q^8 = Q^4 * Q^4 is computed when degree = 7,9.
124  //Note that the formula for the 13th degree approximant used here
125  //is different from the one used for smaller degrees.
127  switch( degree )
128  {
129  case 3 :
130  case 5 :
131  case 7 :
132  case 9 :
133  U = matAlloc( n );
134 
135  QevenPowers.push_back( Q1 );
136 
137  for( unsigned int i = 1; i < (degree + 1)/2 ; ++i )
138  {
139  Qpower = QevenPowers.back();
140  QevenPowers.push_back( matMatMul( Qpower, Qpower ) );
141  }
142 
143  //Computation of U.
144  for ( int i = degree; i > 1; i -= 2 )
145  matMatAdd( U, QevenPowers[i/2], 1.0, padeCoeffs[i], FIRST );
146 
147  //Adding b0 * I .
148  matEyeAdd( U, padeCoeffs[1], 0 );
149  matMatMul( Q1, U, SECOND );
150 
151  //Computation of V.
152  for ( int i = degree - 1; i > 0; i -= 2 )
153  matMatAdd( V, QevenPowers[i/2], 1.0, padeCoeffs[i], FIRST );
154 
155  //Adding b1 * I
156  matEyeAdd( V, padeCoeffs[0], DUMMY );
157 
158  while (!QevenPowers.empty())
159  {
160  delete QevenPowers.back();
161  QevenPowers.pop_back();
162  }
163  break;
164 
165  case 13:
166  Matrix *Q2, *Q4, *Q6;
167  Matrix *temp;
168 
169  Q2 = matMatMul( Q1, Q1 );
170  Q4 = matMatMul( Q2, Q2 );
171  Q6 = matMatMul( Q4, Q2 );
172 
173  //Long and rather messy expression for U and V.
174  //Refer paper mentioned in header for more details.
175  //Storing the result in temporaries is a better idea as it gives us
176  //control on how many temporaries are being created and also to
177  //help in memory deallocation.
178 
179  //Computation of U.
180  temp = matScalShift( Q6, b13[13], 0.0 );
181  matMatAdd( temp, Q4, 1.0, b13[11], FIRST );
182  matMatAdd( temp, Q2, 1.0, b13[9], FIRST );
183 
184  matMatMul( Q6, temp, SECOND );
185 
186  matMatAdd( temp, Q6, 1.0, b13[7], FIRST );
187  matMatAdd( temp, Q4, 1.0, b13[5], FIRST );
188  matMatAdd( temp, Q2, 1.0, b13[3], FIRST );
189  matEyeAdd( temp, b13[1], DUMMY );
190  U = matMatMul( Q1, temp );
191  delete temp;
192 
193  //Computation of V
194  temp = matScalShift( Q6, b13[12], 0.0 );
195  matMatAdd( temp, Q4, 1.0, b13[10], FIRST );
196  matMatAdd( temp, Q2, 1.0, b13[8], FIRST );
197  matMatMul( Q6, temp, SECOND );
198  matMatAdd( temp, Q6, 1.0, b13[6], FIRST );
199  matMatAdd( temp, Q4, 1.0, b13[4], FIRST );
200  matMatAdd( temp, Q2, 1.0, b13[2], FIRST );
201  delete( V );
202  V = matEyeAdd( temp, b13[0] );
203  delete temp;
204 
205  delete Q2;
206  delete Q4;
207  delete Q6;
208  break;
209  }
210 
211  VplusU = matMatAdd( U, V, 1.0, 1.0 );
212  VminusU = matMatAdd( U, V, -1.0, 1.0 );
213 
214  invVminusU = matAlloc( n );
215  matInv( VminusU, swaps, invVminusU );
216  expQ = matMatMul( invVminusU, VplusU );
217 
218 
219  //Memory cleanup.
220  delete U;
221  delete V;
222  delete VplusU;
223  delete VminusU;
224  delete invVminusU;
225  delete swaps;
226 
227  return expQ;
228 }
229 
231 {
232  double mu, norm;
233  unsigned int n = Q_->size();
234  Matrix *expQ, *Q1;
235 
236  mu = matTrace( Q_ )/n;
237 
238  //Q1 <- Q - mu*I
239  //This reduces the norm of the matrix. The idea is that a lower
240  //order approximant will suffice if the norm is smaller.
241  Q1 = matEyeAdd( Q_, -mu );
242 
243  //We cycle through the first four candidate values of m. The moment the norm
244  //satisfies the theta_M bound, we choose that m and compute the Pade'
245  //approximant to the exponential. We can then directly return the exponential.
246  norm = matColNorm( Q1 );
247  for ( unsigned int i = 0; i < 4; ++i )
248  {
249  if ( norm < thetaM[i] )
250  {
251  expQ = computePadeApproximant( Q1, i );
252  matScalShift( expQ, exp( mu ), 0, DUMMY );
253  return expQ;
254  }
255  }
256 
257  //In case none of the candidates were satisfactory, we scale down the norm
258  //by dividing A by 2^s until ||A|| < 1. We then use a 13th degree
259  //Pade approximant.
260  double sf = ceil( log( norm / thetaM[4] ) / log( (double)2 ) );
261  unsigned int s = 0;
262 
263  if ( sf > 0 )
264  {
265  s = static_cast< unsigned int >( sf );
266  matScalShift( Q1, 1.0/(2 << (s - 1)), 0, DUMMY );
267  }
268  expQ = computePadeApproximant( Q1, 4 );
269 
270  //Upto this point, the matrix stored in expQ is r13, the 13th degree
271  //Pade approximant corresponding to A/2^s, not A.
272  //Now we repeatedly square r13 's' times to get the exponential
273  //of A.
274  for ( unsigned int i = 0; i < s; ++i )
275  matMatMul( expQ, expQ, FIRST );
276 
277  matScalShift( expQ, exp( mu ), 0, DUMMY );
278 
279  delete Q1;
280  return expQ;
281 }
282 
284 //MsgDest functions
286 void MarkovSolver::reinit( const Eref& e, ProcPtr p )
287 {
288  MarkovSolverBase::reinit( e, p );
289 }
290 
291 void MarkovSolver::process( const Eref& e, ProcPtr p )
292 {
294 }
295 
296 #ifdef DO_UNIT_TESTS
297 void assignMat( Matrix* A, double testMat[3][3] )
298 {
299  for ( unsigned int i = 0; i < 3; ++i )
300  {
301  for ( unsigned int j = 0; j < 3; ++j )
302  (*A)[i][j] = testMat[i][j];
303  }
304 }
305 
306 #if 0
307 //In this set of tests, matrices are specially chosen so that
308 //we test out all degrees of the Pade approximant.
309 void testMarkovSolver()
310 {
311  MarkovSolver solver;
312 
313  Matrix *expQ;
314 
315  solver.Q_ = matAlloc( 3 );
316 
317  double testMats[5][3][3] = {
318  { //Will require 3rd degree Pade approximant.
319  { 0.003859554140797, 0.003828667792972, 0.000567545354509 },
320  { 0.000630452326710, 0.001941502594891, 0.001687045130505 },
321  { 0.003882371127042, 0.003201121875555, 0.003662942100756 }
322  },
323  { //Will require 5th degree Pade approximant.
324  { 0.009032772098686, 0.000447799046538, 0.009951718245937 },
325  { 0.004122293240791, 0.005703676675533, 0.010337598714782 },
326  { 0.012352886634899, 0.004960259942209, 0.002429343859207 }
327  },
328  { //Will require 7th degree Pade approximant.
329  { 0.249033679156721, 0.026663192545146, 0.193727616177876 },
330  { 0.019543882188296, 0.240474520213763, 0.204325805163358 },
331  { 0.110669567443862, 0.001158556033517, 0.217173676340877 }
332  },
333  { //Will require 9th degree Pade approximant.
334  { 0.708590392291234, 0.253289557366033, 0.083402066470341 },
335  { 0.368148069351060, 0.675040384813246, 0.585189051240853 },
336  { 0.366939478800014, 0.276935085840161, 0.292304127720940 },
337  },
338  { //Will require 13th degree Pade approximant.,
339  { 5.723393958255834, 2.650265678621879, 2.455089725038183 },
340  { 5.563819918184171, 5.681063207977340, 6.573010933999208 },
341  { 4.510226911355842, 3.729779121596184, 6.131599680450886 }
342  }
343  };
344 
345  double correctExps[5][3][3] = {
346  {
347  { 1.003869332885896, 0.003840707339656, 0.000572924780299 },
348  { 0.000635569997632, 1.001947309951925, 0.001691961742250 },
349  { 0.003898019965821, 0.003217566115560, 1.003673477658833 }
350  },
351  {
352  { 1.009136553319587, 0.000475947724581, 0.010011555682222 },
353  { 0.004217120071231, 1.005746704105642, 0.010400661735110 },
354  { 0.012434554824033, 0.004983402186283, 1.002519822649746 }
355  },
356  {
357  { 1.296879503336410, 0.034325768324765, 0.248960074106229 },
358  { 0.039392602584525, 1.272463533413523, 0.260228538022164 },
359  { 0.140263068698347, 0.003332731847933, 1.256323839764616 }
360  },
361  {
362  { 2.174221102665550, 0.550846463313377, 0.279203836454105 },
363  { 0.963674962388503, 2.222317715620410, 1.033020817699738 },
364  { 0.733257221615105, 0.559435366776953, 1.508376826849517 }
365  },
366  {
367  { 3.274163243250245e5, 2.405867301580962e5, 3.034390382218154e5 },
368  { 5.886803379935408e5, 4.325844111569120e5, 5.456065763194024e5 },
369  { 4.671930521670584e5, 3.433084310645007e5, 4.330101744194682e5 }
370  }
371  };
372 
373  double correctColumnNorms[5] = {
374  1.009005583407142,
375  1.025788228214852,
376  1.765512451893010,
377  3.871153286669158,
378  1.383289714485624e+06
379  };
380 
381  for ( unsigned int i = 0; i < 5; ++i )
382  {
383  assignMat( solver.Q_, testMats[i] );
384  expQ = solver.computeMatrixExponential();
385  assert( doubleEq( matColNorm( expQ ), correctColumnNorms[i] ) );
386 
387  //Comparing termwise just to be doubly sure.
388  for( unsigned int j = 0; j < 3; ++j )
389  {
390  for( unsigned int k = 0; k < 3; ++k )
391  assert( doubleEq( (*expQ)[j][k], correctExps[i][j][k] ) );
392  }
393 
394  delete expQ;
395  }
396 
398  //Testing state space interpolation.
400  const Cinfo* rateTableCinfo = MarkovRateTable::initCinfo();
401  const Cinfo* interpol2dCinfo = Interpol2D::initCinfo();
403  const Cinfo* markovSolverCinfo = MarkovSolver::initCinfo();
404 
405  vector< DimInfo > single;
406 
407  Id rateTable2dId = Id::nextId();
408  Id rateTable1dId = Id::nextId();
409  Id int2dId = Id::nextId();
410  Id vecTableId = Id::nextId();
411  Id solver2dId = Id::nextId();
412  Id solver1dId = Id::nextId();
413 
414  ObjId eRateTable2d = Element( rateTable2dId, rateTableCinfo,
415  "rateTable2d", single, 1, true );
416  Element *eRateTable1d = new Element( rateTable1dId, rateTableCinfo,
417  "rateTable1d", single, 1, true );
418  Element *eInt2d = new Element( int2dId, interpol2dCinfo, "int2d", single, 1 );
419  Element *eVecTable = new Element( vecTableId, vectorTableCinfo, "vecTable",
420  single, 1, true );
421  Element *eSolver2d = new Element( solver2dId, markovSolverCinfo,
422  "solver2d", single, 1, true );
423  Element *eSolver1d = new Element( solver1dId, markovSolverCinfo,
424  "solver1d", single, 1, true );
425 
426  Eref rateTable2dEref( eRateTable2d, 0 );
427  Eref rateTable1dEref( eRateTable1d, 0 );
428  Eref int2dEref( eInt2d, 0 );
429  Eref vecTableEref( eVecTable, 0 );
430  Eref solver2dEref( eSolver2d, 0 );
431  Eref solver1dEref( eSolver1d, 0 );
432 
433  vector< double > table1d;
434  vector< vector< double > > table2d;
435  double v, conc;
436 
437  MarkovRateTable* rateTable2d = reinterpret_cast< MarkovRateTable* >
438  ( rateTable2dEref.data() );
439  MarkovRateTable* rateTable1d = reinterpret_cast< MarkovRateTable* >
440  ( rateTable1dEref.data() );
441  VectorTable* vecTable = reinterpret_cast< VectorTable* >
442  ( vecTableEref.data() );
443  Interpol2D* int2d = reinterpret_cast< Interpol2D* >
444  ( int2dEref.data() );
445  MarkovSolver* markovSolver2d = reinterpret_cast< MarkovSolver* >
446  ( solver2dEref.data() );
447  MarkovSolver* markovSolver1d = reinterpret_cast< MarkovSolver* >
448  ( solver1dEref.data() );
449 
450  rateTable2d->init( 3 );
451  rateTable1d->init( 3 );
452 
453  vecTable->setMin( -0.10 );
454  vecTable->setMax( 0.10 );
455  vecTable->setDiv( 200 );
456 
457  v = vecTable->getMin();
458  for ( unsigned int i = 0; i < 201; ++i )
459  {
460  table1d.push_back( 1e3 * exp( 9 * v - 0.45 ) );
461  v += 0.001;
462  }
463 
464  vecTable->setTable( table1d );
465 
466  rateTable2d->setVtChildTable( 1, 3, vecTableId, 0 );
467  rateTable1d->setVtChildTable( 1, 3, vecTableId, 0 );
468 
469  int2d->setXmin( -0.10 );
470  int2d->setXmax( 0.10 );
471  int2d->setYmin( 0 );
472  int2d->setYmax( 50e-6 );
473 
474  v = int2d->getXmin();
475  table2d.resize( 201 );
476  for ( unsigned int i = 0; i < 201; ++i )
477  {
478  conc = int2d->getYmin();
479  for ( unsigned int j = 0; j < 50; ++j )
480  {
481  table2d[i].push_back( 1e3 * conc * exp( -45 * v + 0.65 ) );
482  conc += 1e-6;
483  }
484  v += 0.001;
485  }
486 
487  int2d->setTableVector( table2d );
488 
489  rateTable2d->setInt2dChildTable( 2, 3, int2dId );
490 
491  rateTable2d->setConstantRate( 3, 1, 0.652 );
492  rateTable2d->setConstantRate( 2, 1, 1.541 );
493 
494  rateTable1d->setConstantRate( 3, 1, 0.652 );
495  rateTable1d->setConstantRate( 2, 1, 1.541 );
496 
497  markovSolver2d->init( rateTable2dId, 0.1 );
498  markovSolver1d->init( rateTable1dId, 0.1 );
499 
500  markovSolver2d->setVm( 0.0533 );
501  markovSolver2d->setLigandConc( 3.41e-6 );
502 
503  markovSolver1d->setVm( 0.0533 );
504 
505  Vector initState;
506 
507  initState.push_back( 0.2 );
508  initState.push_back( 0.4 );
509  initState.push_back( 0.4 );
510 
511  markovSolver2d->setInitialState( initState );
512  markovSolver2d->computeState();
513 
514  Vector interpState = markovSolver2d->getState();
515 
516  rateTable2dId.destroy();
517  rateTable1dId.destroy();
518  int2dId.destroy();
519  vecTableId.destroy();
520  solver2dId.destroy();
521  solver1dId.destroy();
522 
523  cout << "." << flush;
524 
525 }
526 #endif // #if 0
527 #endif
#define DUMMY
Definition: MatrixOps.h:33
void init(Id, double)
Matrix * matMatAdd(const Matrix *A, const Matrix *B, double alpha, double beta)
Definition: MatrixOps.cpp:111
vector< double > Vector
Definition: MatrixOps.h:23
static double b3[4]
Definition: MarkovSolver.h:76
void process(const Eref &, ProcPtr)
void reinit(const Eref &, ProcPtr)
double getMin() const
#define SECOND
Definition: MatrixOps.h:31
void setXmin(double value)
Definition: Interpol2D.cpp:229
Matrix * computePadeApproximant(Matrix *, unsigned int)
Matrix * computeMatrixExponential()
Definition: Dinfo.h:60
Matrix * matScalShift(const Matrix *A, double mul, double add)
Definition: MatrixOps.cpp:175
void setMin(double)
static unsigned int mCandidates[5]
Definition: MarkovSolver.h:81
void setVtChildTable(unsigned int, unsigned int, Id, unsigned int)
void setInitialState(Vector)
Vector getState() const
Definition: ObjId.h:20
static double b9[10]
Definition: MarkovSolver.h:67
void setTable(vector< double >)
static double b13[14]
Definition: MarkovSolver.h:61
double getXmin() const
Definition: Interpol2D.cpp:238
static const Cinfo * vectorTableCinfo
static const Cinfo * markovSolverCinfo
static double b5[6]
Definition: MarkovSolver.h:74
void destroy() const
Definition: Id.cpp:176
void log(string msg, serverity_level_ type=debug, bool redirectToConsole=true, bool removeTicks=true)
Log to console (and to a log-file)
static const Cinfo * initCinfo()
bool doubleEq(double x, double y)
Definition: doubleEq.cpp:16
Matrix * matMatMul(Matrix *A, Matrix *B)
Definition: MatrixOps.cpp:36
static Id nextId()
Definition: Id.cpp:132
double getYmin() const
Definition: Interpol2D.cpp:302
static double thetaM[5]
Definition: MarkovSolver.h:78
void setTableVector(vector< vector< double > > value)
Definition: Interpol2D.cpp:420
static const Cinfo * initCinfo()
void init(unsigned int)
void setMax(double)
static const Cinfo * initCinfo()
void setYmax(double value)
Definition: Interpol2D.cpp:307
Definition: Eref.h:26
static const Cinfo * initCinfo()
Definition: Interpol2D.cpp:25
Matrix * matEyeAdd(const Matrix *A, double k)
Definition: MatrixOps.cpp:147
void matInv(Matrix *A, vector< unsigned int > *swaps, Matrix *invA)
Definition: MatrixOps.cpp:348
vector< vector< double > > Matrix
Definition: MatrixOps.h:22
void setConstantRate(unsigned int, unsigned int, double)
Definition: Id.h:17
void reinit(const Eref &, ProcPtr)
double matColNorm(Matrix *A)
Definition: MatrixOps.cpp:282
static const Cinfo * initCinfo()
Definition: VectorTable.cpp:18
void setYmin(double value)
Definition: Interpol2D.cpp:293
#define FIRST
Definition: MatrixOps.h:30
void setInt2dChildTable(unsigned int, unsigned int, Id)
double matTrace(Matrix *A)
Definition: MatrixOps.cpp:271
void setDiv(unsigned int)
Definition: Cinfo.h:18
Matrix * matAlloc(unsigned int n)
Definition: MatrixOps.cpp:480
void setXmax(double value)
Definition: Interpol2D.cpp:243
static double b7[8]
Definition: MarkovSolver.h:71
void process(const Eref &, ProcPtr)
Definition: Finfo.h:12