///|
/// Aggregate evaluation metrics for a group of completed rollouts.
pub struct EvaluationReport {
episodes : Int
total_steps : Int
total_reward : Double
mean_reward : Double
best_reward : Double
worst_reward : Double
terminated : Int
truncated : Int
}
///|
pub fn EvaluationReport::episodes(self : EvaluationReport) -> Int {
self.episodes
}
///|
pub fn EvaluationReport::total_steps(self : EvaluationReport) -> Int {
self.total_steps
}
///|
pub fn EvaluationReport::total_reward(self : EvaluationReport) -> Double {
self.total_reward
}
///|
pub fn EvaluationReport::mean_reward(self : EvaluationReport) -> Double {
self.mean_reward
}
///|
pub fn EvaluationReport::best_reward(self : EvaluationReport) -> Double {
self.best_reward
}
///|
pub fn EvaluationReport::worst_reward(self : EvaluationReport) -> Double {
self.worst_reward
}
///|
pub fn EvaluationReport::terminated(self : EvaluationReport) -> Int {
self.terminated
}
///|
pub fn EvaluationReport::truncated(self : EvaluationReport) -> Int {
self.truncated
}
///|
pub fn[S, A] evaluate_episodes(
episodes : Array[Episode[S, A]],
) -> EvaluationReport {
if episodes.length() == 0 {
return {
episodes: 0,
total_steps: 0,
total_reward: 0.0,
mean_reward: 0.0,
best_reward: 0.0,
worst_reward: 0.0,
terminated: 0,
truncated: 0,
}
}
let mut total_steps = 0
let mut total_reward = 0.0
let mut best_reward = episodes[0].total_reward()
let mut worst_reward = episodes[0].total_reward()
let mut terminated = 0
let mut truncated = 0
for episode in episodes {
let reward = episode.total_reward()
total_steps = total_steps + episode.len()
total_reward = total_reward + reward
if reward > best_reward {
best_reward = reward
}
if reward < worst_reward {
worst_reward = reward
}
if episode.is_terminated() {
terminated = terminated + 1
}
if episode.is_truncated() {
truncated = truncated + 1
}
}
{
episodes: episodes.length(),
total_steps,
total_reward,
mean_reward: total_reward / episodes.length().to_double(),
best_reward,
worst_reward,
terminated,
truncated,
}
}
///|
pub fn[S, A] success_rate(
episodes : Array[Episode[S, A]],
reward_threshold : Double,
) -> Double {
if episodes.length() == 0 {
return 0.0
}
let mut successful = 0
for episode in episodes {
if episode.total_reward() >= reward_threshold {
successful = successful + 1
}
}
successful.to_double() / episodes.length().to_double()
}
///|
pub fn[S, A] episode_reward_histogram(
episodes : Array[Episode[S, A]],
lower : Double,
upper : Double,
buckets : Int,
) -> Array[Int] {
let result : Array[Int] = []
if buckets <= 0 {
return result
}
let mut i = 0
while i < buckets {
result.push(0)
i = i + 1
}
if upper <= lower {
return result
}
let width = (upper - lower) / buckets.to_double()
for episode in episodes {
let raw = ((episode.total_reward() - lower) / width).to_int()
let index = if raw < 0 {
0
} else if raw >= buckets {
buckets - 1
} else {
raw
}
result[index] = result[index] + 1
}
result
}
///|
pub fn[S, A] episode_lengths_histogram(
episodes : Array[Episode[S, A]],
buckets : Int,
) -> Array[Int] {
let result : Array[Int] = []
if buckets <= 0 {
return result
}
let mut i = 0
while i < buckets {
result.push(0)
i = i + 1
}
for episode in episodes {
let index = if episode.len() >= buckets {
buckets - 1
} else {
episode.len()
}
result[index] = result[index] + 1
}
result
}