Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • 2837cec
  • /
  • c
  • /
  • cell_functions.h
Raw File Download
Permalinks

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge Iframe embedding
swh:1:cnt:fbc1d22d0bb180bb4999be1ceb189577353b4798
directory badge Iframe embedding
swh:1:dir:fed0c944d4de09d9eb9eb6c7631f54d261e98a9a
Citations

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
cell_functions.h
/* Everything is much easier to handle as multiple files */
#include "debug.h"
#include "normal.h"
#include "exponential.h"

typedef struct haplo_t {        // The name for a haplotype in c is haplo-types, get it?
  struct haplo_t *parent;		// Every haplotype has a parent haplotype, thus defining the structure of the tree. 
  double ds;					// Every haplotype has a fitness that differs from its parent by ds. 
  double t;
} haplo_t;

typedef struct geno_t {			/* table entry: */
    struct geno_t *next; /* next entry in chain */
    __uint128_t genome; /* defined genome */
	double fitness;		/* fitness benefit due to drivers */
} geno_t;

typedef struct cell_t {
  double bi;			// Inverse birth rate, or inverse cell fitness
  double bt;			// Time until next birth
#if TREE
  haplo_t *h;
#endif
#if EXPLICIT_DRIVERS
  geno_t *genome;
#endif
} cell_t;

static cell_t *Cells, **Que;	// Global array of all cells, an array of pointers to every cell  
static double sd, sp, t, L;
static unsigned long n, nmin, nmax;

static inline double gamma_distribution() {
  double x = exponential();
  for (unsigned int i = 1; i <= SHAPE; i++) x += exponential();
  return x;
}

#define DISTRIBUTION(type) 	( type == 0 ? 1						: \
							( type == 1 ? exponential()			: \
							( type == 2 ? exp(SHAPE*normal())	: \
							( type == 3 ? gamma_distribution()	: \
							( type == 4 ? 2*uniform_double_PRN(): 1 )))))

#include "haplotype.h"
#include "genotype.h"

#define DRIVER_INTERACTION(dn) ( EPISTASIS == 1 ? (dn)*sd : (dn)*sd/(1+(dn)*sd) )

////////////////////////////////////////////////////////////////////////////////
// MUTATE.h                                 ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


void inline update(cell_t *c, double ds) {
#if TREE
	update_haplotype(c, ds);
#endif
    c->bi *= EPISTASIS == 1 ? 1/(1+ds*c->bi) : 1-ds;
}

static void passenger_mutate(cell_t *c, double p) {
	if (p <= L) return;
	update(c, -sp*DISTRIBUTION(PASSENGER_DISTRIBUTION)); 
	passenger_mutate(c, p*uniform_double_PRN()); 
}

#define BIRTH(x) { x->bt = t + exponential()*x->bi; }
static unsigned long Ud_int;

static void mutate(cell_t *c) {
	MT_FLUSH();
	if (Rand++->l <= Ud_int) {
#if EXPLICIT_DRIVERS
		double old_fitness = c->genome->fitness;	
		c->genome = explicit_driver(c->genome);
		update(c, DRIVER_INTERACTION(c->genome->fitness - old_fitness));
#else
		update(c, DRIVER_INTERACTION(DISTRIBUTION(DRIVER_DISTRIBUTION)));
#endif  
}	
	passenger_mutate(c, uniform_double_PRN());
	BIRTH(c);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Rest
/////////////////////////////////////////////////////////////////////////////////////////////////

/* See http://www.cs.caltech.edu/courses/cs191/paperscs191/JPhysChemA(2000-104)1876.pdf to understand Que 
The simulation can never have more than nmax cells. When there are fewer than nmax cells, the 'dead' cells are moved to the end of the que and assigned a birth time of INFINITY */
static cell_t **QueP1, **QueM1, sentinel_old, sentinel_young;		// Pointers and sentinels to check bounds of queues and update with maximum efficiency 

static int cell_compare(const void *a, const void *b) { return ( ((cell_t*)a)->bt > ((cell_t*)b)->bt  ? 1 : -1 ); }	// Are two genotypes identical?

void setup(unsigned long N_min, unsigned long N_max, double U_d, double U_p, double s_d, double s_p) {
    mt_init();
	nmin = N_min;
	nmax = N_max;
	Ud_int = (unsigned long)(U_d*pow(2, 64));
	sd = s_d;
	sp = s_p;
	L = exp(-U_p);
// SETUP CELLS & QUE
	Cells = (cell_t*)calloc(nmax, sizeof(cell_t));
	Que = (cell_t**)malloc(sizeof(cell_t**)*2*nmax);
	sentinel_old.bt = INFINITY;
	sentinel_young.bt = -1;
	Que[0] = &sentinel_young;
	for (cell_t **q=Que + nmax; q<Que + 2*nmax; q++) *q = &sentinel_old;
	QueM1 = Que;
	Que++;
	QueP1 = Que + 1;
}

#define SWAP_CELL_POINTERS(a,b) { cell_t *temp_cell = *(a); *(a) = *(b); *(b) = temp_cell; }
#define CHECK_HEAP_ORDERED() {if ((*child)->bt >= (*parent)->bt) return; }

void later(cell_t **parent) {				// re-orders que for a cell now dividing at a *later* point in time. 
							// These two functions are the rate limiting step in this algorithm; bit-wise operations and tail-recursion are used for speed. 
  cell_t **child = Que + ((parent-QueM1) << 1);		// location of child cell in the heap queue (x << 1 = x*2 in base 2) 
  if (child[0]->bt > child[-1]->bt) child--;    	// Each cell has two children; need youngest child   
  CHECK_HEAP_ORDERED();
  SWAP_CELL_POINTERS(child, parent); 				
  later(child);						// May be younger than grandchild...
}  

void sooner(cell_t **child) { 							// Move a cell up the birth queue if birth time has decreased 
  cell_t **parent = Que + ((child-QueP1) >> 1); 				// parent is the parent event of child in the queue (x >> 1 = x/2 in base 2) 
  CHECK_HEAP_ORDERED();
  SWAP_CELL_POINTERS(child, parent);
  sooner(parent);								// and now the parent becomes the child in the next round 
} 

double generation_time() {
    double Bi_sum = 0;
    for (cell_t **q=Que; q < Que+n; q++) Bi_sum += (*q)->bi;
    return Bi_sum/(2*n);
}

unsigned long simulation(unsigned long N_0, unsigned long t_max, unsigned long *Nt, double *Di, haplo_t **CTCs, double *fitness_array) {
  n = N_0; 
  t = 0;
  double t_next = 0;
  cell_t *c = Cells;
  for (double *fitness = fitness_array; fitness < fitness_array + N_0; fitness++, c++) { 
    c->bi = 1./ *fitness;
    BIRTH(c);
  }
#if TREE 
  init_tree(fitness_array);
#endif
#if EXPLICIT_DRIVERS
  init_genomes();
#endif
  for (; c<Cells+nmax; c++) c->bt = INFINITY;
  qsort(Cells, n, sizeof(cell_t), cell_compare);			/* Start cells out in order for Que */
  c=Cells;
  for (cell_t **q=Que; q < Que + nmax; q++, c++) *q = c;
/* Need to assign all elements in queue to a cell location since I'll use these pointers (i.e. pointers Q[i] : i > n) to find vacant cells spots when division occurs--I never create or destroy pointers to new locations, just swap */
// RUN SIMULATION
  for (int i=0; i<t_max; i++) {
    Nt[i] = n;
    t_next += generation_time();
#if CTCS
    CTCs[i] = (Que[rand_long(n)])->h;
#endif
    while (t<t_next) {
      t += exponential()*Di[n];												/* calculate time until next death, assuming this is the next event */
      if (Que[0]->bt<t) {													/* Birth */	
        t = Que[0]->bt;														/* update current time (we did not actually die!) */
        *Que[n] = *Que[0];													/* replicate cell and place at end of queue */
        mutate(Que[n]); 
        sooner(Que + n);													/* New cell at bottom might move up */
        if (++n >= nmax) {
          Nt[++i] = nmax; 
          return i; }														/* pop exceeded max */
        mutate(Que[0]);														/* mutate both daughters */
        later(Que);															/* New cell at bottom might move up */
        } else {
        cell_t **c = Que + rand_long(n);									/* randomly select cell to be killed & decrease pop */
        if (--n <= nmin) {
          Nt[++i] = nmin; 
          return i; }														/* Extinction */
        SWAP_CELL_POINTERS(c, Que + n);										/* destroy cell by replacing with cell at end of queue--make sure end of queue points to the dead cell because birth events use this pointer to find a vacant spot in Cells. */
        Que[n]->bt = INFINITY;												/* dead cells don't divide */
        sooner(c);															/* cell could've been younger than its parent, if so we should move it up. */
        later(c);															/* else move cell at end of queue down */
  } } } 
  Nt[t_max] = n;
  return t_max;
} 

void end() { 
	free(Cells);	Cells = NULL; 
	Que--;			// Que was originally incremented for a sentinel	
	free(Que);		Que = NULL;	
	free(H);		H = NULL;
	deallocate_genome_hashtable();
}

Software Heritage — Copyright (C) 2015–2025, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Contact— JavaScript license information— Web API

back to top