/*************************************************************************/
/* Copyright (c) 2015 Linas Vepstas                                      */
/* All rights reserved                                                   */
/*                                                                       */
/* Use of the link grammar parsing system is subject to the terms of the */
/* license set forth in the LICENSE file included with this software.    */
/* This license allows free redistribution and use in source and binary  */
/* forms, with or without modification, subject to certain conditions.   */
/*                                                                       */
/*************************************************************************/

#ifndef _HISTOGRAM_H_
#define _HISTOGRAM_H_

#include <stdint.h>
#include <inttypes.h>                   // Format of count_t

#define PARSE_NUM_OVERFLOW (1<<24)  // We always assume sizeof(int)>=4

typedef int32_t count_t;
typedef int64_t w_count_t;          // For overflow detection

/*
 * Count Histogramming is currently not required for anything, and the
 * code runs about 6% faster when it is disabled.
 */
#define PERFORM_COUNT_HISTOGRAMMING 0

#if PERFORM_COUNT_HISTOGRAMMING

#define COUNT_FMT PRId64

/**
 * A histogram distribution of the parse counts.
 * The histogram is with respect to the cost of the parse.  Thus, each
 * bin of the histogram contains a count of the number of parses
 * achievable with that cost.  Rather than setting the baseline cost
 * at zero, it is dynamically scaled, so that 'base' is the number of
 * the first bin with a non-zero count in it.  If there are counts that
 * don't fit into the available bins, then they are accumulated into
 * the overrun bin.  It is always the case that
 *     total == sum_i bin[i] + overrun
 */
#define NUM_BINS 12
typedef struct
{
	short base;
	w_count_t total;
	w_count_t bin[NUM_BINS];
	w_count_t overrun;
} Count_bin;

typedef Count_bin w_Count_bin;

Count_bin hist_zero(void);
Count_bin hist_one(void);

void hist_accum(Count_bin* sum, float, const Count_bin*);
void hist_accumv(Count_bin* sum, float, const Count_bin);
void hist_prod(Count_bin* prod, const Count_bin*, const Count_bin*);
void hist_muladd(Count_bin* prod, const Count_bin*, float, const Count_bin*);
void hist_muladdv(Count_bin* prod, const Count_bin*, float, const Count_bin);

static inline w_count_t hist_total(Count_bin* tot) { return tot->total; }
w_count_t hist_cut_total(Count_bin* tot, count_t min_total);

float hist_cost_cutoff(Count_bin*, count_t count);

#else

#define COUNT_FMT PRId32

typedef count_t Count_bin;
typedef w_count_t w_Count_bin;

static inline count_t hist_zero(void) { return 0; }
static inline count_t hist_one(void) { return 1; }

#define hist_accum(sum, cost, a) (*(sum) += *(a))
#define hist_accumv(sum, cost, a) (*(sum) += (a))
#define hist_prod(prod, a, b) (*(prod) = (*a) * (*b))
#define hist_muladd(prod, a, cost, b) (*(prod) += (*a) * (*b))
#define hist_muladdv(prod, a, cost, b) (*(prod) += (*a) * (b))
#define hist_total(tot) (*tot)

#define hist_cut_total(tot, min_total) (*tot)
static inline float hist_cost_cutoff(count_t* tot, count_t count) { return 1.0e38f; }

#endif /* PERFORM_COUNT_HISTOGRAMMING */

#endif /* _HISTOGRAM_H_ */
