max_inter_ll.cpp.html mathcode2html   
 Source file:   max_inter_ll.cpp
 Converted:   Sat May 9 2015 at 14:46:13
 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 <string.h>
#include <iostream>
#include <fstream>

#include <string.h>
#include <set>

#include <boost/math/special_functions/next.hpp>
#define TDEAD_DELTA_FLOATS 5

#include "max_inter_ll.h"
#include "../qubfast/max_ll_util.h"
#include "../qubfast/ublas_matrixutil.h"

using std::cout;
using std::cerr;
using std::endl;
using std::set;


extern "C" MAXILL_API int inter_ll_arr(
						 int Ns, int *clazz, double *P0_in,  double *K0_in, double *K1_in, double *K2_in,
						 int *Ligand_in, int *Voltage_in, int *Pressure_in,
						 double *Constants, double tdead,
						 int Nseg, int *dwellCounts, int **classeses, float **durationses,
						 double *ll)
{
  std::vector<double*> K0, K1, K2;
  std::vector<int*> Lig, Vol, Pres;
  for (int i=0; i<Ns; ++i) {
    K0.push_back( K0_in + i*Ns );
    K1.push_back( K1_in + i*Ns );
    K2.push_back( K2_in + i*Ns );
    Lig.push_back( Ligand_in + i*Ns );
    Vol.push_back( Voltage_in + i*Ns );
    Pres.push_back( Pressure_in + i*Ns );
  }
  
  return inter_ll(Ns, clazz, P0_in, &(K0[0]), &(K1[0]), &(K2[0]), &(Lig[0]), &(Vol[0]), &(Pres[0]),
		  Constants, tdead, Nseg, dwellCounts, classeses, durationses, ll);
}


extern "C" MAXILL_API int inter_ll(
					     int Ns, int *clazz, double *P0_in,  double **K0_in, double **K1_in, double **K2_in,
					     int **Ligand_in, int **Voltage_in, int **Pressure_in,
					     double *Constants, double tdead,
					     int Nseg, int *dwellCounts, int **classeses, float **durationses,
					     double *ll)
{
  //std::ofstream logger;
  //logger.open("s:\\maxill_log.txt");
  
  matrix<double> K0;         matrix_from_arrays(K0, K0_in, Ns, Ns);
  matrix<double> K1;         matrix_from_arrays(K1, K1_in, Ns, Ns);
  matrix<double> K2;         matrix_from_arrays(K2, K1_in, Ns, Ns);
  matrix<int>    Ligand;     matrix_from_arrays(Ligand, Ligand_in, Ns, Ns);
  matrix<int>    Voltage;    matrix_from_arrays(Voltage, Voltage_in, Ns, Ns);
  matrix<int>    Pressure;    matrix_from_arrays(Pressure, Voltage_in, Ns, Ns);
  
  matrix<double> Q;          BuildQ_p(Ns, Q, K0, K1, K2, Ligand, Voltage, Pressure, Constants);
  matrix<double> eQ;         QtoQe(Q, clazz, tdead, eQ);
  matrix<double> P0;
  if ( P0_in ) 
    {
      matrix_from_array(P0, P0_in, 1, Ns);
      double sum = 0.0;
      for (int i=0; i<Ns; ++i)
	sum += P0_in[i];
      for (int i=0; i<Ns; ++i)
	P0(0,i) = (sum > 1e-8 ) ? (P0(0,i) / sum) : (1.0 / Ns);
    }
  else
    QtoPe(eQ, P0);
  int            Na;
  
  //logger << "K0: " << K0 << endl;
  //logger << "K1: " << K1 << endl;
  //logger << "K2: " << K2 << endl;
  //logger << "L:  " << Ligand << endl;
  //logger << "V:  " << Voltage << endl;
  //logger << "P:  " << Pressure << endl;
  //logger << "Q:  " << Q << endl;
  //logger << "eQ: " << eQ << endl;
  //logger << "P0: " << P0 << endl;
  
  // max class
  int maxcls = clazz[0];
  for (int i=1; i<Ns; ++i)
    if ( clazz[i] > maxcls )
      maxcls = clazz[i];
  std::vector< std::vector<int> > clazz_states(maxcls+1);
  for (int i=0; i<Ns; ++i)
    clazz_states[clazz[i]].push_back(i);
  
  int maxcls_data = -1;
  for (int i=0; i<Nseg; ++i) {
    int *end = classeses[i] + dwellCounts[i];
    for (int *cl = classeses[i]; cl != end; ++cl) 
      if ( *cl > maxcls_data )
	maxcls_data = *cl;
  }
  if ( maxcls_data > maxcls ) {
    cerr << "Not enough classes in the model." << endl;
    return -8;
  }
  
  // we eigendecompose each submatrix eQaa for quick exponentiation in the inner loop:
  std::vector< std::vector<double> > eigvals_aa(maxcls+1);
  std::vector< matrix<double> > eigvecs_aa(maxcls+1);
  std::vector< matrix<double> > eiginvs_aa(maxcls+1);
  vector<double> eig_imag(Ns);
  for (int a=0; a<=maxcls; ++a) {
    Na = (int) clazz_states[a].size();
    if ( Na ) {
      int *aa = &(clazz_states[a][0]);
      matrix<double> eQaa;   matrix_to_partition(eQ, Na, Na, aa, aa, eQaa);
      eigvals_aa[a].resize(Na);
      eigvecs_aa[a].resize(Na, Na);
      eiginvs_aa[a].resize(Na, Na);
      if ( ! eigen_vals_vecs(eQaa, &(eigvals_aa[a][0]), &(eig_imag[0]), eigvecs_aa[a], eiginvs_aa[a], cerr) ) {
	//output << "No convergence in eigen calculations" << endl;
	return -2;
      }
      for (int i=0; i<Na; ++i) {
	if ( fabs(eig_imag[i]) > 1e-5 ) {
	  //output << "Complex eigenvalues found: " << eig_imag[i] << endl;
	  return -2;
	}
	if ( eigvals_aa[a][i] > 1e-5 ) {
	  //output << "Positive eigenvalues found: " << eigvals_aa[a][i] << endl;
	  return -2;
	}
      }
    }
  }
  // Then for efficiency, allocate space for expm_eigen temps
  std::vector< matrix<double> > tmp_nxn(Ns+1), tmp_nxn_diag(Ns+1);
  for (int i=1; i<=Ns; ++i) {
    tmp_nxn[i].resize(i, i);
    tmp_nxn_diag[i].resize(i, i);
    for (int j=0; j<i; ++j)
      for (int k=0; k<i; ++k)
	tmp_nxn_diag[i](j,k) = 0.0;
  }
  // and a place for the final exponentiated matrices:
  std::vector< matrix<double> > eQ_aa(maxcls+1);
  for (int a=0; a<=maxcls; ++a) {
    Na = (int) clazz_states[a].size();
    if ( Na )
      eQ_aa[a].resize(Na, Na);
  }
  
  // partitions eQab are used for transition probability (per second)
  std::vector< std::vector< matrix<double> > > eQab;
  eQab.resize(maxcls+1);
  for (int a=0; a<=maxcls; ++a) {
    eQab[a].resize(maxcls+1);
    Na = (int) clazz_states[a].size();
    if ( Na ) {
      for (int b=0; b<=maxcls; ++b) {
	int Nb = (int) clazz_states[b].size();
	if ( (b != a) && Nb ) {
	  matrix<double>& subQ = eQab[a][b];
	  subQ.resize(Na, Nb);
	  matrix_to_partition(eQ, Na, Nb, &(clazz_states[a][0]), &(clazz_states[b][0]), subQ);
	}
      }
    }
  }
  
  // alpha (temp) rows per class, since they're different sizes
  // actually a pair apiece to avoid temporaries alpha_a <- alpha_a * At
  std::vector< vector<double> > alpha_pre(maxcls+1), alpha_post(maxcls+1);
  for (int a=0; a<=maxcls; ++a) {
    alpha_pre[a].resize( clazz_states[a].size() ); // 1, clazz...size
    alpha_post[a].resize( clazz_states[a].size() ); // 1, clazz...size
  }
  
  // scale accumulator
  *ll = 0.0;
  
  for (int iseg = 0; iseg<Nseg; ++iseg) {
    int Nd = dwellCounts[iseg];
    int *classes = classeses[iseg];
    float *durations = durationses[iseg];
    int a = classes[0];
    Na = (int) clazz_states[a].size();
    int b = a;
    int Nb = Na;
    
    // normalized P0 among possible start states
    double tot = 0.0;
    for (int i=0; i<Na; ++i) {
      alpha_pre[a](i) = P0(0,clazz_states[a][i]);
      tot += alpha_pre[a](i);
    }
    if ( tot ) {
      for (int i=0; i<Na; ++i)
	alpha_pre[a](i) /= tot;
    } else {
      for (int i=0; i<Na; ++i)
	alpha_pre[a](i) = 1.0 / Na;
    }
    *ll += alpha_logscale(alpha_pre[a]);
    
    for (int d=1; d<Nd; ++d) {
      a = b;
      Na = Nb;
      b = classes[d];
      Nb = (int) clazz_states[b].size();
      
      // * exp(Qaa * dur) [scale?]   * eQab [scale]
      expm_eig(&(eigvals_aa[a][0]), eigvecs_aa[a], eiginvs_aa[a], durations[d-1],
	       tmp_nxn_diag[Na], tmp_nxn[Na], eQ_aa[a]);
      noalias(alpha_post[a]) = prod(alpha_pre[a], eQ_aa[a]);
      // *ll += alpha_logscale(alpha_post[a]);
      
      noalias(alpha_pre[b]) = prod(alpha_post[a], eQab[a][b]);
      *ll += alpha_logscale(alpha_pre[b]);
    }
    
    a = b;
    Na = Nb;
    expm_eig(&(eigvals_aa[a][0]), eigvecs_aa[a], eiginvs_aa[a], durations[Nd-1],
	     tmp_nxn_diag[Na], tmp_nxn[Na], eQ_aa[a]);
    noalias(alpha_post[a]) = prod(alpha_pre[a], eQ_aa[a]);
    // *ll += alpha_logscale(alpha_post[a]);
    
    std::vector<int> not_a;
    for (int i=0; i<Ns; ++i)
      if ( clazz[i] != a )
	not_a.push_back(i);
    int Nz = (int) not_a.size();
    matrix<double> eQaz(Na, Nz);
    matrix_to_partition(eQ, Na, Nz, &(clazz_states[a][0]), &(not_a[0]), eQaz);
    vector<double> alpha_z(Nz);
    noalias(alpha_z) = prod(alpha_post[a], eQaz);
    *ll += alpha_logscale(alpha_z);
  }
  
  return 0; // success
}




extern "C" MAXILL_API void mil_prep_events( int *ndwt, int *idwt, float *tdwt, double tdead_ms )
{
  float td = float(tdead_ms * 1.0e-3);
  int ndwells = *ndwt;
  int i; // outgoing index
  int j; // incoming index
  int cls;
  float tm;
  
  // first, drop initial too-short events
  for ( j=0; j<ndwells; j++ ) {
    tm = tdwt[j] * 1.0e-3f;
    if ( (boost::math::float_distance(tm, td) < TDEAD_DELTA_FLOATS) || (tm > td) )
      break;
  }
  // then add the time-values of other too-shorts to the prev. dwell
  for ( i=0; j<ndwells; j++ ) {
    cls = idwt[j];
    tm = tdwt[j] * 1.0e-3f;
    
    if ( (i > 0) && (idwt[i-1] == cls) )
      tdwt[i-1] = (float)(tdwt[i-1] + tm);
    else if ( (i > 0) && ((boost::math::float_distance(tm, td) >= TDEAD_DELTA_FLOATS) && (tm <= td)) )
      tdwt[i-1] = (float)(tdwt[i-1] + tm);
    else {
      idwt[i] = cls;
      tdwt[i] = (float) (tm - td);
      i++;
    }
  }
  *ndwt = i;
}

extern "C" MAXILL_API void mil_prep_segments( int Nseg, int *dwellCounts, int **classeses, float **durationses, double tdead_ms )
{
  for (int i=0; i<Nseg; ++i)
    mil_prep_events(dwellCounts+i, classeses[i], durationses[i], tdead_ms);
}