Skip to content

Instantly share code, notes, and snippets.

@JeffreySarnoff
Last active November 22, 2022 08:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JeffreySarnoff/849d7352be08645d9b712c3a5272644a to your computer and use it in GitHub Desktop.
Save JeffreySarnoff/849d7352be08645d9b712c3a5272644a to your computer and use it in GitHub Desktop.
examples (b) from the redesign of RollingFunctions.jl
# see example at line 70
# see accumulator enhancement at line 70
using StatsBase
abstract type Accumulator{T} <: Function end
const AccNum = Float64 # client settable via ENV
StatsBase.nobs(acc::Accumulator) = acc.nobs
fn(acc::Accumulator) = acc.fn
#=
incremental accumulation of `minimum`
with optional preprocessing function
=#
mutable struct AccMinimum{T,F} <: Accumulator{T}
nobs::Int
nmin::Int
min::T
const fn::F
end
nmin(acc::AccMinimum) = acc.nmin
function AccMinimum(::Type{T}=AccNum, fn::F=identity) where {T,F}
AccMinimum{T,F}(0, 0, typemax(T), fn)
end
function (acc::AccMinimum{T,F})() where {T,F}
acc.min
end
function (acc::AccMinimum{T,F})(x) where {T,F}
acc.nobs += 1
y = acc.fn(x)
if y < acc.min
acc.nmin += 1
acc.min = y
end
acc
end
function (acc::AccMinimum{T})(xs::A) where {T, A<:AbstractVector{T}}
acc.nobs += length(xs)
ys = map(acc.fn, xs)
y = vminimum(ys)
if y < acc.min
acc.nmin += 1
acc.min = y
end
acc
end
function (acc::AccMinimum{T})(xs::NTuple{N,T}) where {T, N}
acc.nobs += N
ys = map(acc.fn, xs)
y = minimum(ys)
if y < acc.min
acc.nmin += 1
acc.min = y
end
acc
end
#=
the following example shows
minimum at index 1 = 6.0
minimum at index 2 = 6.0
minimum at index 3 = 5.0
minimum at index 4 = -2.0
minimum at index 5 = -5.0
minimum at index 6 = -5.0
minimum at index 7 = -5.0
minimum at index 8 = -8.0
The minimum value is -8.0.
The rolling minimum changed 4 times.
=#
xs = Float32[5, 8, 4, -3, -6, 3, 1, -9]
acc = AccMinimum(eltype(xs), x->x+1)
for i in eachindex(xs)
acc(xs[i])
currentmin = acc()
str = string(" minimum at index ", i, " = ", currentmin)
println(str)
end
result = string("\n The minimum value is ", acc(),".");
changes = string("\n The rolling minimum changed ", nmin(acc)-1," times.");
println(result * changes)
#=
accumulator wrapping without the wrapper
given the preceeding implementation of AccMinimum
that accumulates the minimum value
implement an accumulator of the minimum magnitude
see example at line 120
=#
function AccMinimumMag(::Type{T}=AccNum, fn::F=abs) where {T,F}
AccMinimum{T,F}(0, 0, typemax(T), fn)
end
#=
the following example shows
minimum at index 1 = 5.0
minimum at index 2 = 5.0
minimum at index 3 = 4.0
minimum at index 4 = 3.0
minimum at index 5 = 3.0
minimum at index 6 = 3.0
minimum at index 7 = 1.0
minimum at index 8 = 1.0
The minimum magnitude is 1.0.
The rolling minimum magnitude changed 3 times.
=#
xs = Float32[5, 8, 4, -3, -6, 3, 1, -9]
acc = AccMinimumMag(eltype(xs))
for i in eachindex(xs)
acc(xs[i])
currentmin = acc()
str = string(" minimum at index ", i, " = ", currentmin)
println(str)
end
result = string("\n The minimum magnitude is ", acc(),".");
changes = string("\n The rolling minimum magnitude changed ", nmin(acc)-1," times.");
println(result * changes)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment