/
Util.jl
168 lines (151 loc) · 4.77 KB
/
Util.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
module Util
# -----------------------------------------------------------------------------
#
# Bounded heap
#
# -----------------------------------------------------------------------------
mutable struct BoundedHeap{T, O<:Base.Order.Ordering}
values::Vector{T}
cur_length::Int
max_length::Int
order::O
BoundedHeap{T, O}(max_length::Int, order::O) where {T, O} = new(resize!(T[], max_length+1), 0, max_length, order)
end
BoundedHeap(T::Type, max_length::Int, order::Base.Order.Ordering) = BoundedHeap{T, typeof(order)}(max_length, order)
import DataStructures: percolate_down!, percolate_up!, enqueue!, dequeue!, peek
function enqueue!(x::BoundedHeap{T, O}, v::T) where {T,O}
x.values[x.cur_length+1] = v
if(x.cur_length < x.max_length)
x.cur_length +=1
end
percolate_up!(x.values, x.cur_length, x.order)
end
function dequeue!(x::BoundedHeap{T, O})::T where {T,O}
if x.cur_length < 1
throw(BoundsError())
end
v = x.values[1]
x.values[1] = x.values[x.cur_length]
x.cur_length -= 1
percolate_down!(x.values, 1, x.order, x.cur_length)
end
function peek(x::BoundedHeap{T,O})::T where {T,O}
if x.cur_length < 1
throw(BoundsError())
end
return x.values[1]
end
import Base: length
length(x::BoundedHeap) = x.cur_length
lazymap(f::Function, c) = map(f,c)
lazymap(f::Function, c::C) where C<:Channel = Channel() do ch
for x in c
push!(ch, f(x))
end
end
# -----------------------------------------------------------------------------
#
# make filter! work for priority queues
#
# -----------------------------------------------------------------------------
import Base: delete!
import DataStructures: PriorityQueue
delete!(pq::PriorityQueue{K}, k::K) where K = dequeue!(pq, k)
# -----------------------------------------------------------------------------
#
# One-element iterator
#
# -----------------------------------------------------------------------------
struct SingleItemIter{X}
item::X
end
import Base: length, iterate
length(::SingleItemIter) = 1
iterate(i::SingleItemIter) = (i.item, nothing)
iterate(i::SingleItemIter, ::Nothing) = nothing
include("LinAlgUtil.jl")
# -----------------------------------------------------------------------------
#
# Parallel iteration of two iterators
#
# -----------------------------------------------------------------------------
import Base: iterate
struct ParallelIter{I,J,key,value,≺,l0,r0}
left::I
right::J
end
ParallelIter(key, value, ≺, l0, r0, left, right) = ParallelIter{
typeof(left), typeof(right),
key, value, ≺,
l0, r0,
}(left, right)
struct Start end
struct LeftReady{T,S}
liter::T
rstate::S
end
struct RightReady{T,S}
riter::T
lstate::S
end
struct NextTwo{T,S}
lstate::T
rstate::S
end
# LeftDone could be represented by LeftReady{Nothing}, but Julia's type
# inference seems happier with a slightly flatter type tree. I checked
# that by adding
# return it
# to _materialize!, allowing me to obtain the TermsMap from
# @ring! ℤ[x,y]
# t = x.terms[1].m
# it = @. BigInt(1)*x - BigInt(1)*(t*x);
# and then inspecting
# @code_warntype iterate(it, PolynomialRings.Util.Start())
struct LeftDone{S}
rstate::S
end
struct RightDone{S}
lstate::S
end
function iterate2(i::ParallelIter, state::LeftReady)
riter = iterate(i.right, state.rstate)
state.liter, riter
end
function iterate2(i::ParallelIter, state::LeftDone)
riter = iterate(i.right, state.rstate)
nothing, riter
end
function iterate2(i::ParallelIter, state::RightReady)
liter = iterate(i.left, state.lstate)
liter, state.riter
end
function iterate2(i::ParallelIter, state::RightDone)
liter = iterate(i.left, state.lstate)
liter, nothing
end
function iterate2(i::ParallelIter, state::NextTwo)
iterate(i.left, state.lstate), iterate(i.right, state.rstate)
end
function iterate2(i::ParallelIter, ::Start)
iterate(i.left), iterate(i.right)
end
@inline function iterate(i::ParallelIter{I,J,key,value,≺,l0,r0}, state=Start()) where {I,J,key,value,≺,l0,r0}
liter, riter = iterate2(i, state)
if liter === nothing && riter === nothing
return nothing
elseif liter === nothing
return (key(riter[1]), l0, value(riter[1])), LeftDone(riter[2])
elseif riter === nothing
return (key(liter[1]), value(liter[1]), r0), RightDone(liter[2])
elseif key(riter[1]) ≺ key(liter[1])
return (key(riter[1]), l0, value(riter[1])), LeftReady(liter, riter[2])
elseif key(liter[1]) ≺ key(riter[1])
return (key(liter[1]), value(liter[1]), r0), RightReady(riter, liter[2])
elseif key(liter[1]) == key(riter[1])
return (key(liter[1]), value(liter[1]), value(riter[1])), NextTwo(liter[2], riter[2])
else
@assert(false) # unreachable?
end
end
end