Overwhelmed by broadcast interface. Help me 🄺

You are right! The following looks slightly better to me, but certainly can be improved…

# Vector elements are generators for modular arithmetic

struct PrimeGenerator
    val::BigInt
    mod::BigInt
end

value(x::PrimeGenerator) = x.val
modulus(x::PrimeGenerator) = x.mod

import Base.*
function *(x::PrimeGenerator, y::PrimeGenerator) 
    @assert x.mod == y.mod "Groups must be equal"
    mod = modulus(x)
    val = mod(value(x) * value(y), mod)
    PrimeGenerator(val, mod)
end

import Base.^
^(g::PrimeGenerator, n::Integer) = PrimeGenerator(powermod(value(g), n, modulus(g)), modulus(g))

# Definition of the vector

struct GVector{G, T} <: AbstractVector{G}
    x::Vector{T} 
    g::G
end

GVector(gs::Vector{G}, g::G) where {G} = GVector(value.(gs), g)

Base.IndexStyle(::Type{<:GVector}) = IndexLinear()
Base.setindex!(š ::GVector, val::PrimeGenerator, i::Int) = š .x[i] = value(val)
Base.getindex(š ::GVector, i::Int) = PrimeGenerator(š .x[i], modulus(š .g))
Base.length(g::GVector) = length(g.x)
Base.size(g::GVector) = size(g.x)
Base.similar(g::GVector) = GVector(similar(g.x), g.g)

Base.BroadcastStyle(::Type{<:GVector{G, T}}) where {G, T} = Broadcast.ArrayStyle{GVector{G, T}}() 

function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{GVector{G, T}}}, ::Type{G}) where {G, T}
    GVector(similar(Vector{T}, axes(bc)), find(bc).g)
end

find(bc::Base.Broadcast.Broadcasted) = find(bc.args)
find(args::Tuple) = find(find(args[1]), Base.tail(args))
find(x) = x
find(::Tuple{}) = nothing
find(a::GVector, rest) = a
find(::Any, rest) = find(rest)

a = PrimeGenerator(3, 23)
gv = GVector([a, a^2, a^3], a)
s = similar(gv)
s .= gv .^ 2
1 Like