Skip to content
Merged
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 Project.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
name = "PatternFolds"
uuid = "c18a7f1d-76ad-4ce4-950d-5419b888513b"
authors = ["Jean-Francois Baffier"]
version = "0.1.6"
version = "0.2.0"

[deps]
Intervals = "d8418881-c3e1-53bb-8760-2df7ec849ed5"
Lazy = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0"

[compat]
Intervals = "1"
Lazy = "0.15"
julia = "1.7"

Expand Down
16 changes: 5 additions & 11 deletions src/PatternFolds.jl
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
module PatternFolds

# usings
using Intervals
using Lazy

# imports
import Intervals: Unbounded

# exports
export Interval
export IntervalsFold
export IVectorFold
export VectorFold

export a_isless
export a_ismore
export b_isless
export b_ismore
export check_pattern
export closed
export fold
export folds
export gap
export is_point
export is_points
export length
export length # TODO: rename span
export make_vector_fold
export opened
export pattern
export unfold
export value

# includes
include("intervals.jl")
Expand Down
7 changes: 1 addition & 6 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Finally one can redefine PatternFold{T}
PatternFold{T} = Union{AbstractVectorFold{T}, IntervalsFold{T}, MyFold{T[,P]}}
```
"""
PatternFold{T} = Union{AbstractVectorFold{T}, IntervalsFold{T}}
PatternFold = Union{AbstractVectorFold, IntervalsFold}

"""
pattern(<:PatternFold)
Expand Down Expand Up @@ -56,11 +56,6 @@ Return the length of `pf` if unfolded.
Base.length(pf::PatternFold) = pattern_length(pf) * folds(pf)
Base.size(pf::PatternFold) = (length(pf),)

"""
eltype(pf<: PatternFolds)
"""
Base.eltype(::Type{<:PatternFold{T}}) where {T} = T

"""
rand(pf<:PatternFold)
Returns a random value of `pf` as if it was unfolded.
Expand Down
136 changes: 56 additions & 80 deletions src/intervals.jl
Original file line number Diff line number Diff line change
@@ -1,103 +1,68 @@
struct Interval{T <: Real}
a::Tuple{T, Bool}
b::Tuple{T, Bool}
# _maxfloat(::Type{T}) where {T<:AbstractFloat} = prevfloat(typemax(T))
# _minfloat(::Type{T}) where {T<:AbstractFloat} = nextfloat(typemin(T))

function Interval{T}(a, b) where {T <: Real}
bounds = (a[1] < b[1] ? (a, b) : (b, a))
return new{T}(bounds[1], bounds[2])
end
end
Interval(a, b) = Interval{typeof(a[1])}(a,b)

a(i) = i.a
b(i) = i.b
Base.:+(bound::Tuple{T, Bool}, gap::T) where T = bound[1]+gap, bound[2]
Base.:+(i::Interval, gap) = Interval(a(i) + gap, b(i) + gap)

value(i, ::Val{:a}) = i.a[1]
value(i, ::Val{:b}) = i.b[1]
value(i, bound) = value(i, Val(bound))

closed(i, ::Val{:a}) = i.a[2]
closed(i, ::Val{:b}) = i.b[2]
closed(i, bound) = closed(i, Val(bound))
opened(i, bound) = !closed(i, bound)

function a_isless(i₁, i₂)
a₁ = value(i₁, :a)
a₂ = value(i₂, :a)
return a₁ == a₂ ? closed(i₁, :a) || opened(i₂, :a) : a₁ < a₂
end

a_ismore(i₁, i₂) = a_isless(i₂, i₁)

function b_ismore(i₁, i₂)
b₁ = value(i₁, :b)
b₂ = value(i₂, :b)
return b₁ == b₂ ? closed(i₁, :b) || opened(i₂, :b) : b₁ > b₂
end

b_isless(i₁, i₂) = b_ismore(i₂, i₁)

b_eq_a(i₁, i₂) = b(i₁) == a(i₂)
Base.ndims(::Interval) = 1

function Base.in(val, i::Interval)
(x, y) = (value(i, :a), value(i, :b))
lesser = closed(i, :a) ? x ≤ val : x < val
greater = closed(i, :b) ? y ≥ val : y > val
return lesser && greater
function Base.rand(i::Interval{T,L,R}) where {T,L,R}
# α = max(_minfloat(T), first(i))
# β = min(_maxfloat(T), last(i))
μ = maxintfloat(T, Int)
α = max(-μ, first(i))
β = min(μ, last(i))
δ = β - α
# if δ === Inf
if δ > μ
return rand(rand() < 0.5 ? α..zero(T) : zero(T)..β)
else
# r = α + exp10(log10(δ) * rand())
r = α + δ * rand()
r ∉ i && return rand(i)
return r
end
end

Base.length(i::Interval) = 1
Base.size(i::Interval) = value(i, :b) - value(i, :a)
Base.isempty(i::Interval) = size(i) == 0 && (opened(i, :a) || opened(i, :b))
Base.ndims(::Interval) = 1
Base.rand(i::Interval) = rand() * size(i) + value(i, :a)

"""
is_point(i::Interval)
Check if the interval `i` is simple point.
"""
is_point(i) = value(i, :a) == value(i, :b) && !isempty(i)

# function Base.intersect(i₁::Interval, i₂::Interval)
# !a_isless(i₁, i₂) && return intersect(i₂, i₁)
# b_ismore(i₁, i₂) && return i₂
# value(i₁, :b) ∈ i₂
# end

mutable struct IntervalsFold{T <: Real} #<: PatternFold{T, Interval{T}}
pattern::Interval{T}
mutable struct IntervalsFold{T<:AbstractFloat,L<:Intervals.Bound,R<:Intervals.Bound}
pattern::Interval{T,L,R}
gap::T
folds::Int
current::Int
end

IntervalsFold(p, g, f, c = 1) = IntervalsFold(p, g, f, c)
IntervalsFold(p, g, f, c=1) = IntervalsFold(p, g, f, c)

@forward IntervalsFold.pattern Base.isempty, Base.ndims

Base.lastindex(isf::IntervalsFold) = folds(isf)

@forward IntervalsFold.pattern a, b, Base.isempty
Base.getindex(isf::IntervalsFold, key...) = map(k -> get_fold!(isf, k), key)

function pattern(isf::IntervalsFold)
distortion = gap(isf) * (isf.current - 1)
return isf.pattern + (-distortion)
end

function unfold(isf::IntervalsFold)
function unfold(isf::IntervalsFold{T,L,R}) where {T,L,R}
reset_pattern!(isf)
x, y = a(isf), b(isf)
x = first(pattern(isf))
y = last(pattern(isf))
g = gap(isf)
f = folds(isf)
return map(i -> Interval(x + g * i, y + g * i), 0:(f - 1))
return [Interval{T,L,R}(x + g * i, y + g * i) for i in 0:(f - 1)]
end

function set_fold!(isf::IntervalsFold, new_fold = isf.current + 1)
function set_fold!(isf::IntervalsFold, new_fold=isf.current + 1)
if new_fold != isf.current && 0 < new_fold ≤ isf.folds
distortion = gap(isf) * (new_fold - isf.current)
isf.pattern += distortion
isf.current = new_fold
end
end

function get_fold!(isf::IntervalsFold, f)
set_fold!(isf, f)
return isf.pattern
end

function Base.iterate(iter::IntervalsFold)
reset_pattern!(iter)
return pattern(iter), 1
Expand All @@ -107,26 +72,37 @@ end
function Base.iterate(iter::IntervalsFold, state::Int)
state ≥ folds(iter) && return nothing
set_fold!(iter)
return iter.pattern, state + 1
return iter.pattern, state + 1
end

# Reverse iterate method
function Base.iterate(r_iter::Base.Iterators.Reverse{IntervalsFold{T}},
state::Int = length(r_iter.itr)) where {T}
state < 1 && return nothing
iter = r_iter.itr
function Base.iterate(
r_iter::Base.Iterators.Reverse{<:IntervalsFold}, state::Int=length(r_iter.itr)
)
state < 1 && return nothing
iter = r_iter.itr
next_state = state - 1
set_fold!(iter, state)
return iter.pattern, next_state
return iter.pattern, next_state
end

function Base.in(val, isf::IntervalsFold)
reset_pattern!(isf)
return any(i -> val ∈ i, isf)
end

Base.size(isf::IntervalsFold) = size(isf.pattern) * folds(isf)
Base.size(isf::IntervalsFold) = span(isf.pattern) * folds(isf)

Base.eltype(::Type{<:IntervalsFold{T}}) where {T} = Interval{T}
Base.length(isf::IntervalsFold) = folds(isf)

Base.eltype(::Type{<:IntervalsFold{T,L,R}}) where {T,L,R} = Interval{T,L,R}

is_points(isf) = is_point(pattern(isf))

pattern_length(isf::IntervalsFold) = span(pattern(isf))

function Base.rand(isf::IntervalsFold)
i = rand(1:folds(isf)) - 1
p = pattern(isf)
return rand(p) + i * gap(isf)
end
Loading