Transformation interface
{style="opacity:60%;"} src/base.jl
The transformation interface is the centrepiece of this library. Beside straightforward transform application it also enables stochasticity, composition and buffering.
A transformation is a type that subtypes Transform. The only required function to implement for your transformation type T is
- apply- (tfm::T, item::I; randstate)- Applies the transformation - tfmto item- item. Implemented methods can of course dispatch on the type of- item.- randstateencapsulates the random state needed for stochastic transformations. The- applymethod implementation itself should be deterministic.- You may dispatch on a specific item type - Ior use the abstract- Itemif one implementation works for all item types.
You may additionally also implement:
- DataAugmentation.getrandstate- (tfm)for stochastic transformations- Generates random state to be used inside - apply. Calling- apply(tfm, item)is equivalent to- apply(tfm, item; randstate = getrandstate(tfm)). It defaults to- nothing, so we need not implement it for deterministic transformations.
- apply!- (bufitem, tfm::T, item; randstate)to support buffering- Buffered version of - applythat mutates- bufitem. If not implemented, falls back to regular- apply.
- DataAugmentation.compose- (tfm1, tfm2)for custom composition with other transformations- Composes transformations. By default, returns a - Sequencetransformation that applies the transformations one after the other.
Example
The implementation of the MapElem transformation illustrates this interface well. It transforms any item with array data by mapping a function over the array's elements, just like Base.map.
struct MapElem <: Transform
    f
endThe apply implementation dispatches on DataAugmentation.AbstractArrayItem, an abstract item type for items that wrap arrays. Note that the randstate keyword argument needs to be given even for implementations of deterministic transformations. We also make use of the DataAugmentation.setdata helper to update the item data.
function apply(tfm::MapElem, item::AbstractArrayItem; randstate = nothing)
    a = itemdata(item)
    a_ = map(tfm.f, a)
    return setdata(item, a_)
endThe buffered version applies the function inplace using Base.map!:
function apply!(
        bufitem::I,
        tfm::MapElem,
        item::I;
        randstate = nothing) where I <: AbstractArrayItem
    map!(tfm.f, itemdata(bufitem), itemdata(item))
    return bufitem
endFinally, a MapElem can also be composed nicely with other MapElems. Instead of applying them sequentially, the functions are fused and applied once.
compose(tfm1::MapElem, tfm2::MapElem2) = MapElem(tfm2.f ∘ tfm1.f)