Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/HyperdimensionalComputing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ export AbstractHV,
GradedBipolarHV,
RealHV,
GradedHV,
TernaryHV
TernaryHV,
FHRR

include("representations.jl")

include("operations.jl")
export bundle,
bind,
unbind,
shift!,
shift,
ρ,
Expand Down
39 changes: 32 additions & 7 deletions src/encoding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -493,25 +493,25 @@ end

"""
level(v::HV, n::Int) where {HV <: AbstractHV}
level(HV::Type{<:AbstractHV}, n::Int; dims::Int = 10_000)
level(HV::Type{<:AbstractHV}, m::Int; n::Int = 10_000)

Creates a set of level correlated hypervectors, where the first and last hypervectors are quasi-orthogonal.

# Arguments
- `v::HV`: Base hypervector
- `n::Int`: Number of levels (alternatively, provide a vector to be encoded)
- `m::Int`: Number of levels (alternatively, provide a vector to be encoded)
"""
function level(v::HV, n::Int) where {HV <: AbstractHV}
function level(v::HV, m::Int) where {HV <: AbstractHV}
hvs = [v]
p = 2 / n
while length(hvs) < n
p = 2 / m
while length(hvs) < m
u = last(hvs)
push!(hvs, perturbate(u, p))
end
return hvs
end

level(HV::Type{<:AbstractHV}, n::Int; dims::Int = 10_000) = level(HV(dims), n)
level(HV::Type{<:AbstractHV}, m::Int; n::Int = 10_000) = level(HV(n), m)

level(HVv, vals::AbstractVector) = level(HVv, length(vals))
level(HVv, vals::UnitRange) = level(HVv, length(vals))
Expand Down Expand Up @@ -591,12 +591,37 @@ end

decodelevel(hvlevels::AbstractVector{<:AbstractHV}, a::Number, b::Number) = decodelevel(hvlevels, range(a, b, length(hvlevels)))

decodelevel(HV, numvalues; testbound = false) = decodelevel(level(HV, length(numvalues)), numvalues)
decodelevel(HV, numvalues; testbound = false) = decodelevel(level(HV, length(numvalues)), numvalues; testbound)

"""
convertlevel(hvlevels, numvals..., kwargs...)
convertlevel(HV::AbstractHV, numvals..., kwargs...)

Creates the `encoder` and `decoder` for a level incoding in one step. See `encodelevel`
and `decodelevel` for their respective documentations.
"""
convertlevel(hvlevels, numvals...; kwargs...) = encodelevel(hvlevels, numvals...; kwargs...), decodelevel(hvlevels, numvals..., kwargs...)

convertlevel(hv::AbstractHV, numvals...; kwargs...) = encodelevel(hv, numvals...; kwargs...), decodelevel(hv, numvals..., kwargs...)


# levels using FHRR

function level(v::FHRR, m::Int; β = 1 / m)
return [v^(x * β) for x in 1:m]
end

function level(v::FHRR, vals::Union{AbstractVector{<:Number}, UnitRange}; β = 1 / (maximum(vals) - minimum(vals)))
return [v^(x * β) for x in vals]
end

function encodelevel(v::FHRR, vals = (0, 1); β = 1 / (maximum(vals) - minimum(vals)))
return x -> v^(β * x)
end

function decodelevel(v::FHRR, vals = (0, 1); β = 1 / (maximum(vals) - minimum(vals)))
return u -> @.(real(log(u.v) / log(v.v) / β)) |> mean
end


convertlevel(v::FHRR, vals = (0, 1); kwargs...) = encodelevel(v, vals; kwargs...), decodelevel(v, vals; kwargs...)
1 change: 1 addition & 0 deletions src/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ similarity(u::GradedBipolarHV, v::GradedBipolarHV) = sim_cos(u, v)
similarity(u::RealHV, v::RealHV) = sim_cos(u, v)
similarity(u::BinaryHV, v::BinaryHV) = sim_jacc(u, v)
similarity(u::GradedHV, v::GradedHV) = sim_jacc(u, v)
similarity(u::FHRR, v::FHRR) = real(dot(u.v, v.v)) / length(u)

"""
similarity(u::AbstractVector, v::AbstractVector; method::Symbol)
Expand Down
36 changes: 33 additions & 3 deletions src/operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ end
return r
end

# AGGREGATION
# -----------
# BUNDLE
# ------

# binary and bipolar: use majority
function bundle(hvr::Union{BinaryHV, BipolarHV}, hdvs, r)
Expand Down Expand Up @@ -143,6 +143,14 @@ function bundle(::GradedBipolarHV, hdvs, r)
return GradedBipolarHV(r)
end

function bundle(::FHRR, hdvs, r)
for hv in hdvs
r .+= hv.v
end
r ./= abs.(r)
return FHRR(r)
end

function bundle(hdvs; kwargs...)
hv = first(hdvs)
r = empty_vector(hv)
Expand All @@ -153,17 +161,34 @@ Base.:+(hv1::HV, hv2::HV) where {HV <: AbstractHV} = bundle((hv1, hv2))

# BINDING
# -------

Base.bind(hv1::HV, hv2::HV) where {HV <: AbstractHV} = HV(hv1.v .* hv2.v) # default
Base.bind(hv1::BinaryHV, hv2::BinaryHV) = BinaryHV(hv1.v .⊻ hv2.v)
Base.bind(hv1::BipolarHV, hv2::BipolarHV) = BipolarHV(hv1.v .⊻ hv2.v)
Base.bind(hv1::TernaryHV, hv2::TernaryHV) = TernaryHV(hv1.v .* hv2.v)
Base.bind(hv1::RealHV, hv2::RealHV) = RealHV(hv1.v .* hv2.v)
Base.bind(hv1::GradedHV, hv2::GradedHV) = GradedHV(fuzzy_xor.(hv1.v, hv2.v))
Base.bind(hv1::GradedBipolarHV, hv2::GradedBipolarHV) = GradedBipolarHV(fuzzy_xor_bipol.(hv1.v, hv2.v))
Base.bind(hv1::FHRR, hv2::FHRR) = FHRR(hv1.v .* hv2.v)
Base.:*(hv1::HV, hv2::HV) where {HV <: AbstractHV} = bind(hv1, hv2)
Base.bind(hvs::AbstractVector{HV}) where {HV <: AbstractHV} = prod(hvs)


"""
unbind(hv1::HV, hv2::HV)

Unbinds `hv2` from `hv1`. For many types of hypervectors, the binding operator is
idempotent, i.e., `u * v * v == u`.

Aliases with `\`.
"""
unbind(hv1::HV, hv2::HV) where {HV <: AbstractHV} = bind(hv1, hv2)

unbind(hv1::RealHV, hv2::RealHV) where {HV <: AbstractHV} = RealHV(hv1.v ./ hv2.v)
unbind(hv1::FHRR, hv2::FHRR) where {HV <: AbstractHV} = FHRR(hv1.v ./ hv2.v)

Base.:/(hv1::HV, hv2::HV) where {HV <: AbstractHV} = unbind(hv1, hv2)


# SHIFTING
# --------

Expand Down Expand Up @@ -286,3 +311,8 @@ end
perturbate!(hv, args...) = perturbate!(vectype(hv), hv, args...)

perturbate(hv::AbstractHV, args...; kwargs...) = perturbate!(copy(hv), args...; kwargs...)

# OTHER
# -----

Base.:^(hv::FHRR, x::Number) = FHRR(hv.v .^ x)
27 changes: 24 additions & 3 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ Every hypervector HV has the following basic functionality
TODO:
- [ ] SparseHV
- [ ] support for different types
- [ ] complex HDC
=#

abstract type AbstractHV{T} <: AbstractVector{T} end

#Base.collect(hv::AbstractHV) = hv.v
Base.sum(hv::AbstractHV) = sum(hv.v)
Base.size(hv::AbstractHV) = size(hv.v)
Base.getindex(hv::AbstractHV, i) = hv.v[i]
Expand Down Expand Up @@ -106,7 +104,6 @@ end

RealHV(n::Integer = 10_000, distr::Distribution = eldist(RealHV)) = RealHV(rand(distr, n))


Base.similar(hv::RealHV) = RealHV(length(hv), eldist(RealHV))

function normalize!(hv::RealHV)
Expand Down Expand Up @@ -167,6 +164,30 @@ eldist(::Type{<:GradedBipolarHV}) = 2eldist(GradedHV) - 1
Base.similar(hv::GradedBipolarHV) = GradedBipolarHV(length(hv))
LinearAlgebra.normalize!(hv::GradedBipolarHV) = clamp!(hv.v, -1, 1)

# Fourier Holographically Reduced Represenetations
# ------------------------------------------------

struct FHRR{T <: Complex} <: AbstractHV{T}
v::Vector{T}
end

#Base.eltype(::FHRR{T}) where {T} = Complex{T}

FHRR(n::Int = 10_000) = FHRR(exp.(2π * im .* rand(n)))
FHRR(T::Type, n::Int = 10_000) = FHRR(exp.(2π * im .* rand(T, n)))

Base.similar(hv::FHRR{<:Complex{R}}) where {R} = FHRR(exp.(2π * im .* rand(R, length(hv))))

"""
LinearAlgebra.normalize!(hv::FHRR)

A Fourier Holographically Reduced Represenetation is normalized by
setting the norm of each complex element to 1.
"""
function LinearAlgebra.normalize!(hv::FHRR)
hv.v ./= abs.(hv.v)
return hv
end

# TRAITS
# ------
Expand Down
18 changes: 18 additions & 0 deletions test/encoding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,22 @@
x = decoder(hv)
@test 1 ≤ x ≤ 2
end

@testset "FHRR numbers" begin

v = FHRR()

numvals = 0:0.1:10

encoder, decoder = convertlevel(v, numvals)

x, y, z = 2, 5, 10

hx, hy, hz = encoder.((x, y, z))

@test hx isa FHRR
@test similarity(hx, hy) > similarity(hx, hz)

@test decoder(hx) < decoder(hy) < decoder(hz)
end
end
17 changes: 17 additions & 0 deletions test/operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,21 @@ using LinearAlgebra, Random
end
end
end
@testset "FHRR" begin
hv1 = FHRR(n)
hv2 = FHRR(n)

@test bundle([hv1, hv2]) isa FHRR
@test hv1 + hv2 isa FHRR
@test bind([hv1, hv2]) isa FHRR
@test norm(bind([hv1, hv2])) ≈ sqrt(n)

@test shift(hv1, 2) isa FHRR

@test similarity(hv1, hv2) < 0.5
@test similarity(hv2, hv2) ≈ 1

@test norm(hv1^3) ≈ sqrt(n)
end

end
11 changes: 11 additions & 0 deletions test/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,15 @@ using Distributions, LinearAlgebra
@test norm(hdv) ≈ norm(hdv.v)
normalize!(hdv)
end

@testset "FHRR" begin
hdv = FHRR(n)
@test length(hdv) == n
@test eltype(hdv) <: Complex
@test hdv[2] isa Complex

@test sum(hdv) ≈ sum(hdv.v)
@test norm(hdv) ≈ norm(hdv.v)

end
end