https://github.com/cran/sbioPN
Raw File
Tip revision: cb9bccd9cb9d3b21276ae307fb246f69810e9c43 authored by Roberto Bertolusso on 15 March 2014, 00:00:00 UTC
version 1.1.0
Tip revision: cb9bccd
sHaseltineRawlings.c
// -*- mode: C; c-indent-level: 2; c-basic-offset: 2; tab-width: 8 -*-
//
// Copyright (C) 2009-2014 Roberto Bertolusso and Marek Kimmel
//
// This file is part of sbioPN.
//
// sbioPN 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 2 of the License, or
// (at your option) any later version.
//
// sbioPN 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
// along with sbioPN. If not, see <http://www.gnu.org/licenses/>.

#include <R.h>
#include <Rinternals.h>
#include <Rmath.h>
#include <R_ext/Rdynload.h>
#include <R_ext/Visibility.h>

#include "quicksort.h"
#include "helper.h"

//#define rb_double long double
#define rb_double double

//#define RB_PRINT_INCR_INFO
//#define RB_SAVE_INCR_INFO

#define a21 1./5.
#define c2 1./5.

#define a31 3./40.
#define a32 9./40.
#define c3 3./10.

#define a41 44./45.
#define a42 -56./15.
#define a43 32./9.
#define c4 4./5.

#define a51 19372./6561.
#define a52 -25360./2187.
#define a53 64448./6561.
#define a54 -212./729.
#define c5 8./9.

#define a61 9017./3168.
#define a62 -355./33.
#define a63 46732./5247.
#define a64 49./176.
#define a65 -5103./18656.
#define c6 1.

#define a71 35./384.
#define a73 500./1113.
#define a74 125./192.
#define a75 -2187./6784.
#define a76 11./84.
#define c7 1.

#define b41 5179./57600.
#define b43 7571./16695.
#define b44 393./640.
#define b45 -92097./339200.
#define b46 187./2100.
#define b47 1./40.

#define b51 35./384.
#define b53 500./1113.
#define b54 125./192.
#define b55 -2187./6784.
#define b56 11./84.

#define err_pow 1./6.

#define INCR_TO_SAVE 200000

#define RB_MEMORY
#define RB_TIME
#define RB_SUBTIME

#ifdef RB_TIME
#include <time.h>
#endif

struct transition {
  // DO NOT CHANGE ORDER OF ELEMENTS!! (Optimized for total size of structure)
  char cPreNZ_len;
  char cSNZ_len;
  char cType_of_h;
  char cInGroup;
  int iPositionInGroup;
  // NOTE: 4 chars + 1 int use 8 bytes so no space is wasted in 64 bit machines

  int *piPreNZ_VoxelPlace;
  char *pcPreNZ_value;

  int *piSNZ_VoxelPlace;
  char *pcSNZ_value;

  union {
    double   dTrCnt;
    DL_FUNC *pDL_FUNC;
    SEXP     SEXP;
  } h;

  int *piHazardsToMod;

  int iHazardsToMod_count;
  int iLocalVoxelPlace_offset;

  char cSlow;
  char cSlowUpdatedByFastVoxelTransition;
  // Two bytes wasted.
};
typedef struct transition transition_el;


SEXP getListElement(SEXP list, const char *str);
/*
{
  SEXP elmt = R_NilValue, names = getAttrib(list, R_NamesSymbol);
  int i, len = length(list);
  
  for (i = 0; i < len; i++)
    if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) {
      elmt = VECTOR_ELT(list, i);
      break;
    }
  return elmt;
}
*/

typedef enum {
  HZ_DOUBLE,
  HZ_CFUNCTION,
  HZ_RFUNCTION
} HZ_type;

#define MIN_INCR 1e-20

/*
#include <pthread.h>
//#include <stdio.h>
#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}
*/



SEXP sHaseltineRawlings(SEXP model, SEXP T, SEXP delta, SEXP runs,
			SEXP place, SEXP transition, SEXP ect, SEXP burnRnd, SEXP rho)
{
  SEXP sexpTmp;
  int *piTmp;
  char cTmp;

  /*
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }
   //   pthread_exit(NULL);
   */
  int iVoxelPlaceIdx;
  int iVoxelTransitionIdx;

  int iBurnRnd = *INTEGER(burnRnd);

  if (iBurnRnd) {
    Rprintf("\nBurning %d random numbers...", iBurnRnd);
    GetRNGstate();
    int k;
    for (k = 0; k < iBurnRnd; k++) {
      unif_rand();
    }
    PutRNGstate();
    Rprintf(" done!\n", iBurnRnd);
  }

#ifdef RB_TIME
  clock_t c0, c1;
  c0 = clock();
  clock_t clkStep = 0;
  int iElSteps = 0, iTotalStepsOver50, iTotalStepsOver10;
#endif
#ifdef RB_MEMORY
  double dUsedMemAcum = 0, dThisMem;
#endif

  SEXP VoxelFamily = getListElement(model, "VoxelFamily");

  if (VoxelFamily == R_NilValue)
    error("VoxelFamily not provided!\n");

  // Process groups of Voxels
  int iVoxelFamily_len = length(VoxelFamily);
  int iVoxelFamily;
  
  int iVoxelSlowTransitions = 0,  iVoxelFastTransitions = 0;
  int iVoxelTransitions = 0;
  int iVoxelPlaces = 0;
  // First: Find out how many real Places and Transitions there are.
  for (iVoxelFamily = 0; iVoxelFamily < iVoxelFamily_len; iVoxelFamily++) {
    SEXP this_VoxelFamily = VECTOR_ELT(VoxelFamily, iVoxelFamily);

    if ((sexpTmp = getListElement(this_VoxelFamily, "pre")) == R_NilValue)
      error("pre not provided!\n");
    piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
    int iOrigTransitions = piTmp[0], iOrigPlaces = piTmp[1];

    if ((sexpTmp = getListElement(this_VoxelFamily, "Voxels")) == R_NilValue)
      error("Voxels not provided!\n");
    PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
    int iVoxels = INTEGER(sexpTmp)[0];
    UNPROTECT_PTR(sexpTmp);

    iVoxelPlaces += iOrigPlaces * iVoxels;

    if ((sexpTmp = getListElement(this_VoxelFamily, "TransitionInVoxelSubset")) == R_NilValue)
      error("TransitionInVoxelSubset not provided!\n");
    SEXP TransitionInVoxelSubset;
    PROTECT(TransitionInVoxelSubset = coerceVector(sexpTmp, INTSXP));
    int *piTransitionInVoxelSubset = INTEGER(TransitionInVoxelSubset);

    if ((sexpTmp = getListElement(this_VoxelFamily, "slow")) == R_NilValue)
      error("slow not provided!\n");
    SEXP slow;
    PROTECT(slow = coerceVector(sexpTmp, INTSXP));
    int *piSlow = INTEGER(slow);

    SEXP VoxelSubset;
    if ((VoxelSubset = getListElement(this_VoxelFamily, "VoxelSubset")) == R_NilValue)
      error("VoxelSubset not provided!\n");

    int iOrigTransition;
    for (iOrigTransition = 0; iOrigTransition < iOrigTransitions; iOrigTransition++) {
      int iThisVoxelTransitions = length(VECTOR_ELT(VoxelSubset, piTransitionInVoxelSubset[iOrigTransition] - 1));
      iVoxelTransitions += iThisVoxelTransitions;
      if (piSlow[iOrigTransition]) {
	iVoxelSlowTransitions += iThisVoxelTransitions;
      } else {
	iVoxelFastTransitions += iThisVoxelTransitions;
      }
    }
    UNPROTECT_PTR(slow);
    UNPROTECT_PTR(TransitionInVoxelSubset);

    SEXP JumpingPlace;
    if ((JumpingPlace = getListElement(this_VoxelFamily, "JumpingPlace")) != R_NilValue) {

      SEXP JumpingPattern;
      if ((JumpingPattern = getListElement(this_VoxelFamily, "JumpingPattern")) == R_NilValue)
	error("JumpingPattern not provided!\n");
      
      int iJumpingPlace;
      for (iJumpingPlace = 0; iJumpingPlace < length(JumpingPlace); iJumpingPlace++) {    
	sexpTmp = VECTOR_ELT(VECTOR_ELT(JumpingPlace, iJumpingPlace), 2);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iJumpingPattern = INTEGER(sexpTmp)[0] - 1;
	UNPROTECT_PTR(sexpTmp);

	sexpTmp = VECTOR_ELT(VECTOR_ELT(JumpingPlace, iJumpingPlace), 3);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iSlow = INTEGER(sexpTmp)[0];
	UNPROTECT_PTR(sexpTmp);
	
	sexpTmp = VECTOR_ELT(JumpingPattern, iJumpingPattern);
	piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
	int iJumps = piTmp[0];
	
	iVoxelTransitions += iJumps;      
	if (iSlow) {
	  iVoxelSlowTransitions += iJumps;
	} else {
	  iVoxelFastTransitions += iJumps;
	}
      }
    }
  }
  Rprintf("VoxelTransitions: %d\tVoxelPlaces: %d\n", iVoxelTransitions, iVoxelPlaces);
  Rprintf("VoxelSlowTransitions: %d\tVoxelFastTransitions: %d\n", iVoxelSlowTransitions, iVoxelFastTransitions);

  transition_el *pVoxelTransition = (transition_el *) R_alloc(iVoxelTransitions, sizeof(transition_el));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(transition_el) * iVoxelTransitions)/1e6);
  Rprintf("pVoxelTransition: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelTransitions, sizeof(transition_el));
#endif

  transition_el *pVoxelSlowTransition = pVoxelTransition;
  transition_el *pVoxelFastTransition = pVoxelTransition + iVoxelSlowTransitions;

  int iVoxelTransition;

  int iVoxelTransitionsPreNZ_len = 0;
  int iVoxelTransitionsSNZ_len = 0;

  int iVoxelPlacesPreNZ_len = 0;
  int *piVoxelPlacePreNZ_len = (int *) R_alloc(iVoxelPlaces, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelPlaces)/1e6);
  Rprintf("piVoxelPlacePreNZ_len: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlaces, sizeof(int));
#endif
  int **ppiVoxelPlacePreNZ_VoxelTransition = (int **) R_alloc(iVoxelPlaces, sizeof(int *));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int *) * iVoxelPlaces)/1e6);
  Rprintf("ppiVoxelPlacePreNZ_VoxelTransition: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlaces, sizeof(int *));
#endif

  int iVoxelPlacesSNZ_len = 0;
  int *piVoxelPlaceSNZ_len = (int *) R_alloc(iVoxelPlaces, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelPlaces)/1e6);
  Rprintf("piVoxelPlaceSNZ_len: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlaces, sizeof(int));
#endif
  int **ppiVoxelPlaceSNZ_VoxelTransition = (int **) R_alloc(iVoxelPlaces, sizeof(int *));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int *) * iVoxelPlaces)/1e6);
  Rprintf("ppiVoxelPlaceSNZ_VoxelTransition: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlaces, sizeof(int *));
#endif

  int iVoxelPlace;
  for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
    piVoxelPlacePreNZ_len[iVoxelPlace] = piVoxelPlaceSNZ_len[iVoxelPlace] = 0;
  }

  int *piPreNZ_VoxelPlace = NULL, *piSNZ_VoxelPlace = NULL;

  char *pcPreNZ_value = NULL, *pcSNZ_value = NULL;

  int iVoxelCurrentTransition = 0;
  int iVoxelPlace_offset = 0;
  // Second:
  for (iVoxelFamily = 0; iVoxelFamily < iVoxelFamily_len; iVoxelFamily++) {
    //Rprintf("Voxel group: %d\n", iVoxelFamily);
    SEXP this_VoxelFamily = VECTOR_ELT(VoxelFamily, iVoxelFamily);

    sexpTmp = getListElement(this_VoxelFamily, "pre");
    SEXP pre;
    PROTECT(pre = coerceVector(sexpTmp, INTSXP));
    int *piPre = INTEGER(pre);
    piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
    int iOrigTransitions = piTmp[0], iOrigPlaces = piTmp[1];
    //Rprintf("pre: rows: %d\tcols: %d\n", iOrigTransitions, iOrigPlaces);
    
    sexpTmp = getListElement(this_VoxelFamily, "Voxels");
    PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
    int iVoxels = INTEGER(sexpTmp)[0];
    UNPROTECT_PTR(sexpTmp);

    sexpTmp = getListElement(this_VoxelFamily, "post");
    SEXP post;
    PROTECT(post = coerceVector(sexpTmp, INTSXP));
    int *piPost = INTEGER(post);
    
    piPreNZ_VoxelPlace = (int *) Realloc(piPreNZ_VoxelPlace, iOrigPlaces, int);
    pcPreNZ_value = (char *) Realloc(pcPreNZ_value, iOrigPlaces, char);
    piSNZ_VoxelPlace = (int *) Realloc(piSNZ_VoxelPlace, iOrigPlaces, int);
    pcSNZ_value = (char *) Realloc(pcSNZ_value, iOrigPlaces, char);

    sexpTmp = getListElement(this_VoxelFamily, "TransitionInVoxelSubset");
    SEXP TransitionInVoxelSubset;
    PROTECT(TransitionInVoxelSubset = coerceVector(sexpTmp, INTSXP));
    int *piTransitionInVoxelSubset = INTEGER(TransitionInVoxelSubset);

    SEXP VoxelSubset;
    VoxelSubset = getListElement(this_VoxelFamily, "VoxelSubset");

    SEXP h;
    h = getListElement(this_VoxelFamily, "h");

    int iOrigTransition, iOrigPlace;
    for (iOrigTransition = 0; iOrigTransition < iOrigTransitions; iOrigTransition++) {      
      char cPreNZ_len = 0;
      char cSNZ_len = 0;
      for (iOrigPlace = 0; iOrigPlace < iOrigPlaces; iOrigPlace++) {
	if ((cTmp = piPre[iOrigTransition + iOrigTransitions * iOrigPlace])) {
	  piPreNZ_VoxelPlace[(int) cPreNZ_len] = iOrigPlace;
	  pcPreNZ_value[(int) cPreNZ_len++] = cTmp;
	}
	if ((cTmp = piPost[iOrigTransition + iOrigTransitions * iOrigPlace] - 
	     piPre[iOrigTransition + iOrigTransitions * iOrigPlace])) {
	  piSNZ_VoxelPlace[(int) cSNZ_len] = iOrigPlace;
	  pcSNZ_value[(int) cSNZ_len++] = cTmp;
	}
      }

      // For the current transition, find the subset of Voxels in which it applies.
      sexpTmp = VECTOR_ELT(VoxelSubset, piTransitionInVoxelSubset[iOrigTransition] - 1);
      int iVoxelSubset_len = length(sexpTmp);
      SEXP VoxelSubset;
      PROTECT(VoxelSubset = coerceVector(sexpTmp, INTSXP));
      int *piVoxelSubset = INTEGER(VoxelSubset); // Vector with subset of Voxels

      int iVoxelSubset;
      // Create a corresponding transition on each of the Voxels of this subset.
      for (iVoxelSubset = 0; iVoxelSubset < iVoxelSubset_len; iVoxelSubset++) {
	int iVoxel = piVoxelSubset[iVoxelSubset] - 1;
	int iLocalVoxelPlace_offset = iVoxelPlace_offset + iOrigPlaces * iVoxel;
	//Rprintf("Voxel: %d\tTransition: %d\tVoxelTransition: %d\n", iVoxel, iOrigTransition, iVoxelCurrentTransition);

	iVoxelTransitionsPreNZ_len += cPreNZ_len;
	for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < cPreNZ_len; iVoxelPlaceIdx++) {
	  iVoxelPlace = iLocalVoxelPlace_offset + piPreNZ_VoxelPlace[iVoxelPlaceIdx];
	  piVoxelPlacePreNZ_len[iVoxelPlace]++;
	  iVoxelPlacesPreNZ_len++;
	}

	iVoxelTransitionsSNZ_len += cSNZ_len;
	for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < cSNZ_len; iVoxelPlaceIdx++) {
	  iVoxelPlace = iLocalVoxelPlace_offset + piSNZ_VoxelPlace[iVoxelPlaceIdx];
	  piVoxelPlaceSNZ_len[iVoxelPlace]++;
	  iVoxelPlacesSNZ_len++;
	}
	iVoxelCurrentTransition++;
      }
      UNPROTECT_PTR(VoxelSubset);
    }
    UNPROTECT_PTR(TransitionInVoxelSubset);
    UNPROTECT_PTR(post);
    UNPROTECT_PTR(pre);

    // Manage jumps.
    SEXP JumpingPlace;
    if ((JumpingPlace = getListElement(this_VoxelFamily, "JumpingPlace")) != R_NilValue) {
      SEXP JumpingPattern;
      JumpingPattern = getListElement(this_VoxelFamily, "JumpingPattern");
      
      int iJumpingPlace;
      for (iJumpingPlace = 0; iJumpingPlace < length(JumpingPlace); iJumpingPlace++) {
	SEXP this_JumpingPlace = VECTOR_ELT(JumpingPlace, iJumpingPlace);

	sexpTmp = VECTOR_ELT(this_JumpingPlace, 0);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iOrigPlace = INTEGER(sexpTmp)[0] - 1;
	UNPROTECT_PTR(sexpTmp);

	sexpTmp = VECTOR_ELT(this_JumpingPlace, 2);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iJumpingPattern = INTEGER(sexpTmp)[0] - 1;
	UNPROTECT_PTR(sexpTmp);
	
	sexpTmp = VECTOR_ELT(JumpingPattern, iJumpingPattern);
	piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
	int iJumps = piTmp[0];
	SEXP jump;
	PROTECT(jump = coerceVector(sexpTmp, INTSXP));
	int *piJump = INTEGER(jump);
	int iJump;
	for (iJump = 0; iJump < iJumps; iJump++) {
	  int iFromVoxelPlace = iVoxelPlace_offset + iOrigPlaces * (piJump[iJump] - 1) + iOrigPlace;
	  int iToVoxelPlace = iVoxelPlace_offset + iOrigPlaces * (piJump[iJump + iJumps] - 1) + iOrigPlace;
	  char cToVoxelPlacePost_value = piJump[iJump + iJumps*2];

	  iVoxelTransitionsPreNZ_len++;

	  piVoxelPlacePreNZ_len[iFromVoxelPlace]++;
	  iVoxelPlacesPreNZ_len++;

	  iVoxelTransitionsSNZ_len++;

	  piVoxelPlaceSNZ_len[iFromVoxelPlace]++;
	  iVoxelPlacesSNZ_len++;
	  if (cToVoxelPlacePost_value) {
	    iVoxelTransitionsSNZ_len++;

	    piVoxelPlaceSNZ_len[iToVoxelPlace]++;
	    iVoxelPlacesSNZ_len++;
	  }

	  iVoxelCurrentTransition++;

	  //Rprintf("%d\t%d\n", iFromVoxelPlace, iToVoxelPlace);
	}
	UNPROTECT_PTR(jump);
      }
    }
    iVoxelPlace_offset += iOrigPlaces * iVoxels;
  }

  int *piThisPreNZ = (int *) R_alloc(iVoxelPlacesPreNZ_len, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelPlacesPreNZ_len)/1e6);
  Rprintf("ppiVoxelPlacePreNZ_VoxelTransition elements: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlacesPreNZ_len, sizeof(int));
#endif

  int *piThisSNZ = (int *) R_alloc(iVoxelPlacesSNZ_len, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelPlacesSNZ_len)/1e6);
  Rprintf("ppiVoxelPlaceSNZ_VoxelTransition elements: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlacesSNZ_len, sizeof(int));
#endif

  for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
    ppiVoxelPlacePreNZ_VoxelTransition[iVoxelPlace] = piThisPreNZ;
    ppiVoxelPlaceSNZ_VoxelTransition[iVoxelPlace] = piThisSNZ;

    piThisPreNZ += piVoxelPlacePreNZ_len[iVoxelPlace];
    piThisSNZ += piVoxelPlaceSNZ_len[iVoxelPlace];

    piVoxelPlacePreNZ_len[iVoxelPlace] = 0;
    piVoxelPlaceSNZ_len[iVoxelPlace] = 0;
  }

  piThisPreNZ = (int *) R_alloc(iVoxelTransitionsPreNZ_len, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelTransitionsPreNZ_len)/1e6);
  Rprintf("piPreNZ_VoxelPlace elements: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelTransitionsPreNZ_len, sizeof(int));
#endif

  char *pcThisPreNZ_value = (char *) R_alloc(iVoxelTransitionsPreNZ_len, sizeof(char));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(char) * iVoxelTransitionsPreNZ_len)/1e6);
  Rprintf("pcPreNZ_value total: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelTransitionsPreNZ_len, sizeof(char));
#endif
  
  piThisSNZ = (int *) R_alloc(iVoxelTransitionsSNZ_len, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelTransitionsSNZ_len)/1e6);
  Rprintf("piSNZ_VoxelPlace elements: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelTransitionsSNZ_len, sizeof(int));
#endif

  char *pcThisSNZ_value = (char *) R_alloc(iVoxelTransitionsSNZ_len, sizeof(char));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(char) * iVoxelTransitionsSNZ_len)/1e6);
  Rprintf("pcSNZ_value total: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelTransitionsSNZ_len, sizeof(char));
#endif

  iVoxelCurrentTransition = 0;
  int iVoxelCurrentSlowTransition = 0, iVoxelCurrentFastTransition = 0;
  iVoxelPlace_offset = 0;
  // Third:
  for (iVoxelFamily = 0; iVoxelFamily < iVoxelFamily_len; iVoxelFamily++) {
    //Rprintf("Voxel group: %d\n", iVoxelFamily);
    SEXP this_VoxelFamily = VECTOR_ELT(VoxelFamily, iVoxelFamily);

    sexpTmp = getListElement(this_VoxelFamily, "pre");
    SEXP pre;
    PROTECT(pre = coerceVector(sexpTmp, INTSXP));
    int *piPre = INTEGER(pre);
    piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
    int iOrigTransitions = piTmp[0], iOrigPlaces = piTmp[1];
    //Rprintf("pre: rows: %d\tcols: %d\n", iOrigTransitions, iOrigPlaces);
    
    sexpTmp = getListElement(this_VoxelFamily, "Voxels");
    PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
    int iVoxels = INTEGER(sexpTmp)[0];
    UNPROTECT_PTR(sexpTmp);

    sexpTmp = getListElement(this_VoxelFamily, "post");
    SEXP post;
    PROTECT(post = coerceVector(sexpTmp, INTSXP));
    int *piPost = INTEGER(post);
    
    piPreNZ_VoxelPlace = (int *) Realloc(piPreNZ_VoxelPlace, iOrigPlaces, int);
    pcPreNZ_value = (char *) Realloc(pcPreNZ_value, iOrigPlaces, char);
    piSNZ_VoxelPlace = (int *) Realloc(piSNZ_VoxelPlace, iOrigPlaces, int);
    pcSNZ_value = (char *) Realloc(pcSNZ_value, iOrigPlaces, char);

    sexpTmp = getListElement(this_VoxelFamily, "TransitionInVoxelSubset");
    SEXP TransitionInVoxelSubset;
    PROTECT(TransitionInVoxelSubset = coerceVector(sexpTmp, INTSXP));
    int *piTransitionInVoxelSubset = INTEGER(TransitionInVoxelSubset);

    sexpTmp = getListElement(this_VoxelFamily, "slow");
    SEXP slow;
    PROTECT(slow = coerceVector(sexpTmp, INTSXP));
    int *piSlow = INTEGER(slow);

    SEXP VoxelSubset;
    VoxelSubset = getListElement(this_VoxelFamily, "VoxelSubset");

    SEXP h;
    h = getListElement(this_VoxelFamily, "h");

    int iOrigTransition, iOrigPlace;
    for (iOrigTransition = 0; iOrigTransition < iOrigTransitions; iOrigTransition++) {      
      char cPreNZ_len = 0;
      char cSNZ_len = 0;
      for (iOrigPlace = 0; iOrigPlace < iOrigPlaces; iOrigPlace++) {
	if ((cTmp = piPre[iOrigTransition + iOrigTransitions * iOrigPlace])) {
	  piPreNZ_VoxelPlace[(int) cPreNZ_len] = iOrigPlace;
	  pcPreNZ_value[(int) cPreNZ_len++] = cTmp;
	}
	if ((cTmp = piPost[iOrigTransition + iOrigTransitions * iOrigPlace] - 
	     piPre[iOrigTransition + iOrigTransitions * iOrigPlace])) {
	  piSNZ_VoxelPlace[(int) cSNZ_len] = iOrigPlace;
	  pcSNZ_value[(int) cSNZ_len++] = cTmp;
	}
      }

      // For the current transition, find the subset of Voxels in which it applies.
      sexpTmp = VECTOR_ELT(VoxelSubset, piTransitionInVoxelSubset[iOrigTransition] - 1);
      int iVoxelSubset_len = length(sexpTmp);
      SEXP VoxelSubset;
      PROTECT(VoxelSubset = coerceVector(sexpTmp, INTSXP));
      int *piVoxelSubset = INTEGER(VoxelSubset); // Vector with subset of Voxels

      int iVoxelSubset;
      // Create a corresponding transition on each of the Voxels of this subset.
      for (iVoxelSubset = 0; iVoxelSubset < iVoxelSubset_len; iVoxelSubset++) {
	int iVoxel = piVoxelSubset[iVoxelSubset] - 1;
	int iLocalVoxelPlace_offset = iVoxelPlace_offset + iOrigPlaces * iVoxel;
	//Rprintf("Voxel: %d\tTransition: %d\tVoxelTransition: %d\n", iVoxel, iOrigTransition, iVoxelCurrentTransition);

	iVoxelCurrentTransition = (piSlow[iOrigTransition] ? iVoxelCurrentSlowTransition++ : iVoxelSlowTransitions + iVoxelCurrentFastTransition++);

	transition_el *pThisVoxelTransition = &pVoxelTransition[iVoxelCurrentTransition];

	if ((pThisVoxelTransition->cSlow = (char) piSlow[iOrigTransition]))
	  pThisVoxelTransition->cSlowUpdatedByFastVoxelTransition = 0;

	if (inherits(sexpTmp = VECTOR_ELT(h, iOrigTransition), "NativeSymbol")) {
	  pThisVoxelTransition->h.pDL_FUNC = (void *) R_ExternalPtrAddr(sexpTmp);
	  pThisVoxelTransition->cType_of_h = HZ_CFUNCTION;    
	} else if (isNumeric(sexpTmp)){
	  pThisVoxelTransition->h.dTrCnt = REAL(sexpTmp)[0];
	  pThisVoxelTransition->cType_of_h = HZ_DOUBLE;
	} else  if (isFunction(sexpTmp)) {
	  //SET_VECTOR_ELT(sexpFunction, iOrigTransition, lang1(sexpTmp));
	  //piHzType[iOrigTransition] = HZ_RFUNCTION;
	  ;
	} else {
	  error("Unrecognized transition function type\n");
	}

	pThisVoxelTransition->iLocalVoxelPlace_offset = iLocalVoxelPlace_offset;
	pThisVoxelTransition->cPreNZ_len = cPreNZ_len;
	pThisVoxelTransition->piPreNZ_VoxelPlace = piThisPreNZ;
	piThisPreNZ += cPreNZ_len;
	pThisVoxelTransition->pcPreNZ_value = pcThisPreNZ_value;
	pcThisPreNZ_value += cPreNZ_len;
	for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < cPreNZ_len; iVoxelPlaceIdx++) {
	  iVoxelPlace = iLocalVoxelPlace_offset + piPreNZ_VoxelPlace[iVoxelPlaceIdx];
	  pThisVoxelTransition->piPreNZ_VoxelPlace[iVoxelPlaceIdx] = iVoxelPlace;
	  pThisVoxelTransition->pcPreNZ_value[iVoxelPlaceIdx] = pcPreNZ_value[iVoxelPlaceIdx];

	  ppiVoxelPlacePreNZ_VoxelTransition[iVoxelPlace][piVoxelPlacePreNZ_len[iVoxelPlace]++] = iVoxelCurrentTransition;
	}

	pThisVoxelTransition->cSNZ_len = cSNZ_len;
	pThisVoxelTransition->piSNZ_VoxelPlace = piThisSNZ;
	piThisSNZ += cSNZ_len;
	pThisVoxelTransition->pcSNZ_value = pcThisSNZ_value;
	pcThisSNZ_value += cSNZ_len;
	for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < cSNZ_len; iVoxelPlaceIdx++) {
	  iVoxelPlace = iLocalVoxelPlace_offset + piSNZ_VoxelPlace[iVoxelPlaceIdx];
	  pThisVoxelTransition->piSNZ_VoxelPlace[iVoxelPlaceIdx] = iVoxelPlace;
	  pThisVoxelTransition->pcSNZ_value[iVoxelPlaceIdx] = pcSNZ_value[iVoxelPlaceIdx];

	  ppiVoxelPlaceSNZ_VoxelTransition[iVoxelPlace][piVoxelPlaceSNZ_len[iVoxelPlace]++] = iVoxelCurrentTransition;
	}
      }
      UNPROTECT_PTR(VoxelSubset);
    }
    UNPROTECT_PTR(slow);
    UNPROTECT_PTR(TransitionInVoxelSubset);
    UNPROTECT_PTR(post);
    UNPROTECT_PTR(pre);

    // Manage jumps.
    SEXP JumpingPlace;
    if ((JumpingPlace = getListElement(this_VoxelFamily, "JumpingPlace")) != R_NilValue) {

      SEXP JumpingPattern;
      JumpingPattern = getListElement(this_VoxelFamily, "JumpingPattern");
      
      int iJumpingPlace;
      for (iJumpingPlace = 0; iJumpingPlace < length(JumpingPlace); iJumpingPlace++) {
	SEXP this_JumpingPlace = VECTOR_ELT(JumpingPlace, iJumpingPlace);

	sexpTmp = VECTOR_ELT(this_JumpingPlace, 0);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iOrigPlace = INTEGER(sexpTmp)[0] - 1;
	UNPROTECT_PTR(sexpTmp);

	sexpTmp = VECTOR_ELT(this_JumpingPlace, 1);
	PROTECT(sexpTmp = coerceVector(sexpTmp, REALSXP));
	double dH = REAL(sexpTmp)[0];
	UNPROTECT_PTR(sexpTmp);

	sexpTmp = VECTOR_ELT(this_JumpingPlace, 2);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iJumpingPattern = INTEGER(sexpTmp)[0] - 1;
	UNPROTECT_PTR(sexpTmp);

	sexpTmp = VECTOR_ELT(VECTOR_ELT(JumpingPlace, iJumpingPlace), 3);
	PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
	int iSlow = INTEGER(sexpTmp)[0];
	UNPROTECT_PTR(sexpTmp);
	
	sexpTmp = VECTOR_ELT(JumpingPattern, iJumpingPattern);
	piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
	int iJumps = piTmp[0];
	SEXP jump;
	PROTECT(jump = coerceVector(sexpTmp, INTSXP));
	int *piJump = INTEGER(jump);
	int iJump;
	for (iJump = 0; iJump < iJumps; iJump++) {
	  int iFromVoxelPlace = iVoxelPlace_offset + iOrigPlaces * (piJump[iJump] - 1) + iOrigPlace;
	  int iToVoxelPlace = iVoxelPlace_offset + iOrigPlaces * (piJump[iJump + iJumps] - 1) + iOrigPlace;
	  char cToVoxelPlacePost_value = piJump[iJump + iJumps*2];

	iVoxelCurrentTransition = (iSlow ? iVoxelCurrentSlowTransition++ : iVoxelSlowTransitions + iVoxelCurrentFastTransition++);

	  transition_el *pThisVoxelTransition = &pVoxelTransition[iVoxelCurrentTransition];
	  
	  if ((pThisVoxelTransition->cSlow = (char) iSlow))
	    pThisVoxelTransition->cSlowUpdatedByFastVoxelTransition = 0;

	  pThisVoxelTransition->cPreNZ_len = 1;
	  pThisVoxelTransition->piPreNZ_VoxelPlace = piThisPreNZ;
	  piThisPreNZ++;
	  pThisVoxelTransition->pcPreNZ_value = pcThisPreNZ_value;
	  pcThisPreNZ_value++;

	  pThisVoxelTransition->h.dTrCnt = dH;
	  pThisVoxelTransition->cType_of_h = HZ_DOUBLE;
	  pThisVoxelTransition->iLocalVoxelPlace_offset = iVoxelPlace_offset + iOrigPlaces * (piJump[iJump] - 1);

	  pThisVoxelTransition->piPreNZ_VoxelPlace[0] = iFromVoxelPlace;
	  pThisVoxelTransition->pcPreNZ_value[0] = 1;

	  ppiVoxelPlacePreNZ_VoxelTransition[iFromVoxelPlace][piVoxelPlacePreNZ_len[iFromVoxelPlace]++] = iVoxelCurrentTransition;

	  pThisVoxelTransition->cSNZ_len = 1;
	  pThisVoxelTransition->piSNZ_VoxelPlace = piThisSNZ;
	  piThisSNZ++;
	  pThisVoxelTransition->pcSNZ_value = pcThisSNZ_value;
	  pcThisSNZ_value++;
	  pThisVoxelTransition->piSNZ_VoxelPlace[0] = iFromVoxelPlace;
	  pThisVoxelTransition->pcSNZ_value[0] = -1;
	  ppiVoxelPlaceSNZ_VoxelTransition[iFromVoxelPlace][piVoxelPlaceSNZ_len[iFromVoxelPlace]++] = iVoxelCurrentTransition;
	  if (cToVoxelPlacePost_value) {
	    pThisVoxelTransition->cSNZ_len++;
	    piThisSNZ++;
	    pcThisSNZ_value++;
	    pThisVoxelTransition->piSNZ_VoxelPlace[1] = iToVoxelPlace;
	    pThisVoxelTransition->pcSNZ_value[1] = cToVoxelPlacePost_value;
	    ppiVoxelPlaceSNZ_VoxelTransition[iToVoxelPlace][piVoxelPlaceSNZ_len[iToVoxelPlace]++] = iVoxelCurrentTransition;	  
	  }
	  //Rprintf("%d\t%d\n", iFromVoxelPlace, iToVoxelPlace);
	}
	UNPROTECT_PTR(jump);
      }
    }
    iVoxelPlace_offset += iOrigPlaces * iVoxels;
  }

  Free(piPreNZ_VoxelPlace);
  Free(pcPreNZ_value);
  Free(piSNZ_VoxelPlace);
  Free(pcSNZ_value);

  //  Rprintf("VoxelTransitions: %d\tVoxelCurrentTransition: %d\n", iVoxelTransitions, iVoxelCurrentTransition);

  // For the initial calculation of all hazards...
  int *piHazardsToMod_start = (int *) R_alloc(iVoxelTransitions, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelTransitions)/1e6);
  Rprintf("piHazardsToMod_start: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelTransitions, sizeof(int));
#endif
  
  int iHazardsToMod_count = 0;
  // Identify slow transitions (only counts) that need the hazards recalculated
  // when slow transition fire or depending on fast reactions.
  for(iVoxelTransition = 0; iVoxelTransition < iVoxelTransitions; iVoxelTransition++) {
    transition_el *pThisVoxelTransition = &pVoxelTransition[iVoxelTransition];
    int iHazardToCompTot = 0;
    for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cSNZ_len; iVoxelPlaceIdx++) {
      int iVoxelPlace = pThisVoxelTransition->piSNZ_VoxelPlace[iVoxelPlaceIdx];
      
      int iVoxelTransitionIdx2, iVoxelTransition2;
      for(iVoxelTransitionIdx2 = 0; iVoxelTransitionIdx2 < piVoxelPlacePreNZ_len[iVoxelPlace]; iVoxelTransitionIdx2++) {
	iVoxelTransition2 = ppiVoxelPlacePreNZ_VoxelTransition[iVoxelPlace][iVoxelTransitionIdx2];
	if (iVoxelTransition2 < iVoxelSlowTransitions) {
	  if(iVoxelTransition < iVoxelSlowTransitions) {
	    // SlowVoxelTransition updated by a SlowVoxelTransition
	    int iAddThis = TRUE;
	    int iVoxelTransitionIdx3;
	    for (iVoxelTransitionIdx3 = 0; iVoxelTransitionIdx3 < iHazardToCompTot; iVoxelTransitionIdx3++) {
	      if(piHazardsToMod_start[iVoxelTransitionIdx3] == iVoxelTransition2) {
		iAddThis = FALSE;
		break;
	      }
	    }	    
	    if (iAddThis)
	      piHazardsToMod_start[iHazardToCompTot++] = iVoxelTransition2;
	  } else {
	    // SlowVoxelTransition updated by a FastVoxelTransition
	    // Mark it generally as all this kind of SlowVoxelTransitions
	    // are updated together once a deterministic step is performed.
	    pVoxelTransition[iVoxelTransition2].cSlowUpdatedByFastVoxelTransition = 1;
	  }
	}
      }
    }
    iHazardsToMod_count += iHazardToCompTot;
  }  
  int *piThisHazardsToMod = (int *) R_alloc(iHazardsToMod_count, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iHazardsToMod_count)/1e6);
  Rprintf("piHazardsToMod elements: %.2f MB (%d x %d bytes)\n", dThisMem, iHazardsToMod_count, sizeof(int));
#endif
  int iSlowHazardsToModFromFast_len = 0;
  int *piSlowHazardsToModFromFast = (int *) R_alloc(iVoxelSlowTransitions, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelSlowTransitions)/1e6);
  Rprintf("piSlowHazardsToModFromFast: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelSlowTransitions, sizeof(int));
#endif
  //int iHazardsToMod_count2 = 0;
  // Identify slow transitions that need the hazards recalculated
  for(iVoxelTransition = 0; iVoxelTransition < iVoxelSlowTransitions; iVoxelTransition++) {
    transition_el *pThisVoxelTransition = &pVoxelSlowTransition[iVoxelTransition];
    if(pThisVoxelTransition->cSlowUpdatedByFastVoxelTransition) {
      piSlowHazardsToModFromFast[iSlowHazardsToModFromFast_len++] = iVoxelTransition;
    }
    int iHazardToCompTot = 0;
    for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cSNZ_len; iVoxelPlaceIdx++) {
      int iVoxelPlace = pThisVoxelTransition->piSNZ_VoxelPlace[iVoxelPlaceIdx];

      int iVoxelTransitionIdx2, iVoxelTransition2;
      for(iVoxelTransitionIdx2 = 0; iVoxelTransitionIdx2 < piVoxelPlacePreNZ_len[iVoxelPlace]; iVoxelTransitionIdx2++) {
	iVoxelTransition2 = ppiVoxelPlacePreNZ_VoxelTransition[iVoxelPlace][iVoxelTransitionIdx2];
	if (iVoxelTransition2 < iVoxelSlowTransitions) {
	  // SlowVoxelTransition updated by a SlowVoxelTransition
	  int iAddThis = TRUE;
	  int iVoxelTransitionIdx3;
	  for (iVoxelTransitionIdx3 = 0; iVoxelTransitionIdx3 < iHazardToCompTot; iVoxelTransitionIdx3++) {
	    if(piHazardsToMod_start[iVoxelTransitionIdx3] == iVoxelTransition2) {
	      iAddThis = FALSE;
	      break;
	    }
	  }	    
	  if (iAddThis)
	    piHazardsToMod_start[iHazardToCompTot++] = iVoxelTransition2;
	}
      }
    }
    pThisVoxelTransition->iHazardsToMod_count = iHazardToCompTot;
    pThisVoxelTransition->piHazardsToMod = piThisHazardsToMod;
    piThisHazardsToMod += iHazardToCompTot;

    //Rprintf("%d\t%d\n", iVoxelTransition < iVoxelSlowTransitions, iHazardToCompTot);
    for (iVoxelTransitionIdx = 0; iVoxelTransitionIdx < iHazardToCompTot; iVoxelTransitionIdx++) {
      pThisVoxelTransition->piHazardsToMod[iVoxelTransitionIdx] = piHazardsToMod_start[iVoxelTransitionIdx];
      //      iHazardsToMod_count2++;
    }
  }

  //Rprintf("%d\t%d\n", iHazardsToMod_count, iHazardsToMod_count2);
  //  error("");
  int iVoxelFastPlaceIdx_len = 0;
  int *piVoxelFastPlaceIdx = (int *) R_alloc(iVoxelPlaces, sizeof(int));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(int) * iVoxelPlaces)/1e6);
  Rprintf("piVoxelFastPlaceIdx: %.2f MB (%d x %d bytes)\n", dThisMem, iVoxelPlaces, sizeof(int));
#endif

  for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
    for (iVoxelTransitionIdx = 0; iVoxelTransitionIdx < piVoxelPlaceSNZ_len[iVoxelPlace]; iVoxelTransitionIdx++) {
      if (ppiVoxelPlaceSNZ_VoxelTransition[iVoxelPlace][iVoxelTransitionIdx] >= iVoxelSlowTransitions) {
	piVoxelFastPlaceIdx[iVoxelFastPlaceIdx_len++] = iVoxelPlace;
	break;
      }
    }
  }

  // For the initial calculation of all slow hazards...
  for(iVoxelTransition = 0; iVoxelTransition < iVoxelSlowTransitions; iVoxelTransition++) {
    piHazardsToMod_start[iVoxelTransition] = iVoxelTransition;
  }

  rb_double *pdK1 = (rb_double *) R_alloc(7*iVoxelPlaces, sizeof(rb_double));
#ifdef RB_MEMORY
  dUsedMemAcum += (dThisMem = ((double) sizeof(rb_double) * 7*iVoxelPlaces)/1e6);
  Rprintf("pdK1 to pdK7: %.2f MB (%d x %d bytes)\n", dThisMem, 7*iVoxelPlaces, sizeof(rb_double));
#endif
  rb_double *pdK2 = pdK1 + iVoxelPlaces;
  rb_double *pdK3 = pdK2 + iVoxelPlaces;
  rb_double *pdK4 = pdK3 + iVoxelPlaces;
  rb_double *pdK5 = pdK4 + iVoxelPlaces;
  rb_double *pdK6 = pdK5 + iVoxelPlaces;
  rb_double *pdK7 = pdK6 + iVoxelPlaces;
  rb_double *pdYdot = 0;
  
  double dEct = *REAL(ect);
  
  SEXP sexpTmpCrntMarking;
  PROTECT(sexpTmpCrntMarking = allocVector(REALSXP, iVoxelPlaces));
  // double *pdTmpCrntMarking = REAL(sexpTmpCrntMarking);
  rb_double *pdTmpCrntMarking = (rb_double *) R_alloc(iVoxelPlaces, sizeof(rb_double));
  
  SEXP sexpCrntMarking;
  PROTECT(sexpCrntMarking = allocVector(REALSXP, iVoxelPlaces));
    double *pdCrntMarking = REAL(sexpCrntMarking);
    //rb_double *pdCrntMarking = (rb_double *) R_alloc(iVoxelPlaces, sizeof(rb_double));

  rb_double *pdBakCrntMarking = (rb_double *) R_alloc(iVoxelPlaces, sizeof(rb_double));

  rb_double *pdCrntDiffMarking = (rb_double *) R_alloc(iVoxelPlaces, sizeof(rb_double));

  double dDelta = *REAL(delta);
  int iTotalSteps, iSectionSteps;
  double dT = 0;
  void *pCManage_time = 0;
  SEXP sexpRManage_time = 0;
  if (inherits(T, "NativeSymbol")) {
    pCManage_time = (void *) R_ExternalPtrAddr(T);
    dT = ((double(*)(double, rb_double *)) pCManage_time)(-1, pdCrntMarking);
  } else if (isNumeric(T)){
    dT = *REAL(T);
  } else if (isFunction(T)) {
    PROTECT(sexpRManage_time = lang1(T));
    
    defineVar(install("y"), sexpCrntMarking, rho);
    PROTECT(sexpTmp = allocVector(REALSXP, 1));
    *REAL(sexpTmp) = -1;
    defineVar(install("StartTime"), sexpTmp, rho);
    UNPROTECT_PTR(sexpTmp);
    dT = *REAL(VECTOR_ELT(eval(sexpRManage_time, rho),0));
  } else {
    error("Unrecognized time function type\n");
  }

  iTotalSteps = iSectionSteps = (int)(dT / dDelta) + 1;
#ifdef RB_TIME
  iTotalStepsOver50 = iTotalSteps/50;
  iTotalStepsOver10 = iTotalSteps/10;
#endif
  // Hazard vector
  double *pdHazard = (double *) R_alloc(iVoxelSlowTransitions, sizeof(double));
  double *pdBakHazard = (double *) R_alloc(iVoxelSlowTransitions, sizeof(double));

  int iRun, iRuns = *INTEGER(runs);
  
  SEXP sexpRun;
  PROTECT(sexpRun = allocVector(VECSXP, iRuns));
  
  int iTotalUsedRandomNumbers = 0;
  
  // DiscTime Vector
  SEXP sexpD_time;
  PROTECT(sexpD_time = allocVector(REALSXP, iTotalSteps));
  double *pdDiscTime = REAL(sexpD_time);
  double dTmp = 0;
  int k;
  for (k = 0; k < iTotalSteps; k++) {
    pdDiscTime[k] = dTmp;
    dTmp += dDelta;
  }
  
  SEXP sexpMarkingRowNames;
  PROTECT(sexpMarkingRowNames = allocVector(INTSXP, iTotalSteps));
  piTmp = INTEGER(sexpMarkingRowNames);
  for (k = 0; k < iTotalSteps; k++)
    piTmp[k] = k+1;
  
  double **ppdMarking = (double **) R_alloc(iVoxelPlaces, sizeof(double *));

#ifdef RB_SAVE_INCR_INFO
  double *pdIncr = (double *) R_alloc(INCR_TO_SAVE, sizeof(double));
  double *pdIncrTime = (double *) R_alloc(INCR_TO_SAVE, sizeof(double));
  double *pdAcumHazard = (double *) R_alloc(INCR_TO_SAVE, sizeof(double));
  double *pdIntHazard = (double *) R_alloc(INCR_TO_SAVE, sizeof(double));
  double *pdIntHazardTime = (double *) R_alloc(INCR_TO_SAVE, sizeof(double));
#endif

  int *piOrderedTransition = (int *) R_alloc(iVoxelSlowTransitions, sizeof(int));

#ifdef RB_TIME
  c1 = clock();
  Rprintf ("Elapsed CPU time: %f\n", (float) (c1 - c0)/CLOCKS_PER_SEC);
  c0 = c1;
#endif

  GetRNGstate();
  for (iRun = 0; iRun < iRuns; iRun++) {
    
#ifdef RB_SAVE_INCR_INFO
    int iTotAccpIncr = 0, iTotRejIncr = 0, iTotGoBackIncr = 0, iTotIntHazardTime = 0, iTotIncrTime = 0;
    double dSumAccpIncr = 0;
    double dSumSqAccpIncr = 0;
#endif
    
    int iUsedRandomNumbers = 0;
    Rprintf("%d ", iRun+1);
    
    // Totals for kind of transition vector
    SEXP sexpTotXTransition;
    PROTECT(sexpTotXTransition = allocVector(INTSXP, iVoxelTransitions));
    int *piTotTransitions = INTEGER(sexpTotXTransition);
    
    for(iVoxelTransition = 0; iVoxelTransition < iVoxelTransitions; iVoxelTransition++) {
      piTotTransitions[iVoxelTransition] = 0;
    }
    for(iVoxelTransition = 0; iVoxelTransition < iVoxelSlowTransitions; iVoxelTransition++) {
      piOrderedTransition[iVoxelTransition] = iVoxelTransition;
    }
    int iTillResort = 1000, iTotResort = 0;

    // Totals for Infinite Norm error per place
    SEXP sexpInfNormErrorXVoxelPlace;
    PROTECT(sexpInfNormErrorXVoxelPlace = allocVector(INTSXP, iVoxelPlaces));
    int *piInfNormErrorXVoxelPlace = INTEGER(sexpInfNormErrorXVoxelPlace);
    
    for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
      piInfNormErrorXVoxelPlace[iVoxelPlace] = 0;
    }
    
    SEXP sexpMarking;
    PROTECT(sexpMarking = allocVector(VECSXP, iVoxelPlaces));
    // NOTE: Need to address next line (expansion of place names!)
    //setAttrib(sexpMarking, R_NamesSymbol, place);
    //setAttrib(sexpMarking, R_RowNamesSymbol, sexpMarkingRowNames);
    //setAttrib(sexpMarking, R_ClassSymbol, ScalarString(mkChar("data.frame")));

    // Setup initial state
    int iVoxelCurrentPlace = 0;
    for (iVoxelFamily = 0; iVoxelFamily < iVoxelFamily_len; iVoxelFamily++) {
      SEXP this_VoxelFamily = VECTOR_ELT(VoxelFamily, iVoxelFamily);
      
      sexpTmp = getListElement(this_VoxelFamily, "pre");
      piTmp = INTEGER(getAttrib(sexpTmp, R_DimSymbol));
      int iOrigPlaces = piTmp[1];
      
      sexpTmp = getListElement(this_VoxelFamily, "Voxels");
      PROTECT(sexpTmp = coerceVector(sexpTmp, INTSXP));
      int iVoxels = INTEGER(sexpTmp)[0];
      UNPROTECT_PTR(sexpTmp);
      
      if ((sexpTmp = getListElement(this_VoxelFamily, "M")) == R_NilValue)
	error("M not provided!\n");
      SEXP M;
      PROTECT(M = coerceVector(sexpTmp, REALSXP));
      double *pdM = REAL(M);
      
      //Rprintf("\n");
      int iVoxel, iOrigPlace;
      for (iVoxel = 0; iVoxel < iVoxels; iVoxel++) {
	for (iOrigPlace = 0; iOrigPlace < iOrigPlaces; iOrigPlace++) {
	  SET_VECTOR_ELT(sexpMarking, iVoxelCurrentPlace, sexpTmp = allocVector(REALSXP, iTotalSteps));
	  ppdMarking[iVoxelCurrentPlace] = REAL(sexpTmp);
	  
	  pdCrntMarking[iVoxelCurrentPlace] = pdM[iVoxel + iVoxels * iOrigPlace];
	  
	  iVoxelCurrentPlace++;
	}
      }
      UNPROTECT_PTR(M);
    }
    
    double dAcumHazard = 0;
    for(iVoxelTransition = 0; iVoxelTransition < iVoxelSlowTransitions; iVoxelTransition++) {
      pdHazard[iVoxelTransition] = 0;
    }

    double dTime, dTarget = 0;
    int iTotTransitions = 0;
    
    double dIncr = MIN_INCR, dStartIncr;
    double dAbsoluteMaxError = 0;

    int iStep = 0;
    int iAcceptedIncr = 0, iRejectedIncr = 0, iInterruptCnt = 100000;
    double dNewHazard = 0;
#ifdef RB_TIME
    clkStep = clock();
    iElSteps = 0;
#endif
    do {
      if (pCManage_time || sexpRManage_time) {
	double dEnd = 0;
	if (pCManage_time) {
	  dEnd = ((double(*)(double, rb_double *)) pCManage_time)(dTarget, pdCrntMarking);
	} else {
	  defineVar(install("y"), sexpCrntMarking, rho);
	  PROTECT(sexpTmp = allocVector(REALSXP, 1));
	  *REAL(sexpTmp) = dTarget;
	  defineVar(install("StartTime"), sexpTmp, rho);
	  UNPROTECT_PTR(sexpTmp);
	  
	  sexpTmp = eval(sexpRManage_time, rho);
	  dEnd = *REAL(VECTOR_ELT(sexpTmp,0));
	  for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
	    pdCrntMarking[iVoxelPlace] = REAL(VECTOR_ELT(sexpTmp,1))[iVoxelPlace];
	  }
	}
	iSectionSteps = (int)(dEnd / dDelta) + 1;
      }
      
      for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
	ppdMarking[iVoxelPlace][iStep] = pdBakCrntMarking[iVoxelPlace] = pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace];
      }
      
      dTime = dTarget;
      dTarget += dDelta;

      dStartIncr = dIncr;
      
      // For the calculation of all hazards...
      int *piHazardsToMod = piHazardsToMod_start;
      int iHazardsToMod_count = iVoxelSlowTransitions;

	/*
      dAcumHazard = 0;
      for(iVoxelTransition = 0; iVoxelTransition < iVoxelSlowTransitions; iVoxelTransition++) {
	pdHazard[iVoxelTransition] = 0;
      }
	*/
      
      do {    
	// Get hazards only for the transitions associated with
	// places whose quantities changed in the last step.
	for(iVoxelTransitionIdx = 0; iVoxelTransitionIdx < iHazardsToMod_count; iVoxelTransitionIdx++) {
	  iVoxelTransition = piHazardsToMod[iVoxelTransitionIdx];
	  transition_el *pThisVoxelTransition = &pVoxelTransition[iVoxelTransition];

	  switch(pThisVoxelTransition->cType_of_h) {
	  case HZ_DOUBLE:
	    dNewHazard = pThisVoxelTransition->h.dTrCnt;
	    for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cPreNZ_len; iVoxelPlaceIdx++) {
	      char cPre = pThisVoxelTransition->pcPreNZ_value[iVoxelPlaceIdx];
	      // NOTE!!! Decide below between int or double
	      int iMarking = pdCrntMarking[pThisVoxelTransition->piPreNZ_VoxelPlace[iVoxelPlaceIdx]];
	      if (iMarking < cPre) {
		dNewHazard = 0;
		goto update_hazard_1;
	      }
	      for (k = 0; k < cPre; k++)
		dNewHazard *= (iMarking - k) / (double)(k+1);
	    }	    
	    break;
	  case HZ_CFUNCTION:	
	    dNewHazard = ((double(*)(double, rb_double *)) pThisVoxelTransition->h.pDL_FUNC)(dTime, pdCrntMarking + pThisVoxelTransition->iLocalVoxelPlace_offset);
	    break;
	  case HZ_RFUNCTION:
	    defineVar(install("y"), sexpCrntMarking, rho);
	    //dNewHazard = REAL(eval(VECTOR_ELT(sexpFunction, iVoxelTransition), rho))[0];
	    break;
	  }
	update_hazard_1:
	  dAcumHazard += dNewHazard - pdHazard[iVoxelTransition];
	  pdHazard[iVoxelTransition] = dNewHazard;
	}
	
	double dLogRandom;
	if (iVoxelSlowTransitions) {
	  dLogRandom = log(unif_rand());
	  iUsedRandomNumbers++;
	} else
	  dLogRandom = -DBL_MAX;
	double dIntHazard = 0;
	
	dIncr = dStartIncr;
	//dIncr = 1;
	dStartIncr = -1;
	
	int iRKs;
	double dEvalTime = 0;
	int iContinue = TRUE;
	int iStartRK = 1;
	do {
	  if (dTime + dIncr > dTarget) {
	    dIncr = dTarget - dTime;
	  }
	  for(iRKs = iStartRK; iRKs < 8; iRKs++) {
	    switch (iRKs) {
	    case 1:
	      dEvalTime = dTime;
	      pdYdot = pdK1;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace];
	      }
	      break;
	    case 2:
	      dEvalTime = dTime + c2 * dIncr;
	      pdYdot = pdK2;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace] +
		  a21*pdK1[iVoxelPlace] * dIncr;
	      }
	      break;
	    case 3:
	      dEvalTime = dTime + c3 * dIncr;
	      pdYdot = pdK3;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace] +
		  (a31*pdK1[iVoxelPlace] + a32*pdK2[iVoxelPlace]) * dIncr;
	      }
	      break;
	    case 4:
	      dEvalTime = dTime + c4 * dIncr;
	      pdYdot = pdK4;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace] +
		  (a41*pdK1[iVoxelPlace] + a42*pdK2[iVoxelPlace] + a43*pdK3[iVoxelPlace]) * dIncr;
	      }
	      break;
	    case 5:
	      dEvalTime = dTime + c5 * dIncr;
	      pdYdot = pdK5;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace] +
		  (a51*pdK1[iVoxelPlace] + a52*pdK2[iVoxelPlace] + a53*pdK3[iVoxelPlace] +
		   a54*pdK4[iVoxelPlace]) * dIncr;
	      }
	      break;
	    case 6:
	      dEvalTime = dTime + c6 * dIncr;
	      pdYdot = pdK6;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace] +
		  (a61*pdK1[iVoxelPlace] + a62*pdK2[iVoxelPlace] + a63*pdK3[iVoxelPlace] +
		   a64*pdK4[iVoxelPlace] + a65*pdK5[iVoxelPlace]) * dIncr;
	      }
	      break;
	    case 7:
	      dEvalTime = dTime + c7 * dIncr;
	      pdYdot = pdK7;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
		iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
		pdYdot[iVoxelPlace] = 0;
		pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace] +
		  (a71*pdK1[iVoxelPlace] + a73*pdK3[iVoxelPlace] + a74*pdK4[iVoxelPlace] +
		   a75*pdK5[iVoxelPlace] + a76*pdK6[iVoxelPlace]) * dIncr;
	      }
	      break;
	    }

	    for(iVoxelTransition = 0; iVoxelTransition < iVoxelFastTransitions; iVoxelTransition++) {
	      transition_el *pThisVoxelTransition = &pVoxelFastTransition[iVoxelTransition];
	      switch(pThisVoxelTransition->cType_of_h) {
	      case HZ_DOUBLE:
		dNewHazard = pThisVoxelTransition->h.dTrCnt;
		for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cPreNZ_len; iVoxelPlaceIdx++) {
		  for (k = 0; k < pThisVoxelTransition->pcPreNZ_value[iVoxelPlaceIdx]; k++)
		    dNewHazard *= pdTmpCrntMarking[pThisVoxelTransition->piPreNZ_VoxelPlace[iVoxelPlaceIdx]];
		}
		/*
		if (dNewHazard < dEct)
		  continue;
		*/
		break;
	      case HZ_CFUNCTION:	
		dNewHazard = ((double(*)(double, rb_double *)) pThisVoxelTransition->h.pDL_FUNC)(dEvalTime, pdTmpCrntMarking + pThisVoxelTransition->iLocalVoxelPlace_offset);
		break;
	      case HZ_RFUNCTION:
		// defineVar(install("y"), sexpCrntMarking, rho);
		//dNewHazard = REAL(eval(VECTOR_ELT(sexpFunction, iVoxelTransition), rho))[0];
		break;
	      }

	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cSNZ_len; iVoxelPlaceIdx++) {
		pdYdot[pThisVoxelTransition->piSNZ_VoxelPlace[iVoxelPlaceIdx]] += pThisVoxelTransition->pcSNZ_value[iVoxelPlaceIdx] * dNewHazard;
	      }
	    }
	  }
	  rb_double dInfNormError = 0, dInfNormMarking = 0;
	  int iInfNormErrorVoxelPlace = -1;
	  for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
	    iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
	    rb_double dYj = 
	      (b41*pdK1[iVoxelPlace] + b43*pdK3[iVoxelPlace] + b44*pdK4[iVoxelPlace] + b45*pdK5[iVoxelPlace] + b46*pdK6[iVoxelPlace] + b47*pdK7[iVoxelPlace]) * dIncr;
	    rb_double dZj = 
	      (pdCrntDiffMarking[iVoxelPlace] = (b51*pdK1[iVoxelPlace] + b53*pdK3[iVoxelPlace] + b54*pdK4[iVoxelPlace] + b55*pdK5[iVoxelPlace] + b56*pdK6[iVoxelPlace]) * dIncr);
	    
	    rb_double dThisError;
	    if ((dThisError = dYj-dZj) < 0.)
	      dThisError = -dThisError;
	    if (dThisError > dInfNormError) {
	      dInfNormError = dThisError;
	      iInfNormErrorVoxelPlace = iVoxelPlace;
	    }
	    rb_double dThisMarking;	    
	    if ((dThisMarking = pdCrntMarking[iVoxelPlace]) < 0.)
	      dThisMarking = -dThisMarking;
	    if (dThisMarking > dInfNormMarking)
	      dInfNormMarking = dThisMarking;
	  }
	  if (dInfNormMarking > 1.)
	    dInfNormMarking = 1.;
	  rb_double dTau;
	  if ((dTau = dEct*dInfNormMarking) == 0.)
	    dTau = MIN_INCR;

	  if (dInfNormError == 0.) {
	    if (dTau == MIN_INCR)
	      dInfNormError = MIN_INCR*1e-4;
	    else
	      dInfNormError = MIN_INCR;
	  }

	  piInfNormErrorXVoxelPlace[iInfNormErrorVoxelPlace]++;
	  if (dInfNormError > dTau) {
	    // Current increment is rejected.
	    // Try a new one and retry integration step
	    dIncr = .8 * dIncr * R_pow(dTau/dInfNormError,err_pow);
	    iRejectedIncr++;
	    continue;
	  }

	  iAcceptedIncr++;
	  if (dInfNormError > dAbsoluteMaxError)
	    dAbsoluteMaxError = dInfNormError;

	  for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
	    iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
	    pdBakCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace];
	    pdCrntMarking[iVoxelPlace] += pdCrntDiffMarking[iVoxelPlace];
	    pdK1[iVoxelPlace] = pdK7[iVoxelPlace];
	  }
	  if (iStartRK == 1)
	    iStartRK = 2;
	  
	  double dPrevAcumHazard = dAcumHazard;
	  for(iVoxelTransitionIdx = 0; iVoxelTransitionIdx < iSlowHazardsToModFromFast_len; iVoxelTransitionIdx++) {
	    iVoxelTransition = piSlowHazardsToModFromFast[iVoxelTransitionIdx];
	    transition_el *pThisVoxelTransition = &pVoxelTransition[iVoxelTransition];

	    switch(pThisVoxelTransition->cType_of_h) {
	    case HZ_DOUBLE:
	      dNewHazard = pThisVoxelTransition->h.dTrCnt;
	      for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cPreNZ_len; iVoxelPlaceIdx++) {
		char cPre = pThisVoxelTransition->pcPreNZ_value[iVoxelPlaceIdx];
		// NOTE!!! Decide below between int or double
		int iMarking = pdCrntMarking[pThisVoxelTransition->piPreNZ_VoxelPlace[iVoxelPlaceIdx]];
		if (iMarking < cPre) {
		  dNewHazard = 0;
		  goto update_hazard_2;
		}
		for (k = 0; k < cPre; k++)
		  dNewHazard *= (iMarking - k) / (double)(k+1);
	      }	    
	      break;
	    case HZ_CFUNCTION:	
	      dNewHazard = ((double(*)(double, rb_double *)) pThisVoxelTransition->h.pDL_FUNC)(dTime, pdCrntMarking + pThisVoxelTransition->iLocalVoxelPlace_offset);
	      break;
	    case HZ_RFUNCTION:
	      defineVar(install("y"), sexpCrntMarking, rho);
	      //dNewHazard = REAL(eval(VECTOR_ELT(sexpFunction, iVoxelTransition), rho))[0];
	      break;
	    }
	update_hazard_2:
	    dAcumHazard += dNewHazard - (pdBakHazard[iVoxelTransition] = pdHazard[iVoxelTransition]);
	    pdHazard[iVoxelTransition] = dNewHazard;
	  }
	  
	  double dIncrIntHazard = (dPrevAcumHazard + dAcumHazard) * dIncr / 2;
	  double dDiff = dIntHazard + dIncrIntHazard + dLogRandom;
	  if (fabs(dDiff) < dEct) {
	    // Next check is needed because once in a while
	    // you will end here on a first attempt
	    // and not after having entered the else below
	    // on the previous iteration, and you want to
	    // avoid having dStartIncr < 0 which will be
	    // assigned to dIncr for the next cycle...
	    if (dStartIncr < 0)
	      dStartIncr = dIncr;
	    iContinue = FALSE;
	    dIntHazard += dIncrIntHazard;
	  } else if (dDiff < 0) {
	    dIntHazard += dIncrIntHazard;
	  } else {
	    if (dStartIncr < 0)
	      dStartIncr = dIncr;
	    dIncr *= - (dIntHazard + dLogRandom) / dIncrIntHazard;
	    
	    // Invalidate results
	    for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < iVoxelFastPlaceIdx_len; iVoxelPlaceIdx++) {
	      iVoxelPlace = piVoxelFastPlaceIdx[iVoxelPlaceIdx];
	      pdCrntMarking[iVoxelPlace] = pdBakCrntMarking[iVoxelPlace];
	    }
	    dAcumHazard = dPrevAcumHazard;
	    for(iVoxelTransitionIdx = 0; iVoxelTransitionIdx < iSlowHazardsToModFromFast_len; iVoxelTransitionIdx++) {
	      iVoxelTransition = piSlowHazardsToModFromFast[iVoxelTransitionIdx];
	      pdHazard[iVoxelTransition] = pdBakHazard[iVoxelTransition];
	    }
	    iStartRK = 1;
	    continue;
	  }

	  // Update clock according to the last accepted increment
	  dTime += dIncr;

	  // Check if current state needs to be saved
	  if (dTime == dTarget) {
	    ++iStep;
	    // Update the state for the fixed incremented time.
	    for(iVoxelPlace = 0; iVoxelPlace < iVoxelPlaces; iVoxelPlace++) {
	      ppdMarking[iVoxelPlace][iStep] = pdCrntMarking[iVoxelPlace];
	    }
	    if (iStep == iSectionSteps - 1)
	      goto EXIT_LOOP;
#ifdef RB_TIME
	    iElSteps++;
	    if ((iStep % iTotalStepsOver50) == 0) {
	      clock_t clkTmp2 = clock();
	      double dSecondsToFinish = (double) (clkTmp2- clkStep)/CLOCKS_PER_SEC/iElSteps*(iTotalSteps-iStep);
	      Rprintf ("\t");
	      PrintfTime(dSecondsToFinish);
	      clkStep = clkTmp2;
	      iElSteps = 0;
	    }
	    if ((iStep % iTotalStepsOver10) == 0) {
	      Rprintf(".\n");
	    }
#endif
	    dTarget += dDelta;
	    
	    // Force check if user interrupted
	    iInterruptCnt = 1;
	  }
	  if (! --iInterruptCnt) {
	    // Allow user interruption
	    R_CheckUserInterrupt();
	    iInterruptCnt = 100000;
	  }
	  // Set new increment for next integration step
	  dIncr = .8 * dIncr * R_pow(dTau/dInfNormError,err_pow);
	} while (iContinue);

	while (!--iTillResort) {
	  quicksort(piOrderedTransition, piTotTransitions, 0, iVoxelSlowTransitions-1);
	  switch (iTotResort++) {
	  case 0:
	    iTillResort = 10000;
	    break;
	  case 1:
	    iTillResort = 100000;
	    break;
	  default:
	    iTillResort = 1000000;
	  }
	}
	double dPartialAcumHazard = 0;
	// Find out which transition happened
	double dRnd = runif(0, dAcumHazard);
	iUsedRandomNumbers++;
	for(iVoxelTransitionIdx = 0; iVoxelTransitionIdx < iVoxelSlowTransitions; iVoxelTransitionIdx++) {
	  iVoxelTransition = piOrderedTransition[iVoxelTransitionIdx];
	  if (dRnd < (dPartialAcumHazard += pdHazard[iVoxelTransition])) {
	    piTotTransitions[iVoxelTransition]++;
	    
	    transition_el *pThisVoxelTransition = &pVoxelTransition[iVoxelTransition];
	    piHazardsToMod = pThisVoxelTransition->piHazardsToMod;
	    iHazardsToMod_count = pThisVoxelTransition->iHazardsToMod_count;
	    for(iVoxelPlaceIdx = 0; iVoxelPlaceIdx < pThisVoxelTransition->cSNZ_len; iVoxelPlaceIdx++) {
	      iVoxelPlace = pThisVoxelTransition->piSNZ_VoxelPlace[iVoxelPlaceIdx];
	      // Update the state
	      if ((pdCrntMarking[iVoxelPlace] += pThisVoxelTransition->pcSNZ_value[iVoxelPlaceIdx]) < 0)
		pdCrntMarking[iVoxelPlace] = 0;
	      pdBakCrntMarking[iVoxelPlace] = pdTmpCrntMarking[iVoxelPlace] = pdCrntMarking[iVoxelPlace];
	    }
	    break;
	  }
	}
	++iTotTransitions;
      } while (TRUE);
    EXIT_LOOP:;
      Rprintf("|\n");
    } while (iSectionSteps < iTotalSteps);
    iTotalUsedRandomNumbers += iUsedRandomNumbers;
    Rprintf("\t%d\t%d\t%d\t%e\t%d\t%d", iTotTransitions, iUsedRandomNumbers, iTotalUsedRandomNumbers, dAbsoluteMaxError, iAcceptedIncr, iRejectedIncr);
    
#ifdef RB_SUBTIME
    c1 = clock();
    Rprintf ("\t To go: ");
    PrintfTime((double) (c1 - c0)/CLOCKS_PER_SEC/(iRun+1)*(iRuns-iRun-1));
#endif
    Rprintf("\n");

    SEXP sexpTotTransitions;
    PROTECT(sexpTotTransitions = allocVector(INTSXP, 1));
    INTEGER(sexpTotTransitions)[0] = iTotTransitions;
    
    SEXP sexpUsedRandomNumbers;
    PROTECT(sexpUsedRandomNumbers = allocVector(INTSXP, 1));
    INTEGER(sexpUsedRandomNumbers)[0] = iUsedRandomNumbers;
    
    SEXP sexpThisRun;
#ifdef RB_SAVE_INCR_INFO
    if (iRun >= 10)
      PROTECT(sexpThisRun = allocVector(VECSXP, 5));
    else
      PROTECT(sexpThisRun = allocVector(VECSXP, 10));
#else
    PROTECT(sexpThisRun = allocVector(VECSXP, 5));
#endif
    
    SET_VECTOR_ELT(sexpThisRun, 0, sexpMarking);
    UNPROTECT_PTR(sexpMarking);
    SET_VECTOR_ELT(sexpThisRun, 1, sexpTotXTransition);
    UNPROTECT_PTR(sexpTotXTransition);
    SET_VECTOR_ELT(sexpThisRun, 2, sexpTotTransitions);
    UNPROTECT_PTR(sexpTotTransitions);
    SET_VECTOR_ELT(sexpThisRun, 3, sexpUsedRandomNumbers);
    UNPROTECT_PTR(sexpUsedRandomNumbers);
    SET_VECTOR_ELT(sexpThisRun, 4, sexpInfNormErrorXVoxelPlace);
    UNPROTECT_PTR(sexpInfNormErrorXVoxelPlace);

    //    PrintValue(sexpThisRun);
    /*
    int *pttt = (int *) R_alloc(2000000, sizeof(int));
    PROTECT(sexpTmp = allocVector(REALSXP, 2000000));
      UNPROTECT_PTR(sexpTmp);
    */
#ifdef RB_SAVE_INCR_INFO
    if (iRun < 10) {
      SEXP sexpTmp;
      double *pdTmp;

      PROTECT(sexpTmp = allocVector(REALSXP, iTotIncrTime));
      pdTmp = REAL(sexpTmp);
      int i;
      for (i = 0; i < iTotIncrTime; i++)
	pdTmp[i] = pdIncr[i];
      SET_VECTOR_ELT(sexpThisRun, 5, sexpTmp);
      UNPROTECT_PTR(sexpTmp);
      
      PROTECT(sexpTmp = allocVector(REALSXP, iTotIncrTime));
      pdTmp = REAL(sexpTmp);
      for (i = 0; i < iTotIncrTime; i++)
	pdTmp[i] = pdIncrTime[i];
      SET_VECTOR_ELT(sexpThisRun, 6, sexpTmp);
      UNPROTECT_PTR(sexpTmp);
      
      PROTECT(sexpTmp = allocVector(REALSXP, iTotIntHazardTime));
      pdTmp = REAL(sexpTmp);
      for (i = 0; i < iTotIntHazardTime; i++)
	pdTmp[i] = pdAcumHazard[i];
      SET_VECTOR_ELT(sexpThisRun, 7, sexpTmp);
      UNPROTECT_PTR(sexpTmp);
      
      PROTECT(sexpTmp = allocVector(REALSXP, iTotIntHazardTime));
      pdTmp = REAL(sexpTmp);
      for (i = 0; i < iTotIntHazardTime; i++)
	pdTmp[i] = pdIntHazard[i];
      SET_VECTOR_ELT(sexpThisRun, 8, sexpTmp);
      UNPROTECT_PTR(sexpTmp);
      
      PROTECT(sexpTmp = allocVector(REALSXP, iTotIntHazardTime));
      pdTmp = REAL(sexpTmp);
      for (i = 0; i < iTotIntHazardTime; i++)
	pdTmp[i] = pdIntHazardTime[i];
      SET_VECTOR_ELT(sexpThisRun, 9, sexpTmp);
      UNPROTECT_PTR(sexpTmp);
    }
#endif
    //    PrintValue(sexpThisRun);
    
    SEXP sexpNames;
#ifdef RB_SAVE_INCR_INFO
    if (iRun >= 10)
      PROTECT(sexpNames = allocVector(VECSXP, 5));
    else
      PROTECT(sexpNames = allocVector(VECSXP, 10));
#else
    PROTECT(sexpNames = allocVector(VECSXP, 5));
#endif
    SET_VECTOR_ELT(sexpNames, 0, mkChar("M"));
    SET_VECTOR_ELT(sexpNames, 1, mkChar("transitions"));
    SET_VECTOR_ELT(sexpNames, 2, mkChar("tot.transitions"));
    SET_VECTOR_ELT(sexpNames, 3, mkChar("tot.rnd"));
    SET_VECTOR_ELT(sexpNames, 4, mkChar("max.inf.norm"));
#ifdef RB_SAVE_INCR_INFO
    if (iRun < 10) {
      SET_VECTOR_ELT(sexpNames, 5, mkChar("incr"));
      SET_VECTOR_ELT(sexpNames, 6, mkChar("incr.time"));
      SET_VECTOR_ELT(sexpNames, 7, mkChar("hazard"));
      SET_VECTOR_ELT(sexpNames, 8, mkChar("int.hazard"));
      SET_VECTOR_ELT(sexpNames, 9, mkChar("int.hazard.time"));
    }
#endif
    setAttrib(sexpThisRun, R_NamesSymbol, sexpNames);
    UNPROTECT_PTR(sexpNames);

    SET_VECTOR_ELT(sexpRun, iRun, sexpThisRun);
    UNPROTECT_PTR(sexpThisRun);
  }
  PutRNGstate();

#ifdef RB_MEMORY
  Rprintf("Total Memory used: %.2f MB\n", dUsedMemAcum);
#endif

  SEXP sexpAns;
  PROTECT(sexpAns = allocVector(VECSXP, 4));
  SET_VECTOR_ELT(sexpAns, 0, place);
  SET_VECTOR_ELT(sexpAns, 1, transition);
  SET_VECTOR_ELT(sexpAns, 2, sexpD_time);
  UNPROTECT_PTR(sexpD_time);
  SET_VECTOR_ELT(sexpAns, 3, sexpRun);
  UNPROTECT_PTR(sexpRun);

  SEXP sexpNames;
  PROTECT(sexpNames = allocVector(VECSXP, 4));
  SET_VECTOR_ELT(sexpNames, 0, mkChar("place"));
  SET_VECTOR_ELT(sexpNames, 1, mkChar("transition"));
  SET_VECTOR_ELT(sexpNames, 2, mkChar("dt"));
  SET_VECTOR_ELT(sexpNames, 3, mkChar("run"));
  setAttrib(sexpAns, R_NamesSymbol, sexpNames);
  UNPROTECT_PTR(sexpNames);

#ifdef RB_TIME
  c1 = clock();
  double dCpuTime = (double) (c1 - c0)/CLOCKS_PER_SEC;
  Rprintf ("Elapsed CPU time: ");
  PrintfTime(dCpuTime);
  Rprintf ("\t(%fs)\n", dCpuTime);
#endif

  if (sexpRManage_time)
    UNPROTECT_PTR(sexpRManage_time);
  //UNPROTECT_PTR(sexpFunction);
  UNPROTECT_PTR(sexpMarkingRowNames);
  UNPROTECT_PTR(sexpTmpCrntMarking);
  UNPROTECT_PTR(sexpCrntMarking);
  UNPROTECT_PTR(sexpAns);

  return(sexpAns);
}
back to top