52constexpr float LN2 = 0.693147180559945309417232121458176568f;
59 float m = -std::numeric_limits<float>::infinity();
60 for (
int i = 0; i < n; ++i) {
62 if (std::isfinite(v) && v > m) m = v;
78 for (
int i = 0; i < n; ++i) {
80 if (std::isfinite(v)) s += std::exp(v - shift);
82 if (s == 0.0f)
return -std::numeric_limits<float>::infinity();
83 return shift + std::log(s);
137 if (!logits || n_vocab == 0) {
138 return std::numeric_limits<float>::infinity();
140 if (picked_id < 0 || picked_id >= n_vocab) {
141 return std::numeric_limits<float>::infinity();
144 const float picked = logits[picked_id];
145 if (!std::isfinite(picked))
return std::numeric_limits<float>::infinity();
148 if (!std::isfinite(m))
return std::numeric_limits<float>::infinity();
151 if (!std::isfinite(log_z))
return std::numeric_limits<float>::infinity();
153 const float surprisal_nats = std::max(0.0f, -(picked - log_z));
185 if (!logits || n_vocab == 0) {
186 return std::numeric_limits<float>::infinity();
190 if (!std::isfinite(m))
return std::numeric_limits<float>::infinity();
193 if (!std::isfinite(log_z))
return std::numeric_limits<float>::infinity();
196 for (
int i = 0; i < n_vocab; ++i) {
197 const float z = logits[i];
198 if (!std::isfinite(z))
continue;
199 const float p = std::exp(z - log_z);
203 const float h_nats = std::max(0.0f, log_z - ez);
227 const float* candidate_logits,
228 const int32_t* candidate_ids,
233 if (!candidate_logits || !candidate_ids || n_candidates == 0) {
234 return std::numeric_limits<float>::infinity();
239 for (
int i = 0; i < n_candidates; ++i) {
240 if (candidate_ids[i] == picked_id) {
245 if (local == -1)
return std::numeric_limits<float>::infinity();
246 if (n_candidates == 1)
return 0.0f;
248 const float picked = candidate_logits[local];
249 if (!std::isfinite(picked))
return std::numeric_limits<float>::infinity();
252 if (!std::isfinite(m))
return std::numeric_limits<float>::infinity();
255 if (!std::isfinite(log_z))
return std::numeric_limits<float>::infinity();
257 const float surprisal_nats = std::max(0.0f, -(picked - log_z));
273 const float* candidate_logits,
277 if (!candidate_logits || n_candidates == 0) {
278 return std::numeric_limits<float>::infinity();
280 if (n_candidates == 1)
return 0.0f;
283 if (!std::isfinite(m))
return std::numeric_limits<float>::infinity();
286 if (!std::isfinite(log_z))
return std::numeric_limits<float>::infinity();
289 for (
int i = 0; i < n_candidates; ++i) {
290 const float z = candidate_logits[i];
291 if (!std::isfinite(z))
continue;
292 const float p = std::exp(z - log_z);
296 const float h_nats = std::max(0.0f, log_z - ez);
float max_finite(const float *a, int n)
Find maximum finite value in array Used for log-sum-exp shift to prevent overflow.
float log_sum_exp(const float *a, int n, float shift)
Numerically stable log-sum-exp Computes log(Σ exp(aᵢ)) using shift trick to avoid overflow.
float sampling_surprisal(const float *candidate_logits, const int32_t *candidate_ids, int n_candidates, int picked_id, Base base=Base::Nats)
Compute sampling-level surprisal for picked token.
float model_entropy(const float *logits, int n_vocab, Base base=Base::Nats)
float sampling_entropy(const float *candidate_logits, int n_candidates, Base base=Base::Nats)
Compute sampling-level entropy of candidate distribution.
float model_surprisal(const float *logits, int n_vocab, int picked_id, Base base=Base::Nats)
Unified model + sampling perplexity tracker.
PerplexityState model
Model-level (raw logits before filters)
PerplexityState sampling
Sampling-level (post top-k/p/temp)
Rolling NLL accumulator for perplexity computation.