From 183dd95cc773322f2a7723415102f1b276e04a3e Mon Sep 17 00:00:00 2001 From: Helios De Rosario Date: Tue, 7 Jan 2025 19:46:23 +0100 Subject: [PATCH] add `sdft_` prefix to internal API The following names are also slightly changed: backdft > sdft_backindices iterationcount > sdft_iteration updatedft! > sdft_update! --- docs/src/slidingdft.md | 42 +++++++------- src/sdft_implementations.jl | 8 +-- src/sdft_interface.jl | 106 ++++++++++++++++++------------------ 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/docs/src/slidingdft.md b/docs/src/slidingdft.md index 46075fb..f41202b 100644 --- a/docs/src/slidingdft.md +++ b/docs/src/slidingdft.md @@ -67,42 +67,42 @@ The internals of this package take care of the design of the iterator and state Before explaining how to define such a struct, it is convenient to know the functions that can be used to extract the information that is stored in the state of SDFT iterators. There is a function for each one of the three kinds of variables presented in the general recursive equation above. -* [`FourierTools.previousdft`](@ref) for the values of the DFT in previous iterations. -* [`FourierTools.previousdata`](@ref) for the values of the data series used in the most recent iteration. -* [`FourierTools.nextdata`](@ref) for the next value of the data series after the fragment used in the most recent iteration. +* [`FourierTools.sdft_previousdft`](@ref) for the values of the DFT in previous iterations. +* [`FourierTools.sdft_previousdata`](@ref) for the values of the data series used in the most recent iteration. +* [`FourierTools.sdft_nextdata`](@ref) for the next value of the data series after the fragment used in the most recent iteration. For instance, the values used in the formula of the basic SDFT may be obtained from a `state` object as: -* `FourierTools.previousdft(state, 0)` for $X_{i}$. -* `FourierTools.previousdata(state, 0)` for $x[i]$. -* `FourierTools.nextdata(state)` for $x[i+n+1]$. +* `FourierTools.sdft_previousdft(state, 0)` for $X_{i}$. +* `FourierTools.sdft_previousdata(state, 0)` for $x[i]$. +* `FourierTools.sdft_nextdata(state)` for $x[i+n+1]$. -Notice that the second arguments of `previousdft` and `previousdata` might have been ommited in this case, since they are zero by default. +Notice that the second arguments of `sdft_previousdft` and `sdft_previousdata` might have been ommited in this case, since they are zero by default. -For methods that need to know how many steps of the SDFT have been done, this can also be extracted with the function [`FourierTools.iterationcount`](@ref). +For methods that need to know how many steps of the SDFT have been done, this can also be extracted with the function [`FourierTools.sdft_iteration`](@ref). The design of the `struct` representing a new SDFT type is free, but it is required to be a subtype of [`AbstractSDFT`](@ref), and implement the following methods dispatching on that type: -* [`FourierTools.windowlength`](@ref) to return the length of the DFT window. -* [`FourierTools.updatepdf!`](@ref) with the implementation of the recursive equation, extracting the information stored in the state with the functions commented above (`previousdft`, etc.) . +* [`FourierTools.sdft_windowlength`](@ref) to return the length of the DFT window. +* [`FourierTools.sdft_update!`](@ref) with the implementation of the recursive equation, extracting the information stored in the state with the functions commented above (`sdft_previousdft`, etc.) . -Depending on the functions that are used in the particular implementation of `updatepdf!` for a given type, the following methods should be defined too: +Depending on the functions that are used in the particular implementation of `sdft_update!` for a given type, the following methods should be defined too: -* [`FourierTools.dftback`](@ref) if `FourierTools.previousdft` is used. -* [`FourierTools.dataoffsets`](@ref) if `FourierTools.previousdata` is used. +* [`FourierTools.sdft_backindices`](@ref) if `FourierTools.sdft_previousdft` is used. +* [`FourierTools.sdft_dataoffsets`](@ref) if `FourierTools.sdft_previousdata` is used. ### Example The formula of the basic SDFT formula could be implemented for a type `MyBasicSDFT` as follows: ```julia -import FourierTools: updatedft!, windowlength, nextdata, previousdata +import FourierTools: sdft_update!, sdft_windowlength, sdft_nextdata, sdft_previousdata -function udpatedft!(dft, x, method::MyBasicSDFT, state) - n = windowlength(method) +function sdft_udpatedft!(dft, x, method::MyBasicSDFT, state) + n = sdft_windowlength(method) for k in eachindex(dft) X_i = dft[k] - x_iplusn = nextdata(state) - x_i = previousdata(state) + x_iplusn = sdft_nextdata(state) + x_i = sdft_previousdata(state) Wk = exp(2π*im*k/n) dft[k] = Wk * (X_i + x_iplusn - x_i) end @@ -111,13 +111,13 @@ end (The type [`SDFT`](@ref) actually has as a similar, but not identical definition.) -The implementation of `updatepdf!` given in the previous example does use `previousdata` - with the default offset value, equal to zero - so the following is required in this case: +The implementation of `sdft_update!` given in the previous example does use `sdft_previousdata` - with the default offset value, equal to zero - so the following is required in this case: ```julia -FourierTools.dataoffsets(::MyBasicSDFT) = 0 +FourierTools.sdft_dataoffsets(::MyBasicSDFT) = 0 ``` -On the other hand there is no need to define `FourierTools.dftback` in this case, since the interface of of `updatedft!` assumes that the most recent DFT is already contained in its first argument `dft`, so it is not necessary to use the function `previousdft` to get it. +On the other hand there is no need to define `FourierTools.sdft_backindices` in this case, since the interface of of `sdft_update!` assumes that the most recent DFT is already contained in its first argument `dft`, so it is not necessary to use the function `sdft_previousdft` to get it. ### Alternative to subtyping `AbstractSDFT` diff --git a/src/sdft_implementations.jl b/src/sdft_implementations.jl index d126b76..96b722b 100644 --- a/src/sdft_implementations.jl +++ b/src/sdft_implementations.jl @@ -41,14 +41,14 @@ SDFT(n) = SDFT(ComplexF64, n) # Required functions -windowlength(method::SDFT) = method.n +sdft_windowlength(method::SDFT) = method.n -function updatedft!(dft, x, method::SDFT{T,C}, state) where {T,C} +function sdft_update!(dft, x, method::SDFT{T,C}, state) where {T,C} twiddle = one(C) for k in eachindex(dft) - dft[k] = twiddle * (dft[k] + nextdata(state) - previousdata(state)) + dft[k] = twiddle * (dft[k] + sdft_nextdata(state) - sdft_previousdata(state)) twiddle *= method.factor end end -dataoffsets(::SDFT) = 0 +sdft_dataoffsets(::SDFT) = 0 diff --git a/src/sdft_interface.jl b/src/sdft_interface.jl index 40f3499..2ffae3a 100644 --- a/src/sdft_interface.jl +++ b/src/sdft_interface.jl @@ -3,23 +3,23 @@ export AbstractSDFT ## Required functions """ - windowlength(method) + sdft_windowlength(method) Return the length of the window used by `method`. """ -function windowlength end +function sdft_windowlength end """ - updatedft!(dft, x, method, state) + sdft_update!(dft, x, method, state) Update the values of a sliding Discrete Fourier Transform (DFT) of a data series, according to the algorithm of the provided method, for a given state of the sliding DFT. -`dft` is a mutable collection of complex values with length equal to `windowlength(method)`, +`dft` is a mutable collection of complex values with length equal to `sdft_windowlength(method)`, containing the value returned by the last iteration of the sliding DFT. `x` is the data series for which the sliding DFT is computed, at least as long as -`windowlength(method)`. +`sdft_windowlength(method)`. `method` is the object that defines the method to compute the sliding DFT. @@ -30,45 +30,45 @@ of an SDFT iterator made from `method` and `x`, The information that is needed to update the sliding DFT can be extracted from `state` with the following functions: -* [`FourierTools.previousdft`](@ref) to get the DFTs of previous iterations. -* [`FourierTools.previousdata`](@ref) to get a previous value of the data series. -* [`FourierTools.nextdata`](@ref) to get the next value of the data series. +* [`FourierTools.sdft_previousdft`](@ref) to get the DFTs of previous iterations. +* [`FourierTools.sdft_previousdata`](@ref) to get a previous value of the data series. +* [`FourierTools.sdft_nextdata`](@ref) to get the next value of the data series. """ -function updatedft! end +function sdft_update! end ## Conditionally required functions """ - dftback(method) + sdft_backindices(method) Return an integer or a vector of positive integers with the indices of the previous iterations that are needed by the given method to compute a sliding DFT. -If the code of `FourierTools.updatepdf!` for the type of `method` uses the function `FourierTools.previousdft`, +If the code of `FourierTools.updatepdf!` for the type of `method` uses the function `FourierTools.sdft_previousdft`, this function must return the integers that are used as the third argument (`back`) of that function. If that function is not needed, this one may return `nothing` to reduce memory allocations. """ -dftback(::Any) = nothing +sdft_backindices(::Any) = nothing """ - dataoffsets(method) + sdft_dataoffsets(method) Return an integer or a vector of integers with the offsets of data samples that are needed by the given method to compute a sliding DFT. -If the code of `FourierTools.updatepdf!` that dispatches on the type of `method` uses the function `FourierTools.previousdata`, +If the code of `FourierTools.updatepdf!` that dispatches on the type of `method` uses the function `FourierTools.sdft_previousdata`, this function must return the integers that are used as the third argument (`offset`) of that function. If that function is not needed (no past samples are used), this one may return `nothing` to reduce memory allocations. """ -dataoffsets(::Any) = nothing +sdft_dataoffsets(::Any) = nothing ## States -# State data used by `updatedft!` -struct StateData{H, F, N} +# State data used by `sdft_update!` +struct SDFTStateData{H, F, N} dfthistory::H # record of back dfts if needed, otherwise nothing fragment::F # previous data fragment if needed, otherwise nothing nextdatapoint::N # next data point after the fragment @@ -76,13 +76,13 @@ struct StateData{H, F, N} iteration::Int # iteration count end -hasdfthistory(::StateData{Nothing}) = false -hasdfthistory(::StateData) = true -haspreviousdata(::StateData{<:Any, Nothing}) = false -haspreviousdata(::StateData) = true +hasdfthistory(::SDFTStateData{Nothing}) = false +hasdfthistory(::SDFTStateData) = true +haspreviousdata(::SDFTStateData{<:Any, Nothing}) = false +haspreviousdata(::SDFTStateData) = true """ - previousdft(state[, back=0]) + sdft_previousdft(state[, back=0]) Return the DFT computed in the most recent iteration of the sliding DFT represented by `state`, or in a number of previous @@ -92,9 +92,9 @@ If the DFT computed in the most recent iteration corresponds to the fragment of the data series between its positions `i` and `i+n`, then this function returns its DFT for the fragment between `i-back` and `i+n-back`. """ -function previousdft(state::StateData, back=0) +function sdft_previousdft(state::SDFTStateData, back=0) !hasdfthistory(state) && throw(ErrorException( - "previous DFT results not available; the SDFT method has no valid definition of `FourierTools.dftback`" + "previous DFT results not available; the SDFT method has no valid definition of `FourierTools.sdft_backindices`" )) dfthistory = state.dfthistory n = state.windowlength @@ -105,7 +105,7 @@ function previousdft(state::StateData, back=0) end """ - previousdata(state[, offset=0]) + sdft_previousdata(state[, offset=0]) Return the first value of the fragment of the data series that was used in the most recent iteration of the sliding DFT represented by `state`, @@ -115,9 +115,9 @@ If the DFT computed in the most recent iteration corresponds to the fragment of the data series between its positions `i` and `i+n`, then this function returns the `i+offset`-th value. """ -function previousdata(state::StateData, offset=0) +function sdft_previousdata(state::SDFTStateData, offset=0) !haspreviousdata(state) && throw(ErrorException( - "previous data values not available; the SDFT method has no valid definition of `FourierTools.dataoffsets`" + "previous data values not available; the SDFT method has no valid definition of `FourierTools.sdft_dataoffsets`" )) fragment = state.fragment adjustedoffset = rem(offset + state.iteration - 1, length(fragment)) @@ -126,7 +126,7 @@ end """ - nextdata(state) + sdft_nextdata(state) Return the next value after the fragment of the data series that was used in the most recent iteration of the sliding DFT represented by `state`. @@ -138,10 +138,10 @@ then this function returns the `i+n+1`-th value. There is no defined behavior if such value does not exist (i.e. if the end of a finite data series was reached). """ -nextdata(state::StateData) = state.nextdatapoint +sdft_nextdata(state::SDFTStateData) = state.nextdatapoint """ - iterationcount(state) + sdft_iteration(state) Return the number of iterations done for the sliding DFT represented by `state`. @@ -149,7 +149,7 @@ If the DFT computed in the most recent iteration corresponds to the fragment of the data series between its positions `i` and `i+n`, then this function returns the number `i`. """ -iterationcount(state) = state.iteration +sdft_iteration(state) = state.iteration # State of the iterator struct SDFTState{T, H, F, S} @@ -161,7 +161,7 @@ struct SDFTState{T, H, F, S} end # Return the updated state of the iterator, or `nothing` if the data series is consumed. -function updatestate(state::SDFTState, method, x) +function sdft_updatestate(state::SDFTState, method, x) nextiter = iterate(x, state.nextdatastate) if isnothing(nextiter) return nothing @@ -169,18 +169,18 @@ function updatestate(state::SDFTState, method, x) nextdatapoint, nextdatastate = nextiter dfthistory = state.dfthistory fragment = state.fragment - n = windowlength(method) + n = sdft_windowlength(method) # explicit fft of shifted fragment until dfthistory is complete - if !isnothing(dfthistory) && state.iteration <= maximum(dftback(method)) - updatefragment!(fragment, nextdatapoint, state.iteration) + if !isnothing(dfthistory) && state.iteration <= maximum(sdft_backindices(method)) + sdft_updatefragment!(fragment, nextdatapoint, state.iteration) dft = shiftedfft(fragment, state.iteration) else dft = state.dft - statedata = StateData(dfthistory, fragment, nextdatapoint, n, state.iteration) - updatedft!(dft, x, method, statedata) - updatefragment!(fragment, nextdatapoint, state.iteration) + statedata = SDFTStateData(dfthistory, fragment, nextdatapoint, n, state.iteration) + sdft_update!(dft, x, method, statedata) + sdft_updatefragment!(fragment, nextdatapoint, state.iteration) end - updatedfthistory!(dfthistory, dft, n, state.iteration + 1) + sdft_updatedfthistory!(dfthistory, dft, n, state.iteration + 1) return SDFTState(dft, dfthistory, fragment, nextdatastate, state.iteration + 1) end @@ -196,20 +196,20 @@ function shiftedfft(x, delay) return y end -function updatedfthistory!(dfthistory, dft, n, iteration) +function sdft_updatedfthistory!(dfthistory, dft, n, iteration) offset = rem((iteration - 1) * n, length(dfthistory)) dfthistory[(1:n) .+ offset] .= dft end -function updatedfthistory!(::Nothing, args...) end +function sdft_updatedfthistory!(::Nothing, args...) end -function updatefragment!(fragment, nextdatapoint, iteration) +function sdft_updatefragment!(fragment, nextdatapoint, iteration) n = length(fragment) offset = rem(iteration - 1, n) fragment[begin + offset] = nextdatapoint end -function updatefragment!(::Nothing, ::Any, ::Any) end +function sdft_updatefragment!(::Nothing, ::Any, ::Any) end ## Iterator @@ -239,7 +239,7 @@ IteratorSizeWrapper(iteratorsizetrait) = iteratorsizetrait # inherit everything function Base.length(iterator::SDFTIterator) method = getmethod(iterator) data = getdata(iterator) - return length(data) - windowlength(method) + 1 + return length(data) - sdft_windowlength(method) + 1 end Base.eltype(::SDFTIterator{M,T}) where {M,T} = Vector{Complex{eltype(T)}} @@ -248,11 +248,11 @@ Base.isdone(iterator::SDFTIterator) = Base.isdone(getdata(iterator)) Base.isdone(iterator::SDFTIterator, state::SDFTState) = Base.isdone(getdata(iterator), state.nextdatastate) function Base.iterate(itr::SDFTIterator) - windowed_data, datastate = initialize(itr) + windowed_data, datastate = initializesdft(itr) dft = fft(windowed_data) method = getmethod(itr) - backindices = dftback(method) - dfthistory = create_dfthistory(dft, backindices) + backindices = sdft_backindices(method) + dfthistory = create_sdfthistory(dft, backindices) state = SDFTState(dft, dfthistory, windowed_data, datastate, 1) returned_dft = itr.safe ? copy(dft) : dft return returned_dft, state @@ -261,7 +261,7 @@ end function Base.iterate(itr::SDFTIterator, state) method = getmethod(itr) x = getdata(itr) - newstate = updatestate(state, method, x) + newstate = sdft_updatestate(state, method, x) if isnothing(newstate) return nothing end @@ -271,9 +271,9 @@ function Base.iterate(itr::SDFTIterator, state) end # Get the window of the first chunk of data and the state of the data iterator at the end -function initialize(itr) +function initializesdft(itr) x = getdata(itr) - n = windowlength(getmethod(itr)) + n = sdft_windowlength(getmethod(itr)) firstiteration = iterate(x) if isnothing(firstiteration) throw(ErrorException("insufficient data to compute a sliding DFT of window length = $n")) @@ -293,9 +293,9 @@ function initialize(itr) return windowed_data, datastate end -create_dfthistory(::Any, ::Nothing) = nothing -create_dfthistory(dft, n::Integer) = repeat(dft, n+1) -create_dfthistory(dft, indices) = create_dfthistory(dft, maximum(indices)) +create_sdfthistory(::Any, ::Nothing) = nothing +create_sdfthistory(dft, n::Integer) = repeat(dft, n+1) +create_sdfthistory(dft, indices) = create_sdfthistory(dft, maximum(indices)) """ (m::AbstractSDFT)(x[, safe=true])