max_ll_util.cpp.html | mathcode2html |
Source file: max_ll_util.cpp | |
Converted: Sun May 10 2015 at 16:06:29 | |
This documentation file will not reflect any later changes in the source file. |
$$\phantom{******** If you see this on the webpage then the
browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root
is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$
$$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$
$$\newcommand{\A}{{\cal A}}$$
$$\newcommand{\W}{{\cal W}}$$
/* Copyright 2008-2014 Research Foundation State University of New York */ /* This file is part of QUB Express. */ /* QUB Express is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* QUB Express is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* You should have received a copy of the GNU General Public License, */ /* named LICENSE.txt, in the QUB Express program directory. If not, see */ /* <http://www.gnu.org/licenses/>. */ /*
|
See also: Up: Index |
*/ #ifdef _WIN32 #include <windows.h> #else #include <stdlib.h> #define BOOL int #define TRUE 1 #define FALSE 0 #endif #include <iostream> #include <fstream> using std::cout; using std::cerr; using std::endl; #include <set> using std::set; #include <map> using std::map; #include <string.h> #include "max_ll_util.h" #include "ublas_matrixutil.h" //std::ofstream logg; #define MIN_ACTIVE_Q 0.0 /*
|
The Q matrix of rate constants (probability per second) is computed from intrinsic rate constants K0 and K1, and potentially Ligand- and Voltage-sensitive. \[Q_{a,b} = K0_{a,b} * Ligand_{a,b} * e^{K1_{a,b} * Voltage_{a,b}}\] \[Q_{a,a} = - \sum_i Q_{a,i}\] |
*/ QUBFAST_API void BuildQ(int Ns, matrix<double>& Q, matrix<double>& K0, matrix<double>& K1, matrix<int>& Ligand, matrix<int>& Voltage, double *Constants) { if ( ((int) Q.size1()) != Ns || ((int) Q.size2()) != Ns ) Q.resize(Ns, Ns); for (int a=0; a<Ns; ++a) { double rowsum = 0.0; for (int b=0; b<Ns; ++b) { if (a != b) { double k = K1(a,b); if ( Voltage(a,b) ) k *= Constants[ Voltage(a,b) ]; k = exp(k); k *= K0(a,b); if ( Ligand(a,b) ) { double lig = Constants[ Ligand(a,b) ]; k *= lig ? lig : MIN_ACTIVE_Q; } Q(a,b) = k; rowsum += k; } } Q(a,a) = - rowsum; } } QUBFAST_API void BuildQ_p(int Ns, matrix<double>& Q, matrix<double>& K0, matrix<double>& K1, matrix<double>& K2, matrix<int>& Ligand, matrix<int>& Voltage, matrix<int>& Pressure, double *Constants) { if ( ((int) Q.size1()) != Ns || ((int) Q.size2()) != Ns ) Q.resize(Ns, Ns); for (int a=0; a<Ns; ++a) { double rowsum = 0.0; for (int b=0; b<Ns; ++b) { if (a != b) { double k = K0(a,b); if ( Ligand(a,b) ) { double lig = Constants[ Ligand(a,b) ]; k *= lig ? lig : MIN_ACTIVE_Q; } double kExp = 0.0; if ( Voltage(a,b) ) kExp += K1(a,b) * Constants[Voltage(a,b)]; if ( Pressure(a,b) ) kExp += K2(a,b) * Constants[Pressure(a,b)]; k *= exp(kExp); Q(a,b) = k; rowsum += k; } } Q(a,a) = - rowsum; } } /*
|
"Qe" aka \({}^eQ\) is the "apparent" rate constant matrix, given that events with duration <= tdead are not recorded. MIL computes the probability of staying in class a for duration t using the submatrix \({}^eQ_{aa}\) \[A(a, t) = e^{{}^eQ_{aa} (t-tdead)}\] |
*/ QUBFAST_API void QtoQe(matrix<double>& Q, int *clazz, double tdead, matrix<double>& eQ) { /*
|
eQ is partitioned into its Na x Nb submatrices, for classes a and b (likewise partition Q) each partition is computed separately. Notation: going from class a to class b, z is "any class but a", and c is "any class but a or b". Iz is the identity matrix with dimensions of Qzz. \(a = b\): \({}^eQ_{aa} = Q_{aa} - Q_{az} * (I_z - e^{Q_{zz} * tdead}) * Q_{za}\) (accounts for going to another class for a short, then returning undetected) \(a \ne b\): \({}^eQ_{ab} = (Q_{ab} - (Q_{ac} * (I_c - e^{Q_{cc} * tdead}) * Q^{-1}_{cc} * Q_{cb}) * e^{Q_{bb} * tdead}\) (accounts for going to class c for a short, on the way from a to b, then staying in b long enough to be detected) |
*/ int n = (int) Q.size1(); if ( ((int) eQ.size1()) != n || ((int) eQ.size2()) != n ) eQ.resize(n, n); if ( tdead == 0.0 ) { for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) eQ(i,j) = Q(i,j); return; } set<int> classet; // no duplicates, sorted increasing, for iteration for (int i=0; i<n; ++i) classet.insert(clazz[i]); for (set<int>::iterator cls_i = classet.begin(); cls_i != classet.end(); ++cls_i) { std::vector<int> states, outs; for (int i=0; i<n; ++i) if ( *cls_i == clazz[i] ) states.push_back(i); else outs.push_back(i); int Na = (int) states.size(); int Nz = (int) outs.size(); int *sts = & (states[0]); int *ots = & (outs[0]); matrix<double> Qaa(Na, Na); matrix_to_partition(Q, Na, Na, sts, sts, Qaa); matrix<double> Qaz(Na, Nz); matrix_to_partition(Q, Na, Nz, sts, ots, Qaz); matrix<double> Qza(Nz, Na); matrix_to_partition(Q, Nz, Na, ots, sts, Qza); matrix<double> Qzz(Nz, Nz); matrix_to_partition(Q, Nz, Nz, ots, ots, Qzz); matrix<double> Iz(Nz, Nz); fill_identity(Iz); matrix<double> Az(Nz, Nz); expm(Qzz, tdead, Az); matrix<double> Qzi; invm(Qzz, Qzi); matrix<double> missed_returning; missed_returning.resize(Na, Na); noalias(missed_returning) = prod(matrix<double>(prod(matrix<double>(prod(Qaz, matrix<double>(Iz - Az))), Qzi)), Qza); matrix<double> eQaa(Na, Na); noalias(eQaa) = Qaa - missed_returning; matrix_from_partition(eQ, Na, Na, sts, sts, eQaa); for (set<int>::iterator cls_j = classet.begin(); cls_j != classet.end(); ++cls_j) { if ( *cls_j != *cls_i ) { std::vector<int> bees, cees; for (int i=0; i<n; ++i) if ( *cls_j == clazz[i] ) bees.push_back(i); else if ( *cls_i != clazz[i] ) cees.push_back(i); int Nb = (int) bees.size(); int Nc = (int) cees.size(); int *bs = Nb ? &(bees[0]) : NULL; int *cs = Nc ? &(cees[0]) : NULL; matrix<double> Qab(Na, Nb); matrix_to_partition(Q, Na, Nb, sts, bs, Qab); matrix<double> Qbb(Nb, Nb); matrix_to_partition(Q, Nb, Nb, bs, bs, Qbb); matrix<double> escaped_indirect(Na, Nb); if ( Nc ) { matrix<double> Qac(Na, Nc); matrix_to_partition(Q, Na, Nc, sts, cs, Qac); matrix<double> Qcc(Nc, Nc); matrix_to_partition(Q, Nc, Nc, cs, cs, Qcc); matrix<double> Qcb(Nc, Nb); matrix_to_partition(Q, Nc, Nb, cs, bs, Qcb); matrix<double> Ic(Nc, Nc); fill_identity(Ic); matrix<double> Ac(Nc, Nc); expm(Qcc, tdead, Ac); matrix<double> Qci(Nc, Nc); invm(Qcc, Qci); noalias(escaped_indirect) = prod( matrix<double>(prod( matrix<double>(prod(Qac, Ic - Ac)), Qci )), Qcb); } else { // no third class? can't escape indirectly fill_const(escaped_indirect, 0.0); } matrix<double> Ab(Nb, Nb); expm(Qbb, tdead, Ab); matrix<double> eQab(Na, Nb); noalias(eQab) = prod(Qab - escaped_indirect, Ab); matrix_from_partition(eQ, Na, Nb, sts, bs, eQab); } } } } /*
|
As discussed in (Milescu 2005), it can be preferable to start an experiment at equilibrium. Entry probabilities (P0) are then no longer constant, but a function of rate constants. We use the "direct" method given in Neher and Sakmann: Defining \(S = [Q | 1]\) and \(u\) a row vector of ones, \[P_{eq} = u \cdot (S \cdot S^T)^{-1}\] |
*/ QUBFAST_API void QtoPe(matrix<double>& Q, matrix<double>& Pe) { int N = (int) Q.size1(); if ( ((int) Pe.size1()) != 1 || ((int) Pe.size2()) != N ) Pe.resize(1, N); matrix<double> S(N, N+1); matrix<double> U(1, N); for (int i=0; i<N; ++i) { for (int j=0; j<=N; ++j) S(i,j) = (j < N) ? Q(i,j) : 0.0; S(i,N) = 1.0; U(0,i) = 1.0; } matrix<double> SST(N, N); noalias(SST) = prod(S, trans(S)); matrix<double> SSTI(N, N); invm(SST, SSTI); noalias(Pe) = prod(U, SSTI); } QUBFAST_API double alpha_logscale(vector<double>& alpha) { double tot = 0.0; for (vector<double>::iterator ii = alpha.begin(); ii != alpha.end(); ++ii) tot += *ii; double scale = tot ? (1.0 / tot) : 1e10; for (vector<double>::iterator ii = alpha.begin(); ii != alpha.end(); ++ii) *ii *= scale; // std::cerr << scale << std::endl; return - log(scale); }