<commit_before>// ext/games_dice/probabilities.c

#include <stdio.h>
#include "probabilities.h"

VALUE NewProbabilities = Qnil;

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  General utils
//

static inline int max( int *a, int n ) {
  int m = -1000000000;
  int i;
  for ( i=0; i < n; i++ ) {
    m = a[i] > m ? a[i] : m;
  }
  return m;
}

static inline int min( int *a, int n ) {
  int m = 1000000000;
  int i;
  for ( i=0; i < n; i++ ) {
    m = a[i] < m ? a[i] : m;
  }
  return m;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Probability List basics - create, delete, copy
//

static ProbabilityList *create_probability_list() {
  ProbabilityList *pl;
  pl = malloc (sizeof(ProbabilityList));
  if ( pl == NULL ) {
    rb_raise(rb_eRuntimeError, "Could not allocate memory for NewProbabilities");
  }
  pl->probs = NULL;
  pl->slots = 0;
  pl->offset = 0;
  return pl;
}

static void destroy_probability_list( ProbabilityList *pl ) {
  free( pl->probs );
  free( pl );
  return;
}

static double *alloc_probs( ProbabilityList *pl, int slots ) {
  if ( slots < 1 || slots > 1000000 ) {
    rb_raise(rb_eArgError, "Bad number of probability slots");
  }
  pl->slots = slots;
  // TODO: Should this be a NALLOC?
  double *pr = malloc( slots * sizeof(double));
  if (pr == NULL) {
    rb_raise(rb_eRuntimeError, "Could not allocate memory for NewProbabilities");
  }
  pl->probs = pr;
  return pr;
}

static double *alloc_probs_iv( ProbabilityList *pl, int slots, double iv ) {
  if ( iv < 0.0 || iv > 1.0 ) {
    rb_raise(rb_eArgError, "Bad single probability value");
  }
  double *pr = alloc_probs( pl, slots );
  int i;
  for(i=0; i<slots; i++) {
    pr[i] = iv;
  }
  return pr;
}

static ProbabilityList *copy_probability_list( ProbabilityList *orig ) {
  ProbabilityList *pl = create_probability_list();
  double *pr = alloc_probs( pl, orig->slots );
  pl->offset = orig->offset;
  memcpy( pr, orig->probs, orig->slots * sizeof(double) );
  return pl;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Probability List core "native" methods
//

static inline int pl_min( ProbabilityList *pl ) {
  return pl->offset;
}

static inline int pl_max( ProbabilityList *pl ) {
  return pl->offset + pl->slots - 1;
}

static ProbabilityList *pl_add_distributions( ProbabilityList *pl_a, ProbabilityList *pl_b ) {
  int s = pl_a->slots + pl_b->slots - 1;
  int o = pl_a->offset + pl_b->offset;
  int i,j;

  ProbabilityList *pl = create_probability_list();
  pl->offset = o;
  double *pr = alloc_probs_iv( pl, s, 0.0 );
  for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
    pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
  } }
  return pl;
}

static ProbabilityList *pl_add_distributions_mult( int mul_a, ProbabilityList *pl_a, int mul_b, ProbabilityList *pl_b ) {
  int pts[4] = {
    mul_a * pl_min( pl_a ) + mul_b * pl_min( pl_b ),
    mul_a * pl_max( pl_a ) + mul_b * pl_min( pl_b ),
    mul_a * pl_min( pl_a ) + mul_b * pl_max( pl_b ),
    mul_a * pl_max( pl_a ) + mul_b * pl_max( pl_b ) };

  int combined_min = min( pts, 4 );
  int combined_max = max( pts, 4 );
  int s =  1 + combined_max - combined_min;

  ProbabilityList *pl = create_probability_list();
  pl->offset = combined_min;
  double *pr = alloc_probs_iv( pl, s, 0.0 );
  int i,j;
  for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
    int k = mul_a * (i + pl_a->offset) + mul_b * (j + pl_b->offset) - combined_min;
    pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
  } }
  return pl;
}

static inline double pl_p_eql( ProbabilityList *pl, int target ) {
  int idx = target - pl->offset;
  if ( idx < 0 || idx >= pl->slots ) {
    return 0.0;
  }
  return (pl->probs)[idx];
}

static inline double pl_p_gt( ProbabilityList *pl, int target ) {
  return pl_p_ge( pl, target + 1 );
}

static inline double pl_p_lt( ProbabilityList *pl, int target ) {
  return 1.0 - pl_p_ge( pl, target );
}

static inline double pl_p_le( ProbabilityList *pl, int target ) {
  return 1.0 - pl_p_ge( pl, target + 1 );
}

static inline double pl_p_ge( ProbabilityList *pl, int target ) {
  int idx = target - pl->offset;
  if ( idx <= 0 ) {
    return 1.0;
  }
  if ( idx >= pl->slots ) {
    return 0.0;
  }
  int i;
  double t = 0.0;
  // TODO: Cache all sums?
  for ( i=idx; i< pl->slots; i++ ) {
    t += (pl->probs)[i];
  }
  return t;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Ruby integration
//<commit_msg>Use p_le (not p_ge) as detail cumulative probs calculation, for ease of caching later.<commit_after>// ext/games_dice/probabilities.c

#include <stdio.h>
#include "probabilities.h"

VALUE NewProbabilities = Qnil;

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  General utils
//

static inline int max( int *a, int n ) {
  int m = -1000000000;
  int i;
  for ( i=0; i < n; i++ ) {
    m = a[i] > m ? a[i] : m;
  }
  return m;
}

static inline int min( int *a, int n ) {
  int m = 1000000000;
  int i;
  for ( i=0; i < n; i++ ) {
    m = a[i] < m ? a[i] : m;
  }
  return m;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Probability List basics - create, delete, copy
//

static ProbabilityList *create_probability_list() {
  ProbabilityList *pl;
  pl = malloc (sizeof(ProbabilityList));
  if ( pl == NULL ) {
    rb_raise(rb_eRuntimeError, "Could not allocate memory for NewProbabilities");
  }
  pl->probs = NULL;
  pl->slots = 0;
  pl->offset = 0;
  return pl;
}

static void destroy_probability_list( ProbabilityList *pl ) {
  free( pl->probs );
  free( pl );
  return;
}

static double *alloc_probs( ProbabilityList *pl, int slots ) {
  if ( slots < 1 || slots > 1000000 ) {
    rb_raise(rb_eArgError, "Bad number of probability slots");
  }
  pl->slots = slots;
  // TODO: Should this be a NALLOC?
  double *pr = malloc( slots * sizeof(double));
  if (pr == NULL) {
    rb_raise(rb_eRuntimeError, "Could not allocate memory for NewProbabilities");
  }
  pl->probs = pr;
  return pr;
}

static double *alloc_probs_iv( ProbabilityList *pl, int slots, double iv ) {
  if ( iv < 0.0 || iv > 1.0 ) {
    rb_raise(rb_eArgError, "Bad single probability value");
  }
  double *pr = alloc_probs( pl, slots );
  int i;
  for(i=0; i<slots; i++) {
    pr[i] = iv;
  }
  return pr;
}

static ProbabilityList *copy_probability_list( ProbabilityList *orig ) {
  ProbabilityList *pl = create_probability_list();
  double *pr = alloc_probs( pl, orig->slots );
  pl->offset = orig->offset;
  memcpy( pr, orig->probs, orig->slots * sizeof(double) );
  return pl;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Probability List core "native" methods
//

static inline int pl_min( ProbabilityList *pl ) {
  return pl->offset;
}

static inline int pl_max( ProbabilityList *pl ) {
  return pl->offset + pl->slots - 1;
}

static ProbabilityList *pl_add_distributions( ProbabilityList *pl_a, ProbabilityList *pl_b ) {
  int s = pl_a->slots + pl_b->slots - 1;
  int o = pl_a->offset + pl_b->offset;
  int i,j;

  ProbabilityList *pl = create_probability_list();
  pl->offset = o;
  double *pr = alloc_probs_iv( pl, s, 0.0 );
  for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
    pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
  } }
  return pl;
}

static ProbabilityList *pl_add_distributions_mult( int mul_a, ProbabilityList *pl_a, int mul_b, ProbabilityList *pl_b ) {
  int pts[4] = {
    mul_a * pl_min( pl_a ) + mul_b * pl_min( pl_b ),
    mul_a * pl_max( pl_a ) + mul_b * pl_min( pl_b ),
    mul_a * pl_min( pl_a ) + mul_b * pl_max( pl_b ),
    mul_a * pl_max( pl_a ) + mul_b * pl_max( pl_b ) };

  int combined_min = min( pts, 4 );
  int combined_max = max( pts, 4 );
  int s =  1 + combined_max - combined_min;

  ProbabilityList *pl = create_probability_list();
  pl->offset = combined_min;
  double *pr = alloc_probs_iv( pl, s, 0.0 );
  int i,j;
  for ( i=0; i < pl_a->slots; i++ ) { for ( j=0; j < pl_b->slots; j++ ) {
    int k = mul_a * (i + pl_a->offset) + mul_b * (j + pl_b->offset) - combined_min;
    pr[ i + j ] += (pl_a->probs)[i] * (pl_b->probs)[j];
  } }
  return pl;
}

static inline double pl_p_eql( ProbabilityList *pl, int target ) {
  int idx = target - pl->offset;
  if ( idx < 0 || idx >= pl->slots ) {
    return 0.0;
  }
  return (pl->probs)[idx];
}

static inline double pl_p_gt( ProbabilityList *pl, int target ) {
  return 1.0 - pl_p_le( pl, target );
}

static inline double pl_p_lt( ProbabilityList *pl, int target ) {
  return pl_p_le( pl, target - 1 );
}

static inline double pl_p_le( ProbabilityList *pl, int target ) {
  int idx = target - pl->offset;
  if ( idx < 0 ) {
    return 0.0;
  }
  if ( idx >= pl->slots - 1 ) {
    return 1.0;
  }
  int i;
  double t = 0.0;
  // TODO: Cache all sums?
  for ( i=0; i<= idx; i++ ) {
    t += (pl->probs)[i];
  }
  return t;
}

static inline double pl_p_ge( ProbabilityList *pl, int target ) {
  return 1.0 - pl_p_le( pl, target - 1 );
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Ruby integration
//
{'fraction_non_alphanumeric': 0.22638903643896738, 'fraction_numerical': 0.014448103686391161, 'mean_word_length': 2.19660441426146, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 88, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5912759', 'n_tokens_mistral': 3610, 'n_tokens_neox': 3444, 'n_words': 946}