<commit_before>#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libpq-fe.h>
#include <search.h>

static char *escapeLiteral(PGconn *conn, const char *str, size_t len) {
  // provides compatibility for PostgreSQL versions prior 9.0
  // in future: return PQescapeLiteral(conn, str, len);
  char *res;
  size_t res_len;
  res = malloc(2*len+3);
  if (!res) return NULL;
  res[0] = '\'';
  res_len = PQescapeStringConn(conn, res+1, str, len, NULL);
  res[res_len+1] = '\'';
  res[res_len+2] = 0;
  return res;
}

static void freemem(void *ptr) {
  // to be used for "escapeLiteral" function
  // provides compatibility for PostgreSQL versions prior 9.0
  // in future: PQfreemem(ptr);
  free(ptr);
}

// column numbers when querying "individual_suggestion_ranking" view in function main():
#define COL_MEMBER_ID     0
#define COL_WEIGHT        1
#define COL_PREFERENCE    2
#define COL_SUGGESTION_ID 3

// data structure for a candidate (in this case a suggestion) to the proportional runoff system:
struct candidate {
  char *key;              // identifier of the candidate, which is the "suggestion_id" string
  double score_per_step;  // added score per step
  double score;           // current score of candidate; a score of 1.0 is needed to survive a round
  int seat;               // equals 0 for unseated candidates, or contains rank number
};

// compare two integers stored as strings (invocation like strcmp):
static int compare_id(char *id1, char *id2) {
  int ldiff;
  ldiff = strlen(id1) - strlen(id2);
  if (ldiff) return ldiff;
  else return strcmp(id1, id2);
}

// compare two candidates by their key (invocation like strcmp):
static int compare_candidate(struct candidate *c1, struct candidate *c2) {
  return compare_id(c1->key, c2->key);
}

// candidates are stored as global variables due to the constrained twalk() interface:
static int candidate_count;
static struct candidate *candidates;

// function to be passed to twalk() to store candidates ordered in candidates[] array:
static void register_candidate(char **candidate_key, VISIT visit, int level) {
  if (visit == postorder || visit == leaf) {
    struct candidate *candidate;
    candidate = candidates + (candidate_count++);
    candidate->key   = *candidate_key;
    candidate->seat  = 0;
  }
}

// performs a binary search in candidates[] array to lookup a candidate by its key (which is the suggestion_id):
static struct candidate *candidate_by_key(char *candidate_key) {
  struct candidate *candidate;
  struct candidate compare;
  compare.key = candidate_key;
  candidate = bsearch(&compare, candidates, candidate_count, sizeof(struct candidate), (void *)compare_candidate);
  if (!candidate) {
    fprintf(stderr, "Candidate not found (should not happen).\n");
    abort();
  }
  return candidate;
}

// section of a ballot with equally ranked candidates:
struct ballot_section {
  int count;
  struct candidate **candidates;
};

// ballot of the proportional runoff system:
struct ballot {
  int weight;                         // if weight is greater than 1, then the ballot is counted multiple times
  struct ballot_section sections[4];  // 4 sections, most preferred candidates first
};

// determine candidate, which is assigned the next seat (starting with the worst rank):
static struct candidate *loser(int round_number, struct ballot *ballots, int ballot_count) {
  int i, j, k;    // index variables for loops
  int remaining;  // remaining candidates to be seated
  // reset scores of all candidates:
  for (i=0; i<candidate_count; i++) {
    candidates[i].score = 0.0;
  }
  // calculate remaining candidates to be seated:
  remaining = candidate_count - round_number;
  // repeat following loop, if there is more than one remaining candidate:
  if (remaining > 1) while (1) {
    double scale;  // factor to be later multiplied with score_per_step:
    // reset score_per_step for all candidates:
    for (i=0; i<candidate_count; i++) {
      candidates[i].score_per_step = 0.0;
    }
    // calculate score_per_step for all candidates:
    for (i=0; i<ballot_count; i++) {
      for (j=0; j<4; j++) {
        int matches = 0;
        for (k=0; k<ballots[i].sections[j].count; k++) {
          struct candidate *candidate;
          candidate = ballots[i].sections[j].candidates[k];
          if (candidate->score < 1.0 && !candidate->seat) matches++;
        }
        if (matches) {
          double score_inc;
          score_inc = (double)ballots[i].weight / (double)matches;
          for (k=0; k<ballots[i].sections[j].count; k++) {
            struct candidate *candidate;
            candidate = ballots[i].sections[j].candidates[k];
            if (candidate->score < 1.0 && !candidate->seat) {
              candidate->score_per_step += score_inc;
            }
          }
          break;
        }
      }
    }
    // calculate scale factor:
    scale = (double)0.0;  // 0.0 is used to indicate that there is no value yet
    for (i=0; i<candidate_count; i++) {
      double max_scale;
      if (candidates[i].score_per_step > 0.0) {
        max_scale = (1.0-candidates[i].score) / candidates[i].score_per_step;
        if (scale == 0.0 || max_scale <= scale) {
          scale = max_scale;
        }
      }
    }
    // add scale*score_per_step to each candidates score:
    for (i=0; i<candidate_count; i++) {
      if (candidates[i].score_per_step > 0.0) {
        double max_scale;
        max_scale = (1.0-candidates[i].score) / candidates[i].score_per_step;
        if (max_scale == scale) {
          // score of 1.0 should be reached, so we set score directly to avoid floating point errors:
          candidates[i].score = 1.0;
          remaining--;
        } else {
          candidates[i].score += scale * candidates[i].score_per_step;
          if (candidates[i].score >= 1.0) remaining--;
        }
        // when there is only one candidate remaining, then break loop:
        if (remaining <= 1) break;
      }
    }
  }
  // return remaining candidate:<commit_msg>Fixed bug in while loop of "loser" function of lf_update_suggestion_order.c, that has been introduced in last commit<commit_after>#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libpq-fe.h>
#include <search.h>

static char *escapeLiteral(PGconn *conn, const char *str, size_t len) {
  // provides compatibility for PostgreSQL versions prior 9.0
  // in future: return PQescapeLiteral(conn, str, len);
  char *res;
  size_t res_len;
  res = malloc(2*len+3);
  if (!res) return NULL;
  res[0] = '\'';
  res_len = PQescapeStringConn(conn, res+1, str, len, NULL);
  res[res_len+1] = '\'';
  res[res_len+2] = 0;
  return res;
}

static void freemem(void *ptr) {
  // to be used for "escapeLiteral" function
  // provides compatibility for PostgreSQL versions prior 9.0
  // in future: PQfreemem(ptr);
  free(ptr);
}

// column numbers when querying "individual_suggestion_ranking" view in function main():
#define COL_MEMBER_ID     0
#define COL_WEIGHT        1
#define COL_PREFERENCE    2
#define COL_SUGGESTION_ID 3

// data structure for a candidate (in this case a suggestion) to the proportional runoff system:
struct candidate {
  char *key;              // identifier of the candidate, which is the "suggestion_id" string
  double score_per_step;  // added score per step
  double score;           // current score of candidate; a score of 1.0 is needed to survive a round
  int seat;               // equals 0 for unseated candidates, or contains rank number
};

// compare two integers stored as strings (invocation like strcmp):
static int compare_id(char *id1, char *id2) {
  int ldiff;
  ldiff = strlen(id1) - strlen(id2);
  if (ldiff) return ldiff;
  else return strcmp(id1, id2);
}

// compare two candidates by their key (invocation like strcmp):
static int compare_candidate(struct candidate *c1, struct candidate *c2) {
  return compare_id(c1->key, c2->key);
}

// candidates are stored as global variables due to the constrained twalk() interface:
static int candidate_count;
static struct candidate *candidates;

// function to be passed to twalk() to store candidates ordered in candidates[] array:
static void register_candidate(char **candidate_key, VISIT visit, int level) {
  if (visit == postorder || visit == leaf) {
    struct candidate *candidate;
    candidate = candidates + (candidate_count++);
    candidate->key   = *candidate_key;
    candidate->seat  = 0;
  }
}

// performs a binary search in candidates[] array to lookup a candidate by its key (which is the suggestion_id):
static struct candidate *candidate_by_key(char *candidate_key) {
  struct candidate *candidate;
  struct candidate compare;
  compare.key = candidate_key;
  candidate = bsearch(&compare, candidates, candidate_count, sizeof(struct candidate), (void *)compare_candidate);
  if (!candidate) {
    fprintf(stderr, "Candidate not found (should not happen).\n");
    abort();
  }
  return candidate;
}

// section of a ballot with equally ranked candidates:
struct ballot_section {
  int count;
  struct candidate **candidates;
};

// ballot of the proportional runoff system:
struct ballot {
  int weight;                         // if weight is greater than 1, then the ballot is counted multiple times
  struct ballot_section sections[4];  // 4 sections, most preferred candidates first
};

// determine candidate, which is assigned the next seat (starting with the worst rank):
static struct candidate *loser(int round_number, struct ballot *ballots, int ballot_count) {
  int i, j, k;    // index variables for loops
  int remaining;  // remaining candidates to be seated
  // reset scores of all candidates:
  for (i=0; i<candidate_count; i++) {
    candidates[i].score = 0.0;
  }
  // calculate remaining candidates to be seated:
  remaining = candidate_count - round_number;
  // repeat following loop, as long as there is more than one remaining candidate:
  while (remaining > 1) {
    double scale;  // factor to be later multiplied with score_per_step:
    // reset score_per_step for all candidates:
    for (i=0; i<candidate_count; i++) {
      candidates[i].score_per_step = 0.0;
    }
    // calculate score_per_step for all candidates:
    for (i=0; i<ballot_count; i++) {
      for (j=0; j<4; j++) {
        int matches = 0;
        for (k=0; k<ballots[i].sections[j].count; k++) {
          struct candidate *candidate;
          candidate = ballots[i].sections[j].candidates[k];
          if (candidate->score < 1.0 && !candidate->seat) matches++;
        }
        if (matches) {
          double score_inc;
          score_inc = (double)ballots[i].weight / (double)matches;
          for (k=0; k<ballots[i].sections[j].count; k++) {
            struct candidate *candidate;
            candidate = ballots[i].sections[j].candidates[k];
            if (candidate->score < 1.0 && !candidate->seat) {
              candidate->score_per_step += score_inc;
            }
          }
          break;
        }
      }
    }
    // calculate scale factor:
    scale = (double)0.0;  // 0.0 is used to indicate that there is no value yet
    for (i=0; i<candidate_count; i++) {
      double max_scale;
      if (candidates[i].score_per_step > 0.0) {
        max_scale = (1.0-candidates[i].score) / candidates[i].score_per_step;
        if (scale == 0.0 || max_scale <= scale) {
          scale = max_scale;
        }
      }
    }
    // add scale*score_per_step to each candidates score:
    for (i=0; i<candidate_count; i++) {
      if (candidates[i].score_per_step > 0.0) {
        double max_scale;
        max_scale = (1.0-candidates[i].score) / candidates[i].score_per_step;
        if (max_scale == scale) {
          // score of 1.0 should be reached, so we set score directly to avoid floating point errors:
          candidates[i].score = 1.0;
          remaining--;
        } else {
          candidates[i].score += scale * candidates[i].score_per_step;
          if (candidates[i].score >= 1.0) remaining--;
        }
        // when there is only one candidate remaining, then break inner (and thus outer) loop:
        if (remaining <= 1) break;
      }
    }
  }
  // return remaining candidate:
{'fraction_non_alphanumeric': 0.11247225191153498, 'fraction_numerical': 0.011921400970155389, 'mean_word_length': 2.9442282749675748, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, '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': '4711378', 'n_tokens_mistral': 3788, 'n_tokens_neox': 3688, 'n_words': 1229}