///|
/// Descriptive statistics for a replay buffer without exposing storage details.
pub struct ReplayReport {
size : Int
capacity : Int
occupancy : Double
terminal_count : Int
total_reward : Double
mean_reward : Double
minimum_reward : Double
maximum_reward : Double
}
///|
pub fn ReplayReport::size(self : ReplayReport) -> Int {
self.size
}
///|
pub fn ReplayReport::capacity(self : ReplayReport) -> Int {
self.capacity
}
///|
pub fn ReplayReport::occupancy(self : ReplayReport) -> Double {
self.occupancy
}
///|
pub fn ReplayReport::terminal_count(self : ReplayReport) -> Int {
self.terminal_count
}
///|
pub fn ReplayReport::total_reward(self : ReplayReport) -> Double {
self.total_reward
}
///|
pub fn ReplayReport::mean_reward(self : ReplayReport) -> Double {
self.mean_reward
}
///|
pub fn ReplayReport::minimum_reward(self : ReplayReport) -> Double {
self.minimum_reward
}
///|
pub fn ReplayReport::maximum_reward(self : ReplayReport) -> Double {
self.maximum_reward
}
///|
pub fn[S, A] ReplayBuffer::report(self : ReplayBuffer[S, A]) -> ReplayReport {
let items = self.to_array()
if items.length() == 0 {
return {
size: 0,
capacity: self.capacity(),
occupancy: 0.0,
terminal_count: 0,
total_reward: 0.0,
mean_reward: 0.0,
minimum_reward: 0.0,
maximum_reward: 0.0,
}
}
let mut total_reward = 0.0
let mut minimum_reward = items[0].reward
let mut maximum_reward = items[0].reward
let mut terminal_count = 0
for item in items {
total_reward = total_reward + item.reward
if item.reward < minimum_reward {
minimum_reward = item.reward
}
if item.reward > maximum_reward {
maximum_reward = item.reward
}
if item.done {
terminal_count = terminal_count + 1
}
}
let occupancy = if self.capacity() == 0 {
0.0
} else {
self.len().to_double() / self.capacity().to_double()
}
{
size: self.len(),
capacity: self.capacity(),
occupancy,
terminal_count,
total_reward,
mean_reward: total_reward / items.length().to_double(),
minimum_reward,
maximum_reward,
}
}
///|
pub fn[S, A] ReplayBuffer::terminal_indices(
self : ReplayBuffer[S, A],
) -> Array[Int] {
let result : Array[Int] = []
let mut i = 0
for item in self.to_array() {
if item.done {
result.push(i)
}
i = i + 1
}
result
}
///|
pub fn[S, A] ReplayBuffer::reward_histogram(
self : ReplayBuffer[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 item in self.to_array() {
let raw = ((item.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] ReplayBuffer::sample_all(
self : ReplayBuffer[S, A],
) -> Array[ReplaySample[S, A]] {
let result : Array[ReplaySample[S, A]] = []
let mut i = 0
while i < self.len() {
match self.get(i) {
Some(transition) => result.push({ index: i, transition })
None => ()
}
i = i + 1
}
result
}
///|
pub fn[S, A] ReplayBuffer::count_reward_at_least(
self : ReplayBuffer[S, A],
threshold : Double,
) -> Int {
let mut count = 0
for item in self.to_array() {
if item.reward >= threshold {
count = count + 1
}
}
count
}
///|
pub fn[S, A] ReplayBuffer::count_reward_below(
self : ReplayBuffer[S, A],
threshold : Double,
) -> Int {
let mut count = 0
for item in self.to_array() {
if item.reward < threshold {
count = count + 1
}
}
count
}
///|
pub fn[S, A] PrioritizedReplayBuffer::effective_priority_sum(
self : PrioritizedReplayBuffer[S, A],
) -> Double {
let mut total = 0.0
let mut i = 0
while i < self.len() {
match self.get(i) {
Some((_, priority)) => total = total + normalize_positive(priority)
None => ()
}
i = i + 1
}
total
}
///|
pub fn[S, A] PrioritizedReplayBuffer::priority_at(
self : PrioritizedReplayBuffer[S, A],
index : Int,
) -> Double? {
match self.get(index) {
Some((_, priority)) => Some(priority)
None => None
}
}
///|
pub fn[S, A] PrioritizedReplayBuffer::priority_distribution(
self : PrioritizedReplayBuffer[S, A],
) -> Array[Double] {
let result : Array[Double] = []
let total = self.priority_sum()
let mut i = 0
while i < self.len() {
match self.get(i) {
Some((_, priority)) =>
result.push(if total == 0.0 { 0.0 } else { priority / total })
None => result.push(0.0)
}
i = i + 1
}
result
}
///|
pub fn[S, A] PrioritizedReplayBuffer::count_priority_at_least(
self : PrioritizedReplayBuffer[S, A],
threshold : Double,
) -> Int {
let mut count = 0
let mut i = 0
while i < self.len() {
match self.priority_at(i) {
Some(priority) => if priority >= threshold { count = count + 1 }
None => ()
}
i = i + 1
}
count
}