From d3ca8f51eb3a0a9e5953589dd8af0ef1154d406e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 13 Mar 2022 07:14:58 +0700 Subject: [PATCH 01/91] Create Segment_tree.jl --- src/Segment_tree.jl | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/Segment_tree.jl diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl new file mode 100644 index 000000000..e69de29bb From c31a7d9f291c897f5700942b12dfe4012992f86d Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 13 Mar 2022 07:20:07 +0700 Subject: [PATCH 02/91] Create test_segment_tree.jl --- test/test_segment_tree.jl | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/test_segment_tree.jl diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl new file mode 100644 index 000000000..e69de29bb From 43f672d76c0c71a07db9f8777eca1c93864e1dea Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 13 Mar 2022 13:01:16 +0700 Subject: [PATCH 03/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index e69de29bb..d41e1d839 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -0,0 +1,13 @@ +@testset "segment_tree" begin + @testset "Add" begin + X1 = segment_tree(100,Base.+) + + + end + + + @testset "Large_randomized_trial" begin + + end + +end \ No newline at end of file From 1f995006d9d935ea3413e5a02777246e9dd58fcb Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 13 Mar 2022 13:14:48 +0700 Subject: [PATCH 04/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index d41e1d839..6a6bbb7fe 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -1,8 +1,15 @@ @testset "segment_tree" begin @testset "Add" begin - X1 = segment_tree(100,Base.+) - - + X1 = segment_tree(100,Base.:+) + a = zeros(Int64, 100) + change_range!(X1, 3,37,53) + change_range!(X1, 9,23,45) + change_range!(X1, 5,2,21) + a[37:53] .= 3 + a[23:45] .= 9 + a[2:21] .= 5 + @test sum(a[23:99]) == get_range(X1, 23,99) + end From 4ca9a3b54e32e17aaace58f72e4b02ac0b927d96 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 13 Mar 2022 13:19:18 +0700 Subject: [PATCH 05/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 6a6bbb7fe..1ce4c2f43 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -9,7 +9,7 @@ a[23:45] .= 9 a[2:21] .= 5 @test sum(a[23:99]) == get_range(X1, 23,99) - + @test sum(a[55:87]) == get_range(X1, 55,87) end From b2fce0f37433ea98dadf5bd93cd168f9061982f1 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 13 Mar 2022 13:19:27 +0700 Subject: [PATCH 06/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 1ce4c2f43..52b3c2b0b 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -10,6 +10,8 @@ a[2:21] .= 5 @test sum(a[23:99]) == get_range(X1, 23,99) @test sum(a[55:87]) == get_range(X1, 55,87) + @test sum(a[2:3]) == get_range(X1, 2, 3) + @test sum(a[5:77]) == get_range(X1, 5,77) end From 220c695d30d2a0de103e8149f3bc3e35282fe346 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 14 Mar 2022 21:22:56 +0700 Subject: [PATCH 07/91] More code --- src/Segment_tree.jl | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index e69de29bb..04a42c38c 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -0,0 +1,57 @@ +abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end +abstract type Abstractsegmenttree{node_type} end + +#= +Segment trees have the following traits. +1) can_add_range: either Val{True} or Val{False}. +2) can_change_range: either Val{True} or Val{False}. +3) is_functional: either Val{True} or Val{False} + +Dispatching will have "valid". Dispatching for invalid would be error. +=# +can_add_range(::Abstractsegmenttree)= false; +can_change_range(::Abstractsegmenttree) = true; +is_functional(::Abstractsegmenttree) = false; + + +function repeat_op(base,time::Integer, op::Function) + #Hopefully segment tree not larger than 64. Otherwise, big number segment tree may be needed. + Iterations = convert(UInt,time) + #Find trailing zeros. + baseline = base + for i in 1:trailing_zeros(Iterations) + baseline = op(baseline,baseline) + end + Iterations = Iterations>>trailing_zeros(Iterations) + + #Operate to get to the baseline. + #baseline = #Working in progress. + + #Then, you can iterate. + final_value = baseline + while (Iterations!=0) + Iterations>>=1 + baseline = op(baseline,baseline) + if isodd(Iterations) + final_value = op(final_value,baseline) + end + end + #Something + + + return final_value +end + + + +mutable struct Segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} + size::UInt64 + head::node_type +end + +struct functional_segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} + size::UInt64 + head::node_type +end + +mutable struct Segment_tree_node{Dtype, Op, iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} \ No newline at end of file From 71e5c7a67fed985f23c8896e489240bff036ec98 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 14 Mar 2022 21:48:15 +0700 Subject: [PATCH 08/91] Laying foundations Slowly adding code. --- src/Segment_tree.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 04a42c38c..656cec214 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -54,4 +54,9 @@ struct functional_segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegm head::node_type end -mutable struct Segment_tree_node{Dtype, Op, iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} \ No newline at end of file +mutable struct Segment_tree_node{Dtype, Op, iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} + child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op}},Nothing} + #Either both children are valid or none is valid. + value::Dtype + density::Dtype +end \ No newline at end of file From 2711be5611e590cc9d9ce4394079d866d76a303c Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 29 Mar 2022 19:54:40 +0700 Subject: [PATCH 09/91] Update Segment_tree.jl --- src/Segment_tree.jl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 656cec214..27b35af7f 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -47,16 +47,27 @@ end mutable struct Segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} size::UInt64 head::node_type + +end +function Segment_tree(size::Number,Dtype::Type,op::Function, iterated_op::Function) + newsize = convert(UInt64,size) + node_type = Segment_tree_node{Dtype,op,iterated_op} + return Segment_tree{node_type}(newsize, node_type) end +Segment_tree(size::Number,::Type{T}, ::typeof(+)) where {T<:Real} = Segment_tree(size,T,+,*) + struct functional_segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} size::UInt64 head::node_type end +is_functional(functional_segment_tree) = true + mutable struct Segment_tree_node{Dtype, Op, iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op}},Nothing} #Either both children are valid or none is valid. value::Dtype density::Dtype -end \ No newline at end of file +end + From 0f4ddd90f6b780c736f5c795ffd165ff4427a312 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 29 Mar 2022 20:55:12 +0700 Subject: [PATCH 10/91] Update Segment_tree.jl --- src/Segment_tree.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 27b35af7f..8b5583fc3 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -54,8 +54,14 @@ function Segment_tree(size::Number,Dtype::Type,op::Function, iterated_op::Functi node_type = Segment_tree_node{Dtype,op,iterated_op} return Segment_tree{node_type}(newsize, node_type) end -Segment_tree(size::Number,::Type{T}, ::typeof(+)) where {T<:Real} = Segment_tree(size,T,+,*) +Addition_supported = Union{Real, Complex} + +Segment_tree(size::Number, T::Type, op::Function) = Segment_tree(size, T, op, (x,y)->repeat_op(x,y,op)) +Segment_tree(size::Number,::Type{T}, ::typeof(+)) where {T<:Addition_supported} = Segment_tree(size,T,+,*) +Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(+)) where {T<:Addition_supported,N} = Segment_tree(size,Array{T,N},+,*) +Segment_tree(size::Number,::Type{T}, ::typeof(*)) where {T<:Addition_supported} = Segment_tree(size,T,*,^) +Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(*)) where {T<:Addition_supported,N} = Segment_tree(size,Array{T,N},*,^) struct functional_segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} size::UInt64 From b0599e59e2dfa23a356101635a4e97e97642420e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 29 Mar 2022 21:51:43 +0700 Subject: [PATCH 11/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 52b3c2b0b..ae5d9588a 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -1,7 +1,7 @@ @testset "segment_tree" begin @testset "Add" begin - X1 = segment_tree(100,Base.:+) - a = zeros(Int64, 100) + X1 = segment_tree(100,UInt64,Base.:+) + a = zeros(UInt64, 100) change_range!(X1, 3,37,53) change_range!(X1, 9,23,45) change_range!(X1, 5,2,21) @@ -14,9 +14,19 @@ @test sum(a[5:77]) == get_range(X1, 5,77) end - @testset "Large_randomized_trial" begin - + X1 = segment_tree(10000,UInt64, Base.:+) + X2 = zeros(UInt64, 10000) + for i in 1:10000 + a = rand(1:10000) + b = rand(a:10000) + c = rand(UInt64) + change_range!(X1,c,a,b) + X2[a:b] = c + d = rand(1:10000) + e = rand(d:10000) + @test sum(X2[d:e]) == get_range(X1,d,e) + end end end \ No newline at end of file From b84afae36a765c0d136586474d7aae9d0761a6fa Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 30 Mar 2022 20:47:34 +0700 Subject: [PATCH 12/91] Update Segment_tree.jl --- src/Segment_tree.jl | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 8b5583fc3..86ad9e327 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -52,7 +52,7 @@ end function Segment_tree(size::Number,Dtype::Type,op::Function, iterated_op::Function) newsize = convert(UInt64,size) node_type = Segment_tree_node{Dtype,op,iterated_op} - return Segment_tree{node_type}(newsize, node_type) + return Segment_tree{node_type}(newsize, node_type()) end Addition_supported = Union{Real, Complex} @@ -70,10 +70,30 @@ end is_functional(functional_segment_tree) = true -mutable struct Segment_tree_node{Dtype, Op, iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} +mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op}},Nothing} #Either both children are valid or none is valid. value::Dtype density::Dtype + function Segment_tree_node() + return new(nothing) + end end +mutable struct Segment_tree_node_without_identity{Dtype,Op,iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} + child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op}},Nothing} + #Either both children are valid or none is valid. + #This variant will throw an error instead of returning an identity. + #This is not very recommended, as complexity is required to bypass this. + value::Union{Dtype,Nothing} + density::Union{Dtype,Nothing} + function Segment_tree_node_without_identity() + return new(nothing) + end +end + + + +function Segment_tree_node() + +end \ No newline at end of file From d4cd0760757e120665feb07289588d5bc2bc924e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Apr 2022 10:46:53 +0700 Subject: [PATCH 13/91] Finishing lots of things. It takes a lot to set up the projects for this. --- src/Segment_tree.jl | 99 ++++++++++++++++++++++++++++++++++----- test/test_segment_tree.jl | 76 ++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 12 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 86ad9e327..9e807fbd4 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -1,6 +1,14 @@ +#= +Author: Alice Roselia. +It should be made available as part of the (MIT-licensed) Datastructures.jl package. +Feel free to use or extend this code. +=# + + + abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end abstract type Abstractsegmenttree{node_type} end - +Standard_Field = Union{Real, Complex} #= Segment trees have the following traits. 1) can_add_range: either Val{True} or Val{False}. @@ -12,6 +20,10 @@ Dispatching will have "valid". Dispatching for invalid would be error. can_add_range(::Abstractsegmenttree)= false; can_change_range(::Abstractsegmenttree) = true; is_functional(::Abstractsegmenttree) = false; +#Convenience so you don't have to use arguments every time. +get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype +get_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op +get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op function repeat_op(base,time::Integer, op::Function) @@ -47,7 +59,6 @@ end mutable struct Segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} size::UInt64 head::node_type - end function Segment_tree(size::Number,Dtype::Type,op::Function, iterated_op::Function) newsize = convert(UInt64,size) @@ -55,13 +66,13 @@ function Segment_tree(size::Number,Dtype::Type,op::Function, iterated_op::Functi return Segment_tree{node_type}(newsize, node_type()) end -Addition_supported = Union{Real, Complex} - +sizeof(X::Abstractsegmenttree) = X.size +get_head(X::Abstractsegmenttree) = X.head Segment_tree(size::Number, T::Type, op::Function) = Segment_tree(size, T, op, (x,y)->repeat_op(x,y,op)) -Segment_tree(size::Number,::Type{T}, ::typeof(+)) where {T<:Addition_supported} = Segment_tree(size,T,+,*) -Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(+)) where {T<:Addition_supported,N} = Segment_tree(size,Array{T,N},+,*) -Segment_tree(size::Number,::Type{T}, ::typeof(*)) where {T<:Addition_supported} = Segment_tree(size,T,*,^) -Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(*)) where {T<:Addition_supported,N} = Segment_tree(size,Array{T,N},*,^) +Segment_tree(size::Number,::Type{T}, ::typeof(+)) where {T<:Standard_Field} = Segment_tree(size,T,+,*) +Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(+)) where {T<:Standard_Field,N} = Segment_tree(size,Array{T,N},+,*) +Segment_tree(size::Number,::Type{T}, ::typeof(*)) where {T<:Standard_Field} = Segment_tree(size,T,*,^) +Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(*)) where {T<:Standard_Field,N} = Segment_tree(size,Array{T,N},*,^) struct functional_segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} size::UInt64 @@ -71,17 +82,18 @@ is_functional(functional_segment_tree) = true mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} - child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op}},Nothing} + child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op, identity}},Nothing} #Either both children are valid or none is valid. value::Dtype density::Dtype + #Implicitly have information about where it represents. function Segment_tree_node() return new(nothing) end end mutable struct Segment_tree_node_without_identity{Dtype,Op,iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} - child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op}},Nothing} + child_nodes::Union{NTuple{2,Segment_tree_node_without_identity{Dtype, Op, iterated_op}},Nothing} #Either both children are valid or none is valid. #This variant will throw an error instead of returning an identity. #This is not very recommended, as complexity is required to bypass this. @@ -94,6 +106,69 @@ end -function Segment_tree_node() +function Segment_tree_node(Dtype::Type{T}, Op::Function, iterated_op::Function, identity::T) + return Segment_tree_node{Dtype,Op,iterated_op,identity}() +end + +get_identity(X,op::Function) = get_identity(typeof(X),op) +get_identity(::Type,::Function) = nothing +get_identity(::Type{X},typeof(+)) where {X<:Standard_Field} = zero(X) +get_identity(::Type{X},typeof(*)) where {X<:Standard_Field} = one(X) +function Segment_tree_node(Dtype::Type, Op::Function, iterated_op::Function) + if get_identity(Dtype,Op) isa Nothing + return Segment_tree_node_without_identity{Dtype,Op,iterated_op}() + else + return Segment_tree_node{Dtype,Op,iterated_op,get_identity(Dtype,Op)}() + end +end + +Standard_Segment_tree_node = Union{Segment_tree_node,Segment_tree_node_without_identity} #Standard meaning not every Segment_tree_node has this. + +get_left_child(X::Standard_Segment_tree_node) = X.child_nodes[1] +get_right_child(X::Standard_Segment_tree_node) = X.child_nodes[2] + + + +function get_range(X::Abstractsegmenttree, low, high) + # get the reduce(Op, X[i] for all low<=i<=high) + return get_range(get_head(X),low,high, 1, sizeof(X)) +end + + + + +#Implement get_op, get_iterated_op, etc... + +function get_range(X::Standard_Segment_tree_node, Query_low, Query_high, Current_low, Current_high) -end \ No newline at end of file + #while the tree is still not at splitting point + #if on low + #Go down low path. + #else + #Go down high path. + #end + #end + #Split into two functions, ones where you only care about prefix, and the other where you only care about suffix. + while true + Current_mid = div(low+high,2) + if Query_high <= Current_mid + Current_high = Current_mid + X = get_left_child(X) + else if Query_low > Current_mid + Current_low = Current_mid + X = get_right_child(X) + else + return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low),get_right_range(get_right_child(X,Query_high, Current_high))) + #Working in progress. + end + + end +end + +function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low) + +end + +function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_high) + +end diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index ae5d9588a..32462db1a 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -1,3 +1,42 @@ +#= +Author: Alice Roselia. +It should be made available as part of the (MIT-licensed) Datastructures.jl package. +Feel free to use or extend this code. +=# + + + + + + + +#= +Putting my Quarternion to test. + +Quarternion also has associative property, so it should work. + +This is NOT a complete Quarternion implementation. It is only used here for testing purpose. +This code belongs to me (it's my early julia codes) but you could've written this code too. +Just a literal implementation of Quarternion based on its definition, no optimization or other methods. +=# + + + +struct Quarternion{T<:Real} + real::T + i::T + j::T + k::T +end + +#Base.:+(a::Quarternion, b::Quarternion) = Quarternion(a.real+b.real, a.i+b.i, a.j+b.j, a.k+b.k) Not used in the test. +Base.:*(a::Quarternion, b::Quarternion) = +Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, + a.real*b.i + b.real*a.i + a.j*b.k - a.k*b.j, + a.real*b.j + b.real*a.j + a.k*b.i - a.i*b.k, + a.real*b.k + b.real*a.k + a.i*b.j - a.j*b.i, +) + @testset "segment_tree" begin @testset "Add" begin X1 = segment_tree(100,UInt64,Base.:+) @@ -15,6 +54,8 @@ end @testset "Large_randomized_trial" begin + + #Don't worry about the overflow. This is unsigned integer. X1 = segment_tree(10000,UInt64, Base.:+) X2 = zeros(UInt64, 10000) for i in 1:10000 @@ -29,4 +70,39 @@ end end + @testset "Xor_trial" begin + X1 = segment_tree(10000,UInt64, xor) + X2 = zeros(UInt64, 10000) + for i in 1:10000 + a = rand(1:10000) + b = rand(a:10000) + c = rand(UInt64) + change_range!(X1,c,a,b) + X2[a:b] = c + d = rand(1:10000) + e = rand(d:10000) + @test reduce(xor,X2[d:e]) == get_range(X1,d,e) + end + end + + @testset "3x3_matrix_multiplication" begin + #Float/etc should work fine as well. Just don't want to deal with precision issues. + X1 = segment_tree(1000,Array{UInt64,2},*) + identity_matrix = zeros(UInt64,(3,3)) + identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 + #Vector of vector may not be the most efficient, but it should work without problem. + X2 = [identity_matrix for i in 1:1000] + #Viewing without copying should be fine, as we won't mutate the arrays. + #Static arrays recommended for serious uses of this. + for i in 1:1000 + a = rand(1:1000) + b = rand(a:1000) + c = rand(UInt64,(3,3)) + change_range!(X1,c,a,b) + X2[a:b] = c + d = rand(1:1000) + e = rand(d:1000) + @test reduce(*,X2[d:e]) == get_range(X1,d,e) + end + end end \ No newline at end of file From b927996d46e899f1a8efb996f655186f6ec51902 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Apr 2022 10:51:47 +0700 Subject: [PATCH 14/91] Update Segment_tree.jl --- src/Segment_tree.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 9e807fbd4..77ca457b1 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -123,6 +123,7 @@ function Segment_tree_node(Dtype::Type, Op::Function, iterated_op::Function) end Standard_Segment_tree_node = Union{Segment_tree_node,Segment_tree_node_without_identity} #Standard meaning not every Segment_tree_node has this. +#TODO: consider refactoring this into its abstract type instead of as union. get_left_child(X::Standard_Segment_tree_node) = X.child_nodes[1] get_right_child(X::Standard_Segment_tree_node) = X.child_nodes[2] From bcba1d295c15929a6665c1c9a8461c70db58b82c Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Apr 2022 21:56:49 +0700 Subject: [PATCH 15/91] Update Segment_tree.jl --- src/Segment_tree.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 77ca457b1..8284e592e 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -166,8 +166,13 @@ function get_range(X::Standard_Segment_tree_node, Query_low, Query_high, Current end end -function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low) +function get_entire_range(X::Standard_Segment_tree_node, range) + #Working in progress. + +end +function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low) + end function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_high) From bcd0decbb255304b77951a59f599cef38bf4ff3a Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 10:43:19 +0700 Subject: [PATCH 16/91] Update Segment_tree.jl --- src/Segment_tree.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 8284e592e..f149d4eb6 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -168,11 +168,18 @@ end function get_entire_range(X::Standard_Segment_tree_node, range) #Working in progress. - + if X.child_nodes isa Nothing + return get_iterated_op(X)(X.density, range) + else + return X.value + end end -function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low) - +function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, Current_high) + while true + + end + end function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_high) From 0a11172c306b86efb3286169cbd687c377785e2a Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 10:44:38 +0700 Subject: [PATCH 17/91] Update Segment_tree.jl --- src/Segment_tree.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index f149d4eb6..4ea70807d 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -168,7 +168,7 @@ end function get_entire_range(X::Standard_Segment_tree_node, range) #Working in progress. - if X.child_nodes isa Nothing + if X.child_nodes == nothing return get_iterated_op(X)(X.density, range) else return X.value @@ -177,7 +177,7 @@ end function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, Current_high) while true - + end end From e377697c832a09fbcfa892b0949b09779c8a1916 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 10:47:49 +0700 Subject: [PATCH 18/91] Update Segment_tree.jl --- src/Segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 4ea70807d..85cbd8c9c 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -177,7 +177,7 @@ end function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, Current_high) while true - + #Working in progress. end end From 725dd6fc8f52d57463e832fc8a15d0b6c7614c74 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:00:30 +0700 Subject: [PATCH 19/91] Update Segment_tree.jl --- src/Segment_tree.jl | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 85cbd8c9c..15f0e8982 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -116,11 +116,16 @@ get_identity(::Type{X},typeof(+)) where {X<:Standard_Field} = zero(X) get_identity(::Type{X},typeof(*)) where {X<:Standard_Field} = one(X) function Segment_tree_node(Dtype::Type, Op::Function, iterated_op::Function) if get_identity(Dtype,Op) isa Nothing + #Consider this solution. + #Workaround_op(x,y) = ifelse(x==nothing, y, Op(x,y)) + #Workaround_iterated_op(x,y) = ifelse(x==nothing, nothing, iterated_op(x,y)) return Segment_tree_node_without_identity{Dtype,Op,iterated_op}() else return Segment_tree_node{Dtype,Op,iterated_op,get_identity(Dtype,Op)}() end end +get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity +get_element_identity(::Segment_tree_node_without_identity) = nothing Standard_Segment_tree_node = Union{Segment_tree_node,Segment_tree_node_without_identity} #Standard meaning not every Segment_tree_node has this. #TODO: consider refactoring this into its abstract type instead of as union. @@ -151,12 +156,16 @@ function get_range(X::Standard_Segment_tree_node, Query_low, Query_high, Current #end #Split into two functions, ones where you only care about prefix, and the other where you only care about suffix. while true - Current_mid = div(low+high,2) + if X.child_nodes == nothing + return get_iterated_op(X)(X.density, Query_high-Query_low+1) + end + + Current_mid = div(Current_low+Current_high,2) if Query_high <= Current_mid Current_high = Current_mid X = get_left_child(X) else if Query_low > Current_mid - Current_low = Current_mid + Current_low = Current_mid+1 X = get_right_child(X) else return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low),get_right_range(get_right_child(X,Query_high, Current_high))) @@ -176,7 +185,16 @@ function get_entire_range(X::Standard_Segment_tree_node, range) end function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, Current_high) + answer = get_element_identity(X) while true + Current_mid = div(Current_low+Current_high,2) + if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) + X = get_left_child(X) + end #Working in progress. end From c7a02f09e129e865284589441d422b3f2a5ac27e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:11:06 +0700 Subject: [PATCH 20/91] Update Segment_tree.jl --- src/Segment_tree.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 15f0e8982..a671b3d58 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -4,6 +4,9 @@ It should be made available as part of the (MIT-licensed) Datastructures.jl pack Feel free to use or extend this code. =# +#cd("Data_structure) +#(package) activate . + abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end From 90be73491264f35ce2c48799a3db16440778fdff Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:14:49 +0700 Subject: [PATCH 21/91] Update Segment_tree.jl --- src/Segment_tree.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index a671b3d58..5d865cbca 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -190,6 +190,10 @@ end function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, Current_high) answer = get_element_identity(X) while true + if X.child_nodes == nothing + return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) + end + Current_mid = div(Current_low+Current_high,2) if Query_low > Current_mid Current_low = Current_mid+1 From 5964c78533ab67ef3e2fd3995ece94a712467a0d Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:18:58 +0700 Subject: [PATCH 22/91] Update Segment_tree.jl --- src/Segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 5d865cbca..42cc2a402 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -120,7 +120,7 @@ get_identity(::Type{X},typeof(*)) where {X<:Standard_Field} = one(X) function Segment_tree_node(Dtype::Type, Op::Function, iterated_op::Function) if get_identity(Dtype,Op) isa Nothing #Consider this solution. - #Workaround_op(x,y) = ifelse(x==nothing, y, Op(x,y)) + #Workaround_op(x,y) = ifelse(x==nothing, y, ifelse(y==nothing,x,Op(x,y))) #Workaround_iterated_op(x,y) = ifelse(x==nothing, nothing, iterated_op(x,y)) return Segment_tree_node_without_identity{Dtype,Op,iterated_op}() else From e587bceeeafa9bddb61b6ab2a9afa0e6143b4717 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:38:11 +0700 Subject: [PATCH 23/91] Update Segment_tree.jl --- src/Segment_tree.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 42cc2a402..dc03c882a 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -200,6 +200,7 @@ function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, C X = get_right_child(X) else answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) + Current_high = Current_mid X = get_left_child(X) end #Working in progress. From e980c3e63490bf8156a758638f4cbaac46f7057d Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:39:27 +0700 Subject: [PATCH 24/91] Update Segment_tree.jl --- src/Segment_tree.jl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index dc03c882a..6e67daea7 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -208,6 +208,18 @@ function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, C end -function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_high) +function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_low,Current_high) + answer = get_element_identity(X) + while true + if X.child_nodes == nothing + return + end + + Current_mid = div(Current_low+Current_high,2) + if # + else + end + #Working in progress. + end end From 052f0ca9c1d00444be6e37b3f94b77f283789498 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:41:19 +0700 Subject: [PATCH 25/91] Update Segment_tree.jl --- src/Segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 6e67daea7..036928e77 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -171,7 +171,7 @@ function get_range(X::Standard_Segment_tree_node, Query_low, Query_high, Current Current_low = Current_mid+1 X = get_right_child(X) else - return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low),get_right_range(get_right_child(X,Query_high, Current_high))) + return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_high),get_right_range(get_right_child(X),Query_high, Current_low,Current_high)) #Working in progress. end From 811ae219ebf80ea76673db094d3f2cd04ab6bb1e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:41:38 +0700 Subject: [PATCH 26/91] Update Segment_tree.jl --- src/Segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 036928e77..d21bf13e0 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -191,7 +191,7 @@ function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, C answer = get_element_identity(X) while true if X.child_nodes == nothing - return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) + return (get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) end Current_mid = div(Current_low+Current_high,2) From 192ebbd2be7338811d726eddae62165c547d1b0a Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 15 Apr 2022 22:48:34 +0700 Subject: [PATCH 27/91] Update Segment_tree.jl --- src/Segment_tree.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index d21bf13e0..6784811d4 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -216,9 +216,13 @@ function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_low, end Current_mid = div(Current_low+Current_high,2) - if # + if Query_high <= Current_mid + Query_high = Current_mid + X = get_left_child(X) else - + answer = get_op(X)(get_entire_range(get_left_child(X),Current_mid-Current_low+1), answer) + Current_low = Current_mid+1 + X = get_right_child(X) end #Working in progress. end From 30bcdb7afd08883d1504b3daaf1d99e6efbdc92c Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sat, 16 Apr 2022 20:44:39 +0700 Subject: [PATCH 28/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 32462db1a..8ad6b5ab1 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -39,7 +39,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "segment_tree" begin @testset "Add" begin - X1 = segment_tree(100,UInt64,Base.:+) + X1 = Segment_tree(100,UInt64,Base.:+) a = zeros(UInt64, 100) change_range!(X1, 3,37,53) change_range!(X1, 9,23,45) @@ -56,7 +56,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. - X1 = segment_tree(10000,UInt64, Base.:+) + X1 = Segment_tree(10000,UInt64, Base.:+) X2 = zeros(UInt64, 10000) for i in 1:10000 a = rand(1:10000) @@ -71,7 +71,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, end @testset "Xor_trial" begin - X1 = segment_tree(10000,UInt64, xor) + X1 = Segment_tree(10000,UInt64, xor) X2 = zeros(UInt64, 10000) for i in 1:10000 a = rand(1:10000) @@ -87,7 +87,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "3x3_matrix_multiplication" begin #Float/etc should work fine as well. Just don't want to deal with precision issues. - X1 = segment_tree(1000,Array{UInt64,2},*) + X1 = Segment_tree(1000,Array{UInt64,2},*) identity_matrix = zeros(UInt64,(3,3)) identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 #Vector of vector may not be the most efficient, but it should work without problem. From b467ab6fdf1355c4a6aa816d09e10d5a7fa83a79 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 17 Apr 2022 11:19:01 +0700 Subject: [PATCH 29/91] Update Segment_tree.jl --- src/Segment_tree.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index 6784811d4..b476ec8b7 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -91,7 +91,7 @@ mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegm density::Dtype #Implicitly have information about where it represents. function Segment_tree_node() - return new(nothing) + return new{Dtype,Op,iterated_op,identity}(nothing) end end @@ -103,7 +103,7 @@ mutable struct Segment_tree_node_without_identity{Dtype,Op,iterated_op}<:Abstrac value::Union{Dtype,Nothing} density::Union{Dtype,Nothing} function Segment_tree_node_without_identity() - return new(nothing) + return new{Dtype,Op,iterated_op}(nothing) end end From a19cf9db90ad0110f9997e8caee1665cd07a1030 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 18 Apr 2022 21:36:37 +0700 Subject: [PATCH 30/91] Update Segment_tree.jl --- src/Segment_tree.jl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Segment_tree.jl b/src/Segment_tree.jl index b476ec8b7..22d2b588f 100644 --- a/src/Segment_tree.jl +++ b/src/Segment_tree.jl @@ -143,6 +143,9 @@ function get_range(X::Abstractsegmenttree, low, high) return get_range(get_head(X),low,high, 1, sizeof(X)) end +function set_range!(X::Abstractsegmenttree, low,high) + set_range!(get_head(X),low,high,1,sizeof(X)) +end @@ -227,3 +230,25 @@ function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_low, #Working in progress. end end + +function set_range!(X::Standard_Segment_tree_node, Query_low, Query_high, Current_low, Current_high) + while true + if X.child_nodes == nothing + #Do something about it to set the range correctly. + #Perhaps construct empty segment tree nodes? + end + + Current_mid = div(Current_low+Current_high,2) + if Query_high <= Current_mid + Current_high = Current_mid + X = get_left_child(X) + else if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + #Time to set left range and set right range. + #Working in progress. + end + + end +end \ No newline at end of file From 16f8d5ecd033b1a8c4c45acf341f1183de350868 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sat, 21 May 2022 18:55:32 +0700 Subject: [PATCH 31/91] Backup. Making a backup to prepare for a rewrite. --- src/{Segment_tree.jl => segment_tree_backup.jl} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{Segment_tree.jl => segment_tree_backup.jl} (100%) diff --git a/src/Segment_tree.jl b/src/segment_tree_backup.jl similarity index 100% rename from src/Segment_tree.jl rename to src/segment_tree_backup.jl From ddba963819ffe7066aafa02df982a273749aae7e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 22 May 2022 11:24:40 +0700 Subject: [PATCH 32/91] Create segment_tree.jl --- src/segment_tree.jl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/segment_tree.jl diff --git a/src/segment_tree.jl b/src/segment_tree.jl new file mode 100644 index 000000000..fc32cc859 --- /dev/null +++ b/src/segment_tree.jl @@ -0,0 +1,18 @@ +#= +Author: Alice Roselia. +It should be made available as part of the (MIT-licensed) Datastructures.jl package. +Feel free to use or extend this code. +=# + +#cd("Data_structure) +#(package) activate . +abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end +abstract type Abstractsegmenttree{node_type} end +get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype +get_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op +get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op + + +get_middle(low, high) = div(low+high,2) + + From 4ccae34f4b1358793c8c6d7f60e7e1f8bf1da13d Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 22 May 2022 11:46:17 +0700 Subject: [PATCH 33/91] Update segment_tree.jl --- src/segment_tree.jl | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index fc32cc859..0dc79c71e 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -15,4 +15,32 @@ get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, O get_middle(low, high) = div(low+high,2) +function repeat_op(base,time::Integer, op::Function) + #Hopefully segment tree not larger than 64. Otherwise, big number segment tree may be needed. + Iterations = convert(UInt,time) + #Find trailing zeros. + baseline = base + for i in 1:trailing_zeros(Iterations) + baseline = op(baseline,baseline) + end + Iterations = Iterations>>trailing_zeros(Iterations) + + #Operate to get to the baseline. + #baseline = #Working in progress. + + #Then, you can iterate. + final_value = baseline + while (Iterations!=0) + Iterations>>=1 + baseline = op(baseline,baseline) + if isodd(Iterations) + final_value = op(final_value,baseline) + end + end + #Something + + return final_value +end + +struct artificial_identity end From 045f5309401820020d4ce7bfb625d40488a1db1a Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 22 May 2022 12:01:12 +0700 Subject: [PATCH 34/91] Update segment_tree.jl --- src/segment_tree.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 0dc79c71e..8f95482c9 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -42,5 +42,10 @@ function repeat_op(base,time::Integer, op::Function) return final_value end - +#Identity is required. struct artificial_identity end + + +identity(x,y) = artificial_identity +identity(::T, ::typeof(+)) where {T<:Number} = zero(T) +identity(::T, ::typeof(*)) where {T<:Number} = one(T) \ No newline at end of file From 47cbf1cd6b40e2d923cb7880c7ed90857c2662c9 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 22 May 2022 12:01:36 +0700 Subject: [PATCH 35/91] Update segment_tree.jl --- src/segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 8f95482c9..a82927783 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -48,4 +48,4 @@ struct artificial_identity end identity(x,y) = artificial_identity identity(::T, ::typeof(+)) where {T<:Number} = zero(T) -identity(::T, ::typeof(*)) where {T<:Number} = one(T) \ No newline at end of file +identity(::T, ::typeof(*)) where {T<:Number} = one(T) From 66d691a8062021229fc7ee4071b71f0f3f20fe60 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 22 May 2022 18:28:01 +0700 Subject: [PATCH 36/91] Artificial_identity OPs. --- src/segment_tree.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index a82927783..f7f00d551 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -49,3 +49,5 @@ struct artificial_identity end identity(x,y) = artificial_identity identity(::T, ::typeof(+)) where {T<:Number} = zero(T) identity(::T, ::typeof(*)) where {T<:Number} = one(T) +operation_with_identity(f) = (x,y)-> (x===artificial_identity) ? y : (y===artificial_identity ? x : f(x,y)) +repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity) ? artificial_identity : f(base,time) From 3c924d491bc8207132f832eaf6579817c3c79978 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 22 May 2022 20:13:53 +0700 Subject: [PATCH 37/91] Update segment_tree.jl --- src/segment_tree.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index f7f00d551..f16906302 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -51,3 +51,16 @@ identity(::T, ::typeof(+)) where {T<:Number} = zero(T) identity(::T, ::typeof(*)) where {T<:Number} = one(T) operation_with_identity(f) = (x,y)-> (x===artificial_identity) ? y : (y===artificial_identity ? x : f(x,y)) repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity) ? artificial_identity : f(base,time) + + +mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} + child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op, identity}},Nothing} + #Either both children are valid or none is valid. + value::Dtype + density::Dtype + #Implicitly have information about where it represents. + function Segment_tree_node() + return new{Dtype,Op,iterated_op,identity}(nothing) + end +end +get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity \ No newline at end of file From 22e02133b6bf5891bae5610361848a7343bb024a Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 23 May 2022 14:05:06 +0700 Subject: [PATCH 38/91] Update segment_tree.jl --- src/segment_tree.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index f16906302..d03993e98 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -63,4 +63,5 @@ mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegm return new{Dtype,Op,iterated_op,identity}(nothing) end end -get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity \ No newline at end of file +get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity + From c7e9287cf90e28686b8c17eede409cfa9c1b0252 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 23 May 2022 22:03:54 +0700 Subject: [PATCH 39/91] Update segment_tree.jl --- src/segment_tree.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index d03993e98..cab2cc622 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -65,3 +65,13 @@ mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegm end get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity +struct Segment_tree{node_type} <: Abstractsegmenttree{node_type} + size::Int + head::node_type +end +function Segment_tree(type::Type{T}, size, op, iterated_op, identity::T) where {T} + size = convert(Int,size) + return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}()} +end + +function Segment_tree(type::Type, size, op; identity=) \ No newline at end of file From 2aaa920931603ad80133bdb26adbf48d26ce133b Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 23 May 2022 22:07:35 +0700 Subject: [PATCH 40/91] Update segment_tree.jl --- src/segment_tree.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index cab2cc622..b779e00ae 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -74,4 +74,6 @@ function Segment_tree(type::Type{T}, size, op, iterated_op, identity::T) where { return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}()} end -function Segment_tree(type::Type, size, op; identity=) \ No newline at end of file +function Segment_tree(type::Type, size, op; iterated_op=) + #Make both +end \ No newline at end of file From 2b0c31d5cf21c962289b92bfb7674506c898d307 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 24 May 2022 21:29:24 +0700 Subject: [PATCH 41/91] Update segment_tree.jl --- src/segment_tree.jl | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index b779e00ae..1066845dc 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -46,11 +46,11 @@ end struct artificial_identity end -identity(x,y) = artificial_identity -identity(::T, ::typeof(+)) where {T<:Number} = zero(T) -identity(::T, ::typeof(*)) where {T<:Number} = one(T) -operation_with_identity(f) = (x,y)-> (x===artificial_identity) ? y : (y===artificial_identity ? x : f(x,y)) -repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity) ? artificial_identity : f(base,time) +get_identity(x,y) = artificial_identity() +get_identity(::Type{T}, ::typeof(+)) where {T<:Number} = zero(T) +get_identity(::Type{T}, ::typeof(*)) where {T<:Number} = one(T) +operation_with_identity(f) = (x,y)-> (x===artificial_identity()) ? y : (y===artificial_identity() ? x : f(x,y)) +repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity()) ? artificial_identity() : f(base,time) mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} @@ -65,15 +65,32 @@ mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegm end get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity -struct Segment_tree{node_type} <: Abstractsegmenttree{node_type} +struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{node_type} size::Int head::node_type end -function Segment_tree(type::Type{T}, size, op, iterated_op, identity::T) where {T} +function Segment_tree(type::Type{T}, size, op::Function, iterated_op::Function, identity::T) where {T} size = convert(Int,size) - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}()} + println(type) + println(op) + println(typeof(iterated_op)) + println("iterated_op is ",iterated_op) + println(typeof(identity)) + return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,Segment_tree_node{type,op,iterated_op,identity}()) end -function Segment_tree(type::Type, size, op; iterated_op=) +function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) #Make both + if iterated_op===nothing + iterated_op = (x,y)->repeat_op(x,y,op) + end + if identity === nothing + identity = get_identity(type,op) + if identity === artificial_identity() + type = Union{type,artificial_identity} + op = operation_with_identity(op) + iterated_op = repeat_op_with_identity(iterated_op) + end + end + return Segment_tree(type,size,op,iterated_op,identity) end \ No newline at end of file From 8ef4adc7534aac2f760bf4893cf357d0f01eb227 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 24 May 2022 21:43:25 +0700 Subject: [PATCH 42/91] Update segment_tree.jl --- src/segment_tree.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 1066845dc..d94d2b745 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -59,7 +59,7 @@ mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegm value::Dtype density::Dtype #Implicitly have information about where it represents. - function Segment_tree_node() + function Segment_tree_node{Dtype,Op,iterated_op,identity}() where {Dtype,Op,iterated_op,identity} return new{Dtype,Op,iterated_op,identity}(nothing) end end @@ -69,14 +69,14 @@ struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{n size::Int head::node_type end -function Segment_tree(type::Type{T}, size, op::Function, iterated_op::Function, identity::T) where {T} +function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) - println(type) - println(op) println(typeof(iterated_op)) println("iterated_op is ",iterated_op) - println(typeof(identity)) - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,Segment_tree_node{type,op,iterated_op,identity}()) + println(iterated_op isa Function) + head = Segment_tree_node{type,op,iterated_op,identity}() + + #return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,Segment_tree_node{type,op,iterated_op,identity}()) end function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) From a50d63693a92c340f6175958208778637f2874a9 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 24 May 2022 23:07:08 +0700 Subject: [PATCH 43/91] Fixing scoping problems? --- src/segment_tree.jl | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index d94d2b745..6d1fb1fde 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -74,23 +74,28 @@ function Segment_tree(type, size, op::Function, iterated_op::Function, identity) println(typeof(iterated_op)) println("iterated_op is ",iterated_op) println(iterated_op isa Function) - head = Segment_tree_node{type,op,iterated_op,identity}() + head = Segment_tree_node{type, op, iterated_op, identity}() - #return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,Segment_tree_node{type,op,iterated_op,identity}()) + return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head) end function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) #Make both + new_op = op if iterated_op===nothing - iterated_op = (x,y)->repeat_op(x,y,op) + new_iterated_op = (x,y)->repeat_op(x,y,op) + else + new_iterated_op = iterated_op end if identity === nothing - identity = get_identity(type,op) - if identity === artificial_identity() + new_identity = get_identity(type,op) + if new_identity === artificial_identity() type = Union{type,artificial_identity} - op = operation_with_identity(op) - iterated_op = repeat_op_with_identity(iterated_op) + new_op = operation_with_identity(op) + new_iterated_op = repeat_op_with_identity(new_iterated_op) end + else + new_identity = identity end - return Segment_tree(type,size,op,iterated_op,identity) + return Segment_tree(type,size,new_op,new_iterated_op,new_identity) end \ No newline at end of file From a4d361ac5d82068aaf27de9a562d821bbfb98cbe Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 24 May 2022 23:12:09 +0700 Subject: [PATCH 44/91] Update segment_tree.jl --- src/segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 6d1fb1fde..44aa7c464 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -80,7 +80,7 @@ function Segment_tree(type, size, op::Function, iterated_op::Function, identity) end function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) - #Make both + #A bit annoying but local scope must take place. new_op = op if iterated_op===nothing new_iterated_op = (x,y)->repeat_op(x,y,op) From 38969a2ef73d311de28b916b0960415375e87f5b Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 25 May 2022 10:14:09 +0700 Subject: [PATCH 45/91] Update segment_tree.jl --- src/segment_tree.jl | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 44aa7c464..3e2ab8ab9 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -42,6 +42,17 @@ function repeat_op(base,time::Integer, op::Function) return final_value end + +#Specialized cases for repeat_op. + +repeat_op(base::Number, time::Integer, ::typeof(+)) = base*time +repeat_op(base::Number, time::Integer, ::typeof(*)) = base^time +repeat_op(base::T, time::Integer, ::typeof(xor)) where {T<:Integer} = iseven(time) ? zero(T) : base +repeat_op(base::T, ::Integer, ::typeof(&)) = base +repeat_op(base::T, ::Integer, ::typeof(|)) = base + +#I luv multiple dispatch! + #Identity is required. struct artificial_identity end @@ -71,11 +82,7 @@ struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{n end function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) - println(typeof(iterated_op)) - println("iterated_op is ",iterated_op) - println(iterated_op isa Function) head = Segment_tree_node{type, op, iterated_op, identity}() - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head) end From 2b8a9d250303cc98fa93eefd1533c5354ea82de9 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 25 May 2022 21:16:39 +0700 Subject: [PATCH 46/91] Adding the get_range to it. --- src/segment_tree.jl | 29 +++++++++++++++++++++++++++++ src/segment_tree_backup.jl | 1 - 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 3e2ab8ab9..a8f578ae5 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -80,6 +80,7 @@ struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{n size::Int head::node_type end +sizeof(X::Segment_tree) = X.size function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) head = Segment_tree_node{type, op, iterated_op, identity}() @@ -105,4 +106,32 @@ function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothin new_identity = identity end return Segment_tree(type,size,new_op,new_iterated_op,new_identity) +end + + +@inline function get_range(X::Segment_tree,low,high) + + #The reason this is inlined is because there is only ONE line. + #This is only a wrapping call to another function which is NOT inlined. + return get_range(X.head,low,high,1,sizeof(X)) +end + +function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) + while true + if X.child_nodes === nothing + return get_iterated_op(X)(X.density, Query_high-Query_low+1) + end + + Current_mid =get_middle(Current_low,Current_high) + if Query_high <= Current_mid + Current_high = Current_mid + X = get_left_child(X) + else if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_high),get_right_range(get_right_child(X),Query_high, Current_low,Current_high)) + #Working in progress. + end + end end \ No newline at end of file diff --git a/src/segment_tree_backup.jl b/src/segment_tree_backup.jl index 22d2b588f..db306e8f3 100644 --- a/src/segment_tree_backup.jl +++ b/src/segment_tree_backup.jl @@ -177,7 +177,6 @@ function get_range(X::Standard_Segment_tree_node, Query_low, Query_high, Current return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_high),get_right_range(get_right_child(X),Query_high, Current_low,Current_high)) #Working in progress. end - end end From 44ce8170bb6f2d16843b05abb15e147354fea4b2 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Thu, 26 May 2022 20:52:55 +0700 Subject: [PATCH 47/91] Update segment_tree.jl --- src/segment_tree.jl | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index a8f578ae5..32618e21b 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -134,4 +134,56 @@ function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Cur #Working in progress. end end +end + +function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) + answer = get_element_identity(X) + while true + if X.child_nodes === nothing + return (get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) + end + + Current_mid = get_middle(Current_low,Current_high) + if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) + Current_high = Current_mid + X = get_left_child(X) + end + #Working in progress. + end + +end + +function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) + answer = get_element_identity(X) + while true + if X.child_nodes === nothing + return + end + + Current_mid = get_middle(Current_low,Current_high) + if Query_high <= Current_mid + Query_high = Current_mid + X = get_left_child(X) + else + answer = get_op(X)(get_entire_range(get_left_child(X),Current_mid-Current_low+1), answer) + Current_low = Current_mid+1 + X = get_right_child(X) + end + #Working in progress. + end +end + +#inline? +function get_entire_range(X::Standard_Segment_tree_node, range) + #Working in progress. + if X.child_nodes === nothing + + return get_iterated_op(X)(X.density, range) + else + return X.value + end end \ No newline at end of file From 60c4f25e7ad9fb237f50f5e347b2da1a67a2ea8b Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Thu, 26 May 2022 20:54:44 +0700 Subject: [PATCH 48/91] Update segment_tree.jl --- src/segment_tree.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 32618e21b..f9bbd9762 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -109,13 +109,15 @@ function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothin end + @inline function get_range(X::Segment_tree,low,high) #The reason this is inlined is because there is only ONE line. #This is only a wrapping call to another function which is NOT inlined. return get_range(X.head,low,high,1,sizeof(X)) end - +get_left_child(X::Segment_tree_node) = X.child_nodes[1] +get_right_child(X::Segment_tree_node) = X.child_nodes[2] function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) while true if X.child_nodes === nothing @@ -178,7 +180,7 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h end #inline? -function get_entire_range(X::Standard_Segment_tree_node, range) +function get_entire_range(X::Segment_tree_node, range) #Working in progress. if X.child_nodes === nothing From b06b3e975f97553f5da6ae1d09514ff8f59e08e4 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 27 May 2022 19:21:20 +0700 Subject: [PATCH 49/91] Update segment_tree.jl --- src/segment_tree.jl | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index f9bbd9762..ffa88b64c 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -120,7 +120,7 @@ get_left_child(X::Segment_tree_node) = X.child_nodes[1] get_right_child(X::Segment_tree_node) = X.child_nodes[2] function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) while true - if X.child_nodes === nothing + if X.child_nodes === nothing #Is the terminal node. return get_iterated_op(X)(X.density, Query_high-Query_low+1) end @@ -132,8 +132,9 @@ function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Cur Current_low = Current_mid+1 X = get_right_child(X) else - return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_high),get_right_range(get_right_child(X),Query_high, Current_low,Current_high)) - #Working in progress. + return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_mid),get_right_range(get_right_child(X),Query_high, Current_mid+1,Current_high)) + #If this branch is taken before the terminal node is reached, it means that there is a "split". + #This can split only once. This information avoids excessive checks and recursion. end end end @@ -141,7 +142,7 @@ end function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) answer = get_element_identity(X) while true - if X.child_nodes === nothing + if X.child_nodes === nothing #Is the terminal node. return (get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) end @@ -163,12 +164,13 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h answer = get_element_identity(X) while true if X.child_nodes === nothing - return + #Still in progress here. + return (get_iterated_op(X)(X.density, Query_high-Current_low+1)) end Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid - Query_high = Current_mid + Current_high = Current_mid X = get_left_child(X) else answer = get_op(X)(get_entire_range(get_left_child(X),Current_mid-Current_low+1), answer) @@ -180,12 +182,19 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h end #inline? -function get_entire_range(X::Segment_tree_node, range) +#= +Get rid of this insanity. +@inline function get_entire_range(X::Segment_tree_node, range) #Working in progress. if X.child_nodes === nothing - + #Should this density thing be put at this level? return get_iterated_op(X)(X.density, range) else return X.value end +end +=# + +@inline function get_entire_range(X::Segment_tree_node) + return X.value end \ No newline at end of file From 2a502f62ead89752c7c946425940df363ff69f00 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 27 May 2022 19:22:00 +0700 Subject: [PATCH 50/91] Update segment_tree.jl --- src/segment_tree.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index ffa88b64c..763d7eb39 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -155,7 +155,6 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi Current_high = Current_mid X = get_left_child(X) end - #Working in progress. end end @@ -163,8 +162,7 @@ end function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) answer = get_element_identity(X) while true - if X.child_nodes === nothing - #Still in progress here. + if X.child_nodes === nothing #Is the terminal node. return (get_iterated_op(X)(X.density, Query_high-Current_low+1)) end From 6085fdac2706ed0260427314f6b6b3958d872190 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 27 May 2022 19:23:47 +0700 Subject: [PATCH 51/91] Update segment_tree.jl --- src/segment_tree.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 763d7eb39..cc1d1ffe7 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -151,7 +151,8 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi Current_low = Current_mid+1 X = get_right_child(X) else - answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) + #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) + answer = get_op(X)(answer,get_entire_range(get_right_child(X))) Current_high = Current_mid X = get_left_child(X) end From f5d82491ebf676e89c919f39591f67c51746d779 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 27 May 2022 19:44:44 +0700 Subject: [PATCH 52/91] Mark the checkpoint 2 --- src/Segment_tree_backup_2.jl | 201 +++++++++++++++++++++++++++++++++++ src/segment_tree.jl | 14 +-- 2 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 src/Segment_tree_backup_2.jl diff --git a/src/Segment_tree_backup_2.jl b/src/Segment_tree_backup_2.jl new file mode 100644 index 000000000..a79314a1d --- /dev/null +++ b/src/Segment_tree_backup_2.jl @@ -0,0 +1,201 @@ +#= +Author: Alice Roselia. +It should be made available as part of the (MIT-licensed) Datastructures.jl package. +Feel free to use or extend this code. +=# + +#cd("Data_structure) +#(package) activate . +abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end +abstract type Abstractsegmenttree{node_type} end +get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype +get_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op +get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op + + +get_middle(low, high) = div(low+high,2) + +function repeat_op(base,time::Integer, op::Function) + #Hopefully segment tree not larger than 64. Otherwise, big number segment tree may be needed. + Iterations = convert(UInt,time) + #Find trailing zeros. + baseline = base + for i in 1:trailing_zeros(Iterations) + baseline = op(baseline,baseline) + end + Iterations = Iterations>>trailing_zeros(Iterations) + + #Operate to get to the baseline. + #baseline = #Working in progress. + + #Then, you can iterate. + final_value = baseline + while (Iterations!=0) + Iterations>>=1 + baseline = op(baseline,baseline) + if isodd(Iterations) + final_value = op(final_value,baseline) + end + end + #Something + + + return final_value +end + +#Specialized cases for repeat_op. + +repeat_op(base::Number, time::Integer, ::typeof(+)) = base*time +repeat_op(base::Number, time::Integer, ::typeof(*)) = base^time +repeat_op(base::T, time::Integer, ::typeof(xor)) where {T<:Integer} = iseven(time) ? zero(T) : base +repeat_op(base::T, ::Integer, ::typeof(&)) = base +repeat_op(base::T, ::Integer, ::typeof(|)) = base + +#I luv multiple dispatch! + +#Identity is required. +struct artificial_identity end + + +get_identity(x,y) = artificial_identity() +get_identity(::Type{T}, ::typeof(+)) where {T<:Number} = zero(T) +get_identity(::Type{T}, ::typeof(*)) where {T<:Number} = one(T) +operation_with_identity(f) = (x,y)-> (x===artificial_identity()) ? y : (y===artificial_identity() ? x : f(x,y)) +repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity()) ? artificial_identity() : f(base,time) + + +mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} + child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op, identity}},Nothing} + #Either both children are valid or none is valid. + value::Dtype + density::Dtype + #Implicitly have information about where it represents. + function Segment_tree_node{Dtype,Op,iterated_op,identity}() where {Dtype,Op,iterated_op,identity} + return new{Dtype,Op,iterated_op,identity}(nothing) + end +end +get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity + +struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{node_type} + size::Int + head::node_type +end +sizeof(X::Segment_tree) = X.size +function Segment_tree(type, size, op::Function, iterated_op::Function, identity) + size = convert(Int,size) + head = Segment_tree_node{type, op, iterated_op, identity}() + return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head) +end + +function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) + #A bit annoying but local scope must take place. + new_op = op + if iterated_op===nothing + new_iterated_op = (x,y)->repeat_op(x,y,op) + else + new_iterated_op = iterated_op + end + if identity === nothing + new_identity = get_identity(type,op) + if new_identity === artificial_identity() + type = Union{type,artificial_identity} + new_op = operation_with_identity(op) + new_iterated_op = repeat_op_with_identity(new_iterated_op) + end + else + new_identity = identity + end + return Segment_tree(type,size,new_op,new_iterated_op,new_identity) +end + + + +@inline function get_range(X::Segment_tree,low,high) + + #The reason this is inlined is because there is only ONE line. + #This is only a wrapping call to another function which is NOT inlined. + return get_range(X.head,low,high,1,sizeof(X)) +end +get_left_child(X::Segment_tree_node) = X.child_nodes[1] +get_right_child(X::Segment_tree_node) = X.child_nodes[2] +function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) + while true + if X.child_nodes === nothing #Is the terminal node. + return get_iterated_op(X)(X.density, Query_high-Query_low+1) + end + + Current_mid =get_middle(Current_low,Current_high) + if Query_high <= Current_mid + Current_high = Current_mid + X = get_left_child(X) + else if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_mid),get_right_range(get_right_child(X),Query_high, Current_mid+1,Current_high)) + #If this branch is taken before the terminal node is reached, it means that there is a "split". + #This can split only once. This information avoids excessive checks and recursion. + end + end +end + +function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) + answer = get_element_identity(X) + while true + if X.child_nodes === nothing #Is the terminal node. + #Hopefully, this is correct. + # get operation between the right (previously accumulated answer) and the left (this node) + return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) + end + + Current_mid = get_middle(Current_low,Current_high) + if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) (Except that the 2nd argument wasn't needed.) + answer = get_op(X)(answer,get_entire_range(get_right_child(X))) + Current_high = Current_mid + X = get_left_child(X) + end + end + +end + +function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) + answer = get_element_identity(X) + while true + if X.child_nodes === nothing #Is the terminal node. + return get_op(X)(answer,get_iterated_op(X)(X.density, Query_high-Current_low+1)) + end + + Current_mid = get_middle(Current_low,Current_high) + if Query_high <= Current_mid + Current_high = Current_mid + X = get_left_child(X) + else + #Same logic. + answer = get_op(X)(get_entire_range(get_left_child(X)), answer) + Current_low = Current_mid+1 + X = get_right_child(X) + end + #Working in progress. + end +end +#= +Get rid of this insanity. +#inline? +@inline function get_entire_range(X::Segment_tree_node, range) + #Working in progress. + if X.child_nodes === nothing + #Should this density thing be put at this level? + return get_iterated_op(X)(X.density, range) + else + return X.value + end +end +=# + +@inline function get_entire_range(X::Segment_tree_node) + return X.value +end \ No newline at end of file diff --git a/src/segment_tree.jl b/src/segment_tree.jl index cc1d1ffe7..a79314a1d 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -143,7 +143,9 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi answer = get_element_identity(X) while true if X.child_nodes === nothing #Is the terminal node. - return (get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) + #Hopefully, this is correct. + # get operation between the right (previously accumulated answer) and the left (this node) + return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) end Current_mid = get_middle(Current_low,Current_high) @@ -151,7 +153,7 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi Current_low = Current_mid+1 X = get_right_child(X) else - #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) + #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) (Except that the 2nd argument wasn't needed.) answer = get_op(X)(answer,get_entire_range(get_right_child(X))) Current_high = Current_mid X = get_left_child(X) @@ -164,7 +166,7 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h answer = get_element_identity(X) while true if X.child_nodes === nothing #Is the terminal node. - return (get_iterated_op(X)(X.density, Query_high-Current_low+1)) + return get_op(X)(answer,get_iterated_op(X)(X.density, Query_high-Current_low+1)) end Current_mid = get_middle(Current_low,Current_high) @@ -172,17 +174,17 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h Current_high = Current_mid X = get_left_child(X) else - answer = get_op(X)(get_entire_range(get_left_child(X),Current_mid-Current_low+1), answer) + #Same logic. + answer = get_op(X)(get_entire_range(get_left_child(X)), answer) Current_low = Current_mid+1 X = get_right_child(X) end #Working in progress. end end - -#inline? #= Get rid of this insanity. +#inline? @inline function get_entire_range(X::Segment_tree_node, range) #Working in progress. if X.child_nodes === nothing From ae119c82dc36256f76a18d43c6ae61dd704ffb8e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 27 May 2022 19:47:16 +0700 Subject: [PATCH 53/91] Cleaned up --- src/segment_tree.jl | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index a79314a1d..ba0671d2a 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -179,22 +179,8 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h Current_low = Current_mid+1 X = get_right_child(X) end - #Working in progress. end end -#= -Get rid of this insanity. -#inline? -@inline function get_entire_range(X::Segment_tree_node, range) - #Working in progress. - if X.child_nodes === nothing - #Should this density thing be put at this level? - return get_iterated_op(X)(X.density, range) - else - return X.value - end -end -=# @inline function get_entire_range(X::Segment_tree_node) return X.value From 1b38dc46a0083205775b8fb854c825962d5b7599 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 27 May 2022 21:05:33 +0700 Subject: [PATCH 54/91] Update segment_tree.jl --- src/segment_tree.jl | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index ba0671d2a..ffa1abbc8 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -116,6 +116,12 @@ end #This is only a wrapping call to another function which is NOT inlined. return get_range(X.head,low,high,1,sizeof(X)) end + +@inline function set_range!(X::Segment_tree, low, high, value) + #Same logic. Wrap the call. + set_range!(get_head(X),low,high,1,sizeof(X), value) +end + get_left_child(X::Segment_tree_node) = X.child_nodes[1] get_right_child(X::Segment_tree_node) = X.child_nodes[2] function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) @@ -184,4 +190,27 @@ end @inline function get_entire_range(X::Segment_tree_node) return X.value +end + +function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value) + #Working in progress. + while true + if X.child_nodes === nothing + #Do something about it to set the range correctly. + #Perhaps construct empty segment tree nodes? + end + + Current_mid = get_middle(Current_low,Current_high) + if Query_high <= Current_mid + Current_high = Current_mid + X = get_left_child(X) + else if Query_low > Current_mid + Current_low = Current_mid+1 + X = get_right_child(X) + else + #Time to set left range and set right range. + #Working in progress. + end + + end end \ No newline at end of file From a1189d6fe365d507948166ea86bdc11fef6dd261 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 29 May 2022 20:31:25 +0700 Subject: [PATCH 55/91] Update segment_tree.jl --- src/segment_tree.jl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index ffa1abbc8..9c5dfe7e7 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -134,7 +134,7 @@ function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Cur if Query_high <= Current_mid Current_high = Current_mid X = get_left_child(X) - else if Query_low > Current_mid + elseif Query_low > Current_mid Current_low = Current_mid+1 X = get_right_child(X) else @@ -198,6 +198,8 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu if X.child_nodes === nothing #Do something about it to set the range correctly. #Perhaps construct empty segment tree nodes? + construct_children!(X, Query_low, Query_high, Current_low, Current_high, value) + #return? end Current_mid = get_middle(Current_low,Current_high) @@ -213,4 +215,16 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu end end +end + +function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value) + +end + +function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value) + +end + +function construct_children!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value) + end \ No newline at end of file From 7e4ef92fb555a357e24f87a10be8005f35807145 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 30 May 2022 12:08:50 +0700 Subject: [PATCH 56/91] Update segment_tree.jl --- src/segment_tree.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 9c5dfe7e7..cbaf6d32d 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -227,4 +227,8 @@ end function construct_children!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value) +end + +function propagate_density!(X::Segment_tree_node) + get_left_child(X).density = get_right_child(X).density end \ No newline at end of file From 2ddda23afb2207881c1384e6a7def4f3cc7f858a Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 1 Jun 2022 09:08:12 +0700 Subject: [PATCH 57/91] Update segment_tree.jl --- src/segment_tree.jl | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index cbaf6d32d..0f4259806 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -48,8 +48,8 @@ end repeat_op(base::Number, time::Integer, ::typeof(+)) = base*time repeat_op(base::Number, time::Integer, ::typeof(*)) = base^time repeat_op(base::T, time::Integer, ::typeof(xor)) where {T<:Integer} = iseven(time) ? zero(T) : base -repeat_op(base::T, ::Integer, ::typeof(&)) = base -repeat_op(base::T, ::Integer, ::typeof(|)) = base +repeat_op(base::Integer, ::Integer, ::typeof(&)) = base +repeat_op(base::Integer, ::Integer, ::typeof(|)) = base #I luv multiple dispatch! @@ -79,12 +79,20 @@ get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) wher struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{node_type} size::Int head::node_type + #The stack will be used each time it is required. + Stack::Vector{node_type} + empty_node::node_type end sizeof(X::Segment_tree) = X.size function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) head = Segment_tree_node{type, op, iterated_op, identity}() - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head) + empty_node = Segment_tree_node{type, op, iterated_op, identity}() + Stack = Vector(undef,65) + for i in 1:65 + Stack[i] = empty_node + end + return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head, Stack, empty_node) end function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) @@ -124,9 +132,10 @@ end get_left_child(X::Segment_tree_node) = X.child_nodes[1] get_right_child(X::Segment_tree_node) = X.child_nodes[2] +is_terminal(X::Segment_tree_node) = (X.child_nodes===nothing) function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) while true - if X.child_nodes === nothing #Is the terminal node. + if is_terminal(X) #Is the terminal node. return get_iterated_op(X)(X.density, Query_high-Query_low+1) end @@ -148,7 +157,7 @@ end function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) answer = get_element_identity(X) while true - if X.child_nodes === nothing #Is the terminal node. + if is_terminal(X) #Is the terminal node. #Hopefully, this is correct. # get operation between the right (previously accumulated answer) and the left (this node) return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) @@ -171,7 +180,7 @@ end function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) answer = get_element_identity(X) while true - if X.child_nodes === nothing #Is the terminal node. + if is_terminal(X) #Is the terminal node. return get_op(X)(answer,get_iterated_op(X)(X.density, Query_high-Current_low+1)) end @@ -195,7 +204,7 @@ end function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value) #Working in progress. while true - if X.child_nodes === nothing + if is_terminal(X) #Do something about it to set the range correctly. #Perhaps construct empty segment tree nodes? construct_children!(X, Query_low, Query_high, Current_low, Current_high, value) @@ -206,7 +215,7 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu if Query_high <= Current_mid Current_high = Current_mid X = get_left_child(X) - else if Query_low > Current_mid + elseif Query_low > Current_mid Current_low = Current_mid+1 X = get_right_child(X) else From 07845bbacc6663aeeda290d65ba5358b62fbe3fd Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 1 Jun 2022 10:13:20 +0700 Subject: [PATCH 58/91] The "6 functions plan" checkpoint. --- src/segment_tree.jl | 51 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 0f4259806..21dec90de 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -80,7 +80,7 @@ struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{n size::Int head::node_type #The stack will be used each time it is required. - Stack::Vector{node_type} + stack::Vector{node_type} empty_node::node_type end sizeof(X::Segment_tree) = X.size @@ -88,11 +88,11 @@ function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) head = Segment_tree_node{type, op, iterated_op, identity}() empty_node = Segment_tree_node{type, op, iterated_op, identity}() - Stack = Vector(undef,65) + stack = Vector(undef,65) for i in 1:65 - Stack[i] = empty_node + stack[i] = empty_node end - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head, Stack, empty_node) + return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head, stack, empty_node) end function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) @@ -127,7 +127,8 @@ end @inline function set_range!(X::Segment_tree, low, high, value) #Same logic. Wrap the call. - set_range!(get_head(X),low,high,1,sizeof(X), value) + #The utility memories are here. + set_range!(get_head(X),low,high,1,sizeof(X), value, X.stack, X.empty_node) end get_left_child(X::Segment_tree_node) = X.child_nodes[1] @@ -201,14 +202,30 @@ end return X.value end -function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value) +#= +Plan: + +set_range!. +set_left_range!. +set_right_range! +construct_children! +construct_left_children! +construct_right_children! +=# + +function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) #Working in progress. while true if is_terminal(X) #Do something about it to set the range correctly. #Perhaps construct empty segment tree nodes? construct_children!(X, Query_low, Query_high, Current_low, Current_high, value) - #return? + #Next, we need to recompute the entire stack. + #Working in progress. + error("Working in progress.") + + + return end Current_mid = get_middle(Current_low,Current_high) @@ -220,24 +237,34 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu X = get_right_child(X) else #Time to set left range and set right range. + set_left_range!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node) + set_right_range!(get_right_child, Query_high, Current_mid+1, Current_high, value, stack, empty_node) + #recompute the entire stack. The same way as above. + error("Working in progress.") #Working in progress. end end end -function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value) + + +function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node) end -function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value) +function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node) end -function construct_children!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value) - +function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) where {T<:Segment_tree_node} + left = T(nothing, get_element_identity(X), get_element_identity(X)) + right = T(nothing, get_element_identity(X), get_element_identity(X)) + X.child_nodes = (left,right) end +#= function propagate_density!(X::Segment_tree_node) get_left_child(X).density = get_right_child(X).density -end \ No newline at end of file +end +=# \ No newline at end of file From 9d7190c7f34381f28f323111e221155ff62a1de0 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 1 Jun 2022 18:03:23 +0700 Subject: [PATCH 59/91] Update segment_tree.jl --- src/segment_tree.jl | 65 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 21dec90de..3474c79de 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -212,22 +212,37 @@ construct_children! construct_left_children! construct_right_children! =# +function reconstruct_stack!(stack, empty_node, stack_begin, stack_end) + for i in stack_end:-1:stack_begin + node = stack[i] + node.value = get_op(node)(get_left_child(node).value,get_right_child(node).value) + stack[i] = empty_node + end +end + function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) #Working in progress. + stack_top = 1 #The top of the stack where you can change. while true if is_terminal(X) #Do something about it to set the range correctly. #Perhaps construct empty segment tree nodes? + #Push the final into the stack. construct_children!(X, Query_low, Query_high, Current_low, Current_high, value) + #What to do here? Not sure. + + reconstruct_stack!(stack,empty_node,1,stack_top-1) #Next, we need to recompute the entire stack. + #Please ensure that X is not in the stack. (Since this will be handled separately.) #Working in progress. error("Working in progress.") return end - + stack[stack_top] = X + stack_top += 1 Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid Current_high = Current_mid @@ -238,8 +253,9 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu else #Time to set left range and set right range. set_left_range!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node) - set_right_range!(get_right_child, Query_high, Current_mid+1, Current_high, value, stack, empty_node) - #recompute the entire stack. The same way as above. + set_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node) + reconstruct_stack!(stack,empty_node,1,stack_top-1) + #recompute the entire stack. This time with X. error("Working in progress.") #Working in progress. end @@ -250,17 +266,56 @@ end function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node) - + while true + if is_terminal(X) + #Something here? + end + #Push the stack here? + Current_mid = get_middle(Current_low,Current_high) + if Query_low > Current_mid + #Not doing anything here? + Current_low = Current_mid+1 + X = get_right_child(X) + else + #Do something here? + Current_high = Current_mid + X = get_left_child(X) + end + end end function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node) - + while true + if is_terminal(X) #Is the terminal node. + #Something here? + end + + Current_mid = get_middle(Current_low,Current_high) + if Query_high <= Current_mid + #No need for anything? (Since the rest is out of range.) + Current_high = Current_mid + X = get_left_child(X) + else + #Same logic, something here? + Current_low = Current_mid+1 + X = get_right_child(X) + end + end end +function set_entire_range!(X::Segment_tree_node, range, value) + X.density = value + X.value = get_iterated_op(X)(range, value) +end function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) where {T<:Segment_tree_node} + #= + Supposedly start? + Should Implicitly be here. left = T(nothing, get_element_identity(X), get_element_identity(X)) right = T(nothing, get_element_identity(X), get_element_identity(X)) X.child_nodes = (left,right) + =# + end #= From e8d7549ddb5828541dea283ca33db99d3d9fc28e Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 3 Jun 2022 18:07:52 +0700 Subject: [PATCH 60/91] Trying to make set_range. --- src/segment_tree.jl | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 3474c79de..cbd540328 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -229,7 +229,7 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu #Do something about it to set the range correctly. #Perhaps construct empty segment tree nodes? #Push the final into the stack. - construct_children!(X, Query_low, Query_high, Current_low, Current_high, value) + construct_children!(X, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) #What to do here? Not sure. reconstruct_stack!(stack,empty_node,1,stack_top-1) @@ -252,8 +252,8 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu X = get_right_child(X) else #Time to set left range and set right range. - set_left_range!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node) - set_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node) + set_left_range!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) + set_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) reconstruct_stack!(stack,empty_node,1,stack_top-1) #recompute the entire stack. This time with X. error("Working in progress.") @@ -265,12 +265,18 @@ end -function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node) +function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) while true if is_terminal(X) + construct_left_children!(X,Query_low,Current_low,Current_high,value,stack,empty_node, stack_top) + reconstruct_stack!(stack,empty_node,1,stack_top-1) + #Next, we need to recompute the entire stack. + #Please ensure that X is not in the stack. (Since this will be handled separately.) #Something here? end #Push the stack here? + stack[stack_top] = X + stack_top += 1 Current_mid = get_middle(Current_low,Current_high) if Query_low > Current_mid #Not doing anything here? @@ -284,12 +290,16 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h end end -function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node) +function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) while true if is_terminal(X) #Is the terminal node. - #Something here? + #Same logic. + construct_right_children!(X,Query_high,Current_low,Current_high,value,stack,empty_node,stack_top) + reconstruct_stack!(stack,empty_node,1,stack_top-1) end + stack[stack_top] = X + stack_top += 1 Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid #No need for anything? (Since the rest is out of range.) @@ -307,7 +317,7 @@ function set_entire_range!(X::Segment_tree_node, range, value) X.density = value X.value = get_iterated_op(X)(range, value) end -function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) where {T<:Segment_tree_node} +function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} #= Supposedly start? Should Implicitly be here. @@ -318,6 +328,16 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end +function construct_left_children!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) + +end +function construct_right_children!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) + #Something here? +end + +function construct_entire_range!() + #Hmm? +end #= function propagate_density!(X::Segment_tree_node) get_left_child(X).density = get_right_child(X).density From 975f62df8b4cabb8092a13606291b944ce5d66b9 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:08:40 +0700 Subject: [PATCH 61/91] Update segment_tree.jl --- src/segment_tree.jl | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index cbd540328..f70fdfd41 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -4,7 +4,25 @@ It should be made available as part of the (MIT-licensed) Datastructures.jl pack Feel free to use or extend this code. =# -#cd("Data_structure) + +#= +Note from the author: This has only barely touched the surface of its capability. +For example, amortizing run-time costs would allow certain operations to happen on a specially initialized segment tree. +Moreover, if the density is propagated at every step, and the underlying type has commutative property, additive would be possible. +There are also 2d variants (Segment tree whose nodes are themselves segment tree) and so on. +These are complicated. +This is the crown jewel of competitive programming solving many challenging problems. The author tries to bring it out to the wider world +to bring it to the full potential. + +This code may be better optimized than code with explicit recursion found in many competitive programming codes, but it may still lacks many +good optimizations such as unrolling small leaves into a single array and so on. + +It's bittersweet really. The author quit competitive programming because there is no way the author could've implemented such a +complicated algorithm in time in a limited situation. Still, this is very useful. +=# + +#To test this package. +#cd("Data_structure") #(package) activate . abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end abstract type Abstractsegmenttree{node_type} end @@ -284,6 +302,8 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h X = get_right_child(X) else #Do something here? + #Set range using Range and value. + set_entire_range!(get_right_child(X),Current_high-Current_mid,value) Current_high = Current_mid X = get_left_child(X) end @@ -306,7 +326,8 @@ function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current Current_high = Current_mid X = get_left_child(X) else - #Same logic, something here? + #Same logic? + set_entire_range!(get_left_child(X), Current_mid-Current_low+1, value) Current_low = Current_mid+1 X = get_right_child(X) end @@ -316,6 +337,7 @@ end function set_entire_range!(X::Segment_tree_node, range, value) X.density = value X.value = get_iterated_op(X)(range, value) + X.child_nodes = nothing end function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} #= From e33f46231e7aab6a1841533e4f8ccfc05d368a83 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:11:59 +0700 Subject: [PATCH 62/91] Update segment_tree.jl --- src/segment_tree.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index f70fdfd41..04a031118 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -17,8 +17,8 @@ to bring it to the full potential. This code may be better optimized than code with explicit recursion found in many competitive programming codes, but it may still lacks many good optimizations such as unrolling small leaves into a single array and so on. -It's bittersweet really. The author quit competitive programming because there is no way the author could've implemented such a -complicated algorithm in time in a limited situation. Still, this is very useful. +Let us bring the full potential out of this surprisingly general set of algortihm. +Knowledge of abstract algebra should be put to use. =# #To test this package. From 79f952d42b7b8324265e6617cd30b0f4e177c309 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Fri, 3 Jun 2022 20:12:17 +0700 Subject: [PATCH 63/91] Update segment_tree.jl --- src/segment_tree.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 04a031118..46ab0c8be 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -254,7 +254,6 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu #Next, we need to recompute the entire stack. #Please ensure that X is not in the stack. (Since this will be handled separately.) #Working in progress. - error("Working in progress.") return @@ -274,7 +273,6 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu set_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) reconstruct_stack!(stack,empty_node,1,stack_top-1) #recompute the entire stack. This time with X. - error("Working in progress.") #Working in progress. end From 3e0548885b7dec97d0bf3cb89895699eb6e4a569 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 8 Jun 2022 17:22:18 +0700 Subject: [PATCH 64/91] Update segment_tree.jl --- src/segment_tree.jl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 46ab0c8be..44f477db1 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -24,6 +24,13 @@ Knowledge of abstract algebra should be put to use. #To test this package. #cd("Data_structure") #(package) activate . + + + +#= +TODO: Consider adding cases of equal as a separate case. +=# + abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end abstract type Abstractsegmenttree{node_type} end get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype @@ -181,7 +188,9 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi # get operation between the right (previously accumulated answer) and the left (this node) return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) end - + #If this new decision pass, compare Query_low with Current_mid+1. + #3 cases. Exact overlap, partial overlap, and no overlap. + Current_mid = get_middle(Current_low,Current_high) if Query_low > Current_mid Current_low = Current_mid+1 @@ -321,6 +330,9 @@ function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid #No need for anything? (Since the rest is out of range.) + #If Query_high == Current_mid (This means that it is EXACTLY half) + #Maybe do something else? Maybe end it right here? + Current_high = Current_mid X = get_left_child(X) else From 36459d59b2e8805e1f978b2688bc47e9132f4134 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 13 Jun 2022 22:05:07 +0700 Subject: [PATCH 65/91] Update segment_tree.jl --- src/segment_tree.jl | 76 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 44f477db1..364ac32ae 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -192,9 +192,14 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi #3 cases. Exact overlap, partial overlap, and no overlap. Current_mid = get_middle(Current_low,Current_high) - if Query_low > Current_mid - Current_low = Current_mid+1 + decision_boundary = Current_mid+1 + if Query_low > decision_boundary + #Current_low = Current_mid+1 This is equivalent. + Current_low = decision_boundary X = get_right_child(X) + elseif Query_low == decision_boundary + #Wait a bit. + return get_op(X)(answer,get_entire_range(get_right_child(X))) else #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) (Except that the 2nd argument wasn't needed.) answer = get_op(X)(answer,get_entire_range(get_right_child(X))) @@ -213,11 +218,14 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h end Current_mid = get_middle(Current_low,Current_high) - if Query_high <= Current_mid - Current_high = Current_mid + decision_boundary = Current_mid + #We write logics about variables. Let the compiler micro-optimize the registries. + if Query_high < decision_boundary + Current_high = decision_boundary X = get_left_child(X) + elseif Query_high == decision_boundary + return get_op(X)(get_entire_range(get_left_child(X)), answer) else - #Same logic. answer = get_op(X)(get_entire_range(get_left_child(X)), answer) Current_low = Current_mid+1 X = get_right_child(X) @@ -290,23 +298,28 @@ end -function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) +function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) + stack_top = old_stack_top while true if is_terminal(X) construct_left_children!(X,Query_low,Current_low,Current_high,value,stack,empty_node, stack_top) - reconstruct_stack!(stack,empty_node,1,stack_top-1) - #Next, we need to recompute the entire stack. - #Please ensure that X is not in the stack. (Since this will be handled separately.) - #Something here? + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return end #Push the stack here? stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) - if Query_low > Current_mid - #Not doing anything here? - Current_low = Current_mid+1 + decision_boundary = Current_mid+1 + if Query_low > decision_boundary + #Same logic as get_left_range + Current_low = decision_boundary X = get_right_child(X) + elseif Query_low == decision_boundary + set_entire_range!(get_right_child(X),Current_high-Current_mid,value) + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + #reconstruct_stack + return else #Do something here? #Set range using Range and value. @@ -317,24 +330,32 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h end end -function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) +function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) + stack_top = old_stack_top while true if is_terminal(X) #Is the terminal node. #Same logic. construct_right_children!(X,Query_high,Current_low,Current_high,value,stack,empty_node,stack_top) - reconstruct_stack!(stack,empty_node,1,stack_top-1) + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return end stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) - if Query_high <= Current_mid + decision_boundary = Current_mid + if Query_high < decision_boundary #No need for anything? (Since the rest is out of range.) #If Query_high == Current_mid (This means that it is EXACTLY half) #Maybe do something else? Maybe end it right here? Current_high = Current_mid X = get_left_child(X) + elseif Query_high == decision_boundary + set_entire_range!(get_left_child(X), Current_mid-Current_low+1, value) + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + #reconstruct_stack + return else #Same logic? set_entire_range!(get_left_child(X), Current_mid-Current_low+1, value) @@ -349,7 +370,7 @@ function set_entire_range!(X::Segment_tree_node, range, value) X.value = get_iterated_op(X)(range, value) X.child_nodes = nothing end -function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} +function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} #= Supposedly start? Should Implicitly be here. @@ -357,14 +378,33 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h right = T(nothing, get_element_identity(X), get_element_identity(X)) X.child_nodes = (left,right) =# + stack_top = old_stack_top + old_density = X.density + while true + stack[stack_top] = X + stack_top += 1 + Current_mid = get_middle(Current_low,Current_high) + end + end function construct_left_children!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) - + stack_top = old_stack_top + while true + stack[stack_top] = X + stack_top += 1 + Current_mid = get_middle(Current_low,Current_high) + end end function construct_right_children!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) #Something here? + stack_top = old_stack_top + while true + stack[stack_top] = X + stack_top += 1 + Current_mid = get_middle(Current_low,Current_high) + end end function construct_entire_range!() From bf77117f2dd6e6293ccc5c44d34ea1bf3b642dbf Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sat, 18 Jun 2022 22:50:29 +0700 Subject: [PATCH 66/91] Update segment_tree.jl --- src/segment_tree.jl | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 364ac32ae..1bb186530 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -112,6 +112,7 @@ sizeof(X::Segment_tree) = X.size function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) head = Segment_tree_node{type, op, iterated_op, identity}() + head.value = head.density = identity empty_node = Segment_tree_node{type, op, iterated_op, identity}() stack = Vector(undef,65) for i in 1:65 @@ -384,6 +385,35 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) + if Query_high <= Current_mid + #Construct some children. + Current_high = Current_mid + left_child = T() + right_child = T() + right_child.value = right_child.density = old_density + X.child_nodes = (left_child, right_child) + X = get_left_child(X) + elseif Query_low > Current_mid + #Construct some children as well. + Current_high = Current_mid + left_child = T() + right_child = T() + left_child.value = left_child.density = old_density + X.child_nodes = (left_child, right_child) + X = get_left_child(X) + Current_low = Current_mid+1 + else + #Construct left and right children. + left_child = T() + right_child = T() + left_child.density = right_child.density = old_density + X.child_nodes = (left_child, right_child) + construct_left_range!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) + construct_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) + reconstruct_stack!(stack,empty_node,1,stack_top-1) + return + #recompute the entire stack. This time with X. + end end @@ -395,6 +425,7 @@ function construct_left_children!(X::Segment_tree_node, Query_low, Current_low, stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) + decision_boundary = Current_mid end end function construct_right_children!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) From a545edd65b8d44174fb574d09d9608ecdbd4c97b Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 19 Jun 2022 21:30:10 +0700 Subject: [PATCH 67/91] Update segment_tree.jl --- src/segment_tree.jl | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 1bb186530..bf23e107a 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -419,16 +419,44 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end -function construct_left_children!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) +function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} stack_top = old_stack_top while true stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) decision_boundary = Current_mid + if Query_low > decision_boundary + #Same logic as get_left_range but with new constructed children. + Current_low = decision_boundary + #Get new children. + left_child = T() + right_child = T() + set_entire_range!(left_child, Current_mid-Current_low,old_density) + #The left range is out of range and must be of old density + right_child.density = old_density + X = get_right_child(X) + #Now, this is happening again. + elseif Query_low == decision_boundary + #set_entire_range!(get_right_child(X),Current_high-Current_mid,value) + #This is a special condition where we can just set both left and right. + left_child = T() + right_child = T() + set_entire_range!(left_child, Current_mid-Current_low,old_density) + set_entire_range!(right_child, Current_high-Current_mid+1) + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + #reconstruct_stack + return + else + #Do something here? + #Set range using Range and value. + set_entire_range!(get_right_child(X),Current_high-Current_mid,value) + Current_high = Current_mid + X = get_left_child(X) + end end end -function construct_right_children!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) +function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} #Something here? stack_top = old_stack_top while true @@ -438,9 +466,6 @@ function construct_right_children!(X::Segment_tree_node, Query_high, Current_low end end -function construct_entire_range!() - #Hmm? -end #= function propagate_density!(X::Segment_tree_node) get_left_child(X).density = get_right_child(X).density From c091fc00aee61a368212a2021a5faadaa03bef50 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 19 Jun 2022 23:23:17 +0700 Subject: [PATCH 68/91] Update segment_tree.jl --- src/segment_tree.jl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index bf23e107a..9cffacd51 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -380,8 +380,9 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h X.child_nodes = (left,right) =# stack_top = old_stack_top - old_density = X.density + while true + old_density = X.density stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) @@ -390,7 +391,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_high = Current_mid left_child = T() right_child = T() - right_child.value = right_child.density = old_density + right_child.density = old_density X.child_nodes = (left_child, right_child) X = get_left_child(X) elseif Query_low > Current_mid @@ -398,7 +399,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_high = Current_mid left_child = T() right_child = T() - left_child.value = left_child.density = old_density + left_child.density = old_density X.child_nodes = (left_child, right_child) X = get_left_child(X) Current_low = Current_mid+1 @@ -422,6 +423,7 @@ end function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} stack_top = old_stack_top while true + old_density = X.density stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) @@ -435,6 +437,7 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va set_entire_range!(left_child, Current_mid-Current_low,old_density) #The left range is out of range and must be of old density right_child.density = old_density + X.child_nodes = (left_child,right_child) X = get_right_child(X) #Now, this is happening again. elseif Query_low == decision_boundary @@ -443,14 +446,18 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va left_child = T() right_child = T() set_entire_range!(left_child, Current_mid-Current_low,old_density) - set_entire_range!(right_child, Current_high-Current_mid+1) + set_entire_range!(right_child, Current_high-Current_mid+1, value) + X.child_nodes = (left_child,right_child) reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) #reconstruct_stack return else #Do something here? #Set range using Range and value. - set_entire_range!(get_right_child(X),Current_high-Current_mid,value) + left_child = T() + right_child = T() + left_child.density = + set_entire_range!(right_child, Current_high-Current_mid+1, value) Current_high = Current_mid X = get_left_child(X) end From 7adc876dbbd33438df6b7b3a26dcda95bff60fc8 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 00:07:33 +0700 Subject: [PATCH 69/91] Update segment_tree.jl --- src/segment_tree.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 9cffacd51..220b5a7ed 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -380,9 +380,9 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h X.child_nodes = (left,right) =# stack_top = old_stack_top - + old_density = X.density while true - old_density = X.density + #old_density = X.density stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) @@ -391,7 +391,8 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_high = Current_mid left_child = T() right_child = T() - right_child.density = old_density + #We still need to check for this thing. + set_entire_range!(right_child, Current_high-Current_mid+1, old_density) X.child_nodes = (left_child, right_child) X = get_left_child(X) elseif Query_low > Current_mid @@ -399,9 +400,9 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_high = Current_mid left_child = T() right_child = T() - left_child.density = old_density + set_entire_range!(left_child, Current_mid-Current_low, old_density) X.child_nodes = (left_child, right_child) - X = get_left_child(X) + X = get_right_child(X) Current_low = Current_mid+1 else #Construct left and right children. @@ -422,8 +423,8 @@ end function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} stack_top = old_stack_top + old_density = X.density while true - old_density = X.density stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) @@ -436,7 +437,6 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va right_child = T() set_entire_range!(left_child, Current_mid-Current_low,old_density) #The left range is out of range and must be of old density - right_child.density = old_density X.child_nodes = (left_child,right_child) X = get_right_child(X) #Now, this is happening again. @@ -456,7 +456,6 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va #Set range using Range and value. left_child = T() right_child = T() - left_child.density = set_entire_range!(right_child, Current_high-Current_mid+1, value) Current_high = Current_mid X = get_left_child(X) From 5e36349e8fac649cc4fcdddc4edf99ca3148e1fe Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 00:12:39 +0700 Subject: [PATCH 70/91] Update segment_tree.jl --- src/segment_tree.jl | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 220b5a7ed..b256b6289 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -388,22 +388,21 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid #Construct some children. - Current_high = Current_mid left_child = T() right_child = T() - #We still need to check for this thing. set_entire_range!(right_child, Current_high-Current_mid+1, old_density) X.child_nodes = (left_child, right_child) + Current_high = Current_mid X = get_left_child(X) elseif Query_low > Current_mid #Construct some children as well. - Current_high = Current_mid + left_child = T() right_child = T() set_entire_range!(left_child, Current_mid-Current_low, old_density) X.child_nodes = (left_child, right_child) - X = get_right_child(X) Current_low = Current_mid+1 + X = get_right_child(X) else #Construct left and right children. left_child = T() @@ -421,7 +420,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end -function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} +function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} stack_top = old_stack_top old_density = X.density while true @@ -438,6 +437,7 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va set_entire_range!(left_child, Current_mid-Current_low,old_density) #The left range is out of range and must be of old density X.child_nodes = (left_child,right_child) + Current_low = Current_mid+1 X = get_right_child(X) #Now, this is happening again. elseif Query_low == decision_boundary @@ -462,13 +462,27 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va end end end -function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) where {T<:Segment_tree_node} +function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} #Something here? stack_top = old_stack_top while true stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) + decision_boundary = Current_mid + if Query_high < decision_boundary + #If Query_high == Current_mid (This means that it is EXACTLY half) + + Current_high = Current_mid + X = get_left_child(X) + elseif Query_high == decision_boundary + + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + else + Current_low = Current_mid+1 + X = get_right_child(X) + end end end From b5d9b09b546611c1cab251c8147c8e65fb8abcd6 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 00:43:12 +0700 Subject: [PATCH 71/91] Update segment_tree.jl --- src/segment_tree.jl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index b256b6289..8b91b18ae 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -465,6 +465,7 @@ end function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} #Something here? stack_top = old_stack_top + old_density = X.density while true stack[stack_top] = X stack_top += 1 @@ -472,14 +473,25 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, decision_boundary = Current_mid if Query_high < decision_boundary #If Query_high == Current_mid (This means that it is EXACTLY half) - + left_child = T() + right_child = T() + set_entire_range!(right_child, Current_high-Current_mid+1, old_density) + X.child_nodes = (left_child,right_child) Current_high = Current_mid X = get_left_child(X) elseif Query_high == decision_boundary - + left_child = T() + right_child = T() + set_entire_range!(left_child, Current_mid-Current_low,value) + set_entire_range!(right_child, Current_high-Current_mid+1, old_density) + X.child_nodes = (left_child,right_child) reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return else + left_child = T() + right_child = T() + set_entire_range!(left_child, Current_high-Current_mid+1, value) + X.child_nodes = (left_child,right_child) Current_low = Current_mid+1 X = get_right_child(X) end From 59f7d05cad31044648a1adce91068596fe98769c Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 00:44:19 +0700 Subject: [PATCH 72/91] Update segment_tree.jl --- src/segment_tree.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 8b91b18ae..bb6ab339e 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -502,4 +502,5 @@ end function propagate_density!(X::Segment_tree_node) get_left_child(X).density = get_right_child(X).density end -=# \ No newline at end of file +=# + From 7e92312f3a8172e3ea9a770107764d33f4d16536 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 21:43:28 +0700 Subject: [PATCH 73/91] Changing something. --- src/DataStructures.jl | 3 ++- test/runtests.jl | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/DataStructures.jl b/src/DataStructures.jl index 11c0804ad..cea3e4ad4 100644 --- a/src/DataStructures.jl +++ b/src/DataStructures.jl @@ -48,6 +48,7 @@ module DataStructures export MultiDict, enumerateall export RobinDict + export Segment_tree, get_range, set_range! export OrderedRobinDict, isordered export SwissDict @@ -77,7 +78,7 @@ module DataStructures include("int_set.jl") include("fenwick.jl") - + include("segment_tree.jl") include("list.jl") include("mutable_list.jl") include("balanced_tree.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 33927d2a4..481365961 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -32,6 +32,7 @@ tests = ["deprecations", "fenwick", "robin_dict", "ordered_robin_dict", + "segment_tree", "dibit_vector", "swiss_dict", "avl_tree", From 5c2705ea2e02fbdf0b967526898ebb3d73ec51b0 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 21:56:51 +0700 Subject: [PATCH 74/91] Remove backups. Gone. Snap. They've done their work. Nothing personal. Text files don't feel. --- src/Segment_tree_backup_2.jl | 201 ---------------------------- src/segment_tree_backup.jl | 253 ----------------------------------- 2 files changed, 454 deletions(-) delete mode 100644 src/Segment_tree_backup_2.jl delete mode 100644 src/segment_tree_backup.jl diff --git a/src/Segment_tree_backup_2.jl b/src/Segment_tree_backup_2.jl deleted file mode 100644 index a79314a1d..000000000 --- a/src/Segment_tree_backup_2.jl +++ /dev/null @@ -1,201 +0,0 @@ -#= -Author: Alice Roselia. -It should be made available as part of the (MIT-licensed) Datastructures.jl package. -Feel free to use or extend this code. -=# - -#cd("Data_structure) -#(package) activate . -abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end -abstract type Abstractsegmenttree{node_type} end -get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype -get_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op -get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op - - -get_middle(low, high) = div(low+high,2) - -function repeat_op(base,time::Integer, op::Function) - #Hopefully segment tree not larger than 64. Otherwise, big number segment tree may be needed. - Iterations = convert(UInt,time) - #Find trailing zeros. - baseline = base - for i in 1:trailing_zeros(Iterations) - baseline = op(baseline,baseline) - end - Iterations = Iterations>>trailing_zeros(Iterations) - - #Operate to get to the baseline. - #baseline = #Working in progress. - - #Then, you can iterate. - final_value = baseline - while (Iterations!=0) - Iterations>>=1 - baseline = op(baseline,baseline) - if isodd(Iterations) - final_value = op(final_value,baseline) - end - end - #Something - - - return final_value -end - -#Specialized cases for repeat_op. - -repeat_op(base::Number, time::Integer, ::typeof(+)) = base*time -repeat_op(base::Number, time::Integer, ::typeof(*)) = base^time -repeat_op(base::T, time::Integer, ::typeof(xor)) where {T<:Integer} = iseven(time) ? zero(T) : base -repeat_op(base::T, ::Integer, ::typeof(&)) = base -repeat_op(base::T, ::Integer, ::typeof(|)) = base - -#I luv multiple dispatch! - -#Identity is required. -struct artificial_identity end - - -get_identity(x,y) = artificial_identity() -get_identity(::Type{T}, ::typeof(+)) where {T<:Number} = zero(T) -get_identity(::Type{T}, ::typeof(*)) where {T<:Number} = one(T) -operation_with_identity(f) = (x,y)-> (x===artificial_identity()) ? y : (y===artificial_identity() ? x : f(x,y)) -repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity()) ? artificial_identity() : f(base,time) - - -mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} - child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op, identity}},Nothing} - #Either both children are valid or none is valid. - value::Dtype - density::Dtype - #Implicitly have information about where it represents. - function Segment_tree_node{Dtype,Op,iterated_op,identity}() where {Dtype,Op,iterated_op,identity} - return new{Dtype,Op,iterated_op,identity}(nothing) - end -end -get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity - -struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{node_type} - size::Int - head::node_type -end -sizeof(X::Segment_tree) = X.size -function Segment_tree(type, size, op::Function, iterated_op::Function, identity) - size = convert(Int,size) - head = Segment_tree_node{type, op, iterated_op, identity}() - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head) -end - -function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) - #A bit annoying but local scope must take place. - new_op = op - if iterated_op===nothing - new_iterated_op = (x,y)->repeat_op(x,y,op) - else - new_iterated_op = iterated_op - end - if identity === nothing - new_identity = get_identity(type,op) - if new_identity === artificial_identity() - type = Union{type,artificial_identity} - new_op = operation_with_identity(op) - new_iterated_op = repeat_op_with_identity(new_iterated_op) - end - else - new_identity = identity - end - return Segment_tree(type,size,new_op,new_iterated_op,new_identity) -end - - - -@inline function get_range(X::Segment_tree,low,high) - - #The reason this is inlined is because there is only ONE line. - #This is only a wrapping call to another function which is NOT inlined. - return get_range(X.head,low,high,1,sizeof(X)) -end -get_left_child(X::Segment_tree_node) = X.child_nodes[1] -get_right_child(X::Segment_tree_node) = X.child_nodes[2] -function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) - while true - if X.child_nodes === nothing #Is the terminal node. - return get_iterated_op(X)(X.density, Query_high-Query_low+1) - end - - Current_mid =get_middle(Current_low,Current_high) - if Query_high <= Current_mid - Current_high = Current_mid - X = get_left_child(X) - else if Query_low > Current_mid - Current_low = Current_mid+1 - X = get_right_child(X) - else - return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_mid),get_right_range(get_right_child(X),Query_high, Current_mid+1,Current_high)) - #If this branch is taken before the terminal node is reached, it means that there is a "split". - #This can split only once. This information avoids excessive checks and recursion. - end - end -end - -function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) - answer = get_element_identity(X) - while true - if X.child_nodes === nothing #Is the terminal node. - #Hopefully, this is correct. - # get operation between the right (previously accumulated answer) and the left (this node) - return get_op(X)(get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) - end - - Current_mid = get_middle(Current_low,Current_high) - if Query_low > Current_mid - Current_low = Current_mid+1 - X = get_right_child(X) - else - #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) (Except that the 2nd argument wasn't needed.) - answer = get_op(X)(answer,get_entire_range(get_right_child(X))) - Current_high = Current_mid - X = get_left_child(X) - end - end - -end - -function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) - answer = get_element_identity(X) - while true - if X.child_nodes === nothing #Is the terminal node. - return get_op(X)(answer,get_iterated_op(X)(X.density, Query_high-Current_low+1)) - end - - Current_mid = get_middle(Current_low,Current_high) - if Query_high <= Current_mid - Current_high = Current_mid - X = get_left_child(X) - else - #Same logic. - answer = get_op(X)(get_entire_range(get_left_child(X)), answer) - Current_low = Current_mid+1 - X = get_right_child(X) - end - #Working in progress. - end -end -#= -Get rid of this insanity. -#inline? -@inline function get_entire_range(X::Segment_tree_node, range) - #Working in progress. - if X.child_nodes === nothing - #Should this density thing be put at this level? - return get_iterated_op(X)(X.density, range) - else - return X.value - end -end -=# - -@inline function get_entire_range(X::Segment_tree_node) - return X.value -end \ No newline at end of file diff --git a/src/segment_tree_backup.jl b/src/segment_tree_backup.jl deleted file mode 100644 index db306e8f3..000000000 --- a/src/segment_tree_backup.jl +++ /dev/null @@ -1,253 +0,0 @@ -#= -Author: Alice Roselia. -It should be made available as part of the (MIT-licensed) Datastructures.jl package. -Feel free to use or extend this code. -=# - -#cd("Data_structure) -#(package) activate . - - - -abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end -abstract type Abstractsegmenttree{node_type} end -Standard_Field = Union{Real, Complex} -#= -Segment trees have the following traits. -1) can_add_range: either Val{True} or Val{False}. -2) can_change_range: either Val{True} or Val{False}. -3) is_functional: either Val{True} or Val{False} - -Dispatching will have "valid". Dispatching for invalid would be error. -=# -can_add_range(::Abstractsegmenttree)= false; -can_change_range(::Abstractsegmenttree) = true; -is_functional(::Abstractsegmenttree) = false; -#Convenience so you don't have to use arguments every time. -get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype -get_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op -get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op - - -function repeat_op(base,time::Integer, op::Function) - #Hopefully segment tree not larger than 64. Otherwise, big number segment tree may be needed. - Iterations = convert(UInt,time) - #Find trailing zeros. - baseline = base - for i in 1:trailing_zeros(Iterations) - baseline = op(baseline,baseline) - end - Iterations = Iterations>>trailing_zeros(Iterations) - - #Operate to get to the baseline. - #baseline = #Working in progress. - - #Then, you can iterate. - final_value = baseline - while (Iterations!=0) - Iterations>>=1 - baseline = op(baseline,baseline) - if isodd(Iterations) - final_value = op(final_value,baseline) - end - end - #Something - - - return final_value -end - - - -mutable struct Segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} - size::UInt64 - head::node_type -end -function Segment_tree(size::Number,Dtype::Type,op::Function, iterated_op::Function) - newsize = convert(UInt64,size) - node_type = Segment_tree_node{Dtype,op,iterated_op} - return Segment_tree{node_type}(newsize, node_type()) -end - -sizeof(X::Abstractsegmenttree) = X.size -get_head(X::Abstractsegmenttree) = X.head -Segment_tree(size::Number, T::Type, op::Function) = Segment_tree(size, T, op, (x,y)->repeat_op(x,y,op)) -Segment_tree(size::Number,::Type{T}, ::typeof(+)) where {T<:Standard_Field} = Segment_tree(size,T,+,*) -Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(+)) where {T<:Standard_Field,N} = Segment_tree(size,Array{T,N},+,*) -Segment_tree(size::Number,::Type{T}, ::typeof(*)) where {T<:Standard_Field} = Segment_tree(size,T,*,^) -Segment_tree(size::Number,::Type{Array{T,N}}, ::typeof(*)) where {T<:Standard_Field,N} = Segment_tree(size,Array{T,N},*,^) - -struct functional_segment_tree{node_type<:Abstractsegmenttreenode}<:Abstractsegmenttree{node_type} - size::UInt64 - head::node_type -end -is_functional(functional_segment_tree) = true - - -mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} - child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op, identity}},Nothing} - #Either both children are valid or none is valid. - value::Dtype - density::Dtype - #Implicitly have information about where it represents. - function Segment_tree_node() - return new{Dtype,Op,iterated_op,identity}(nothing) - end -end - -mutable struct Segment_tree_node_without_identity{Dtype,Op,iterated_op}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} - child_nodes::Union{NTuple{2,Segment_tree_node_without_identity{Dtype, Op, iterated_op}},Nothing} - #Either both children are valid or none is valid. - #This variant will throw an error instead of returning an identity. - #This is not very recommended, as complexity is required to bypass this. - value::Union{Dtype,Nothing} - density::Union{Dtype,Nothing} - function Segment_tree_node_without_identity() - return new{Dtype,Op,iterated_op}(nothing) - end -end - - - -function Segment_tree_node(Dtype::Type{T}, Op::Function, iterated_op::Function, identity::T) - return Segment_tree_node{Dtype,Op,iterated_op,identity}() -end - -get_identity(X,op::Function) = get_identity(typeof(X),op) -get_identity(::Type,::Function) = nothing -get_identity(::Type{X},typeof(+)) where {X<:Standard_Field} = zero(X) -get_identity(::Type{X},typeof(*)) where {X<:Standard_Field} = one(X) -function Segment_tree_node(Dtype::Type, Op::Function, iterated_op::Function) - if get_identity(Dtype,Op) isa Nothing - #Consider this solution. - #Workaround_op(x,y) = ifelse(x==nothing, y, ifelse(y==nothing,x,Op(x,y))) - #Workaround_iterated_op(x,y) = ifelse(x==nothing, nothing, iterated_op(x,y)) - return Segment_tree_node_without_identity{Dtype,Op,iterated_op}() - else - return Segment_tree_node{Dtype,Op,iterated_op,get_identity(Dtype,Op)}() - end -end -get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity -get_element_identity(::Segment_tree_node_without_identity) = nothing - -Standard_Segment_tree_node = Union{Segment_tree_node,Segment_tree_node_without_identity} #Standard meaning not every Segment_tree_node has this. -#TODO: consider refactoring this into its abstract type instead of as union. - -get_left_child(X::Standard_Segment_tree_node) = X.child_nodes[1] -get_right_child(X::Standard_Segment_tree_node) = X.child_nodes[2] - - - -function get_range(X::Abstractsegmenttree, low, high) - # get the reduce(Op, X[i] for all low<=i<=high) - return get_range(get_head(X),low,high, 1, sizeof(X)) -end - -function set_range!(X::Abstractsegmenttree, low,high) - set_range!(get_head(X),low,high,1,sizeof(X)) -end - - - -#Implement get_op, get_iterated_op, etc... - -function get_range(X::Standard_Segment_tree_node, Query_low, Query_high, Current_low, Current_high) - - #while the tree is still not at splitting point - #if on low - #Go down low path. - #else - #Go down high path. - #end - #end - #Split into two functions, ones where you only care about prefix, and the other where you only care about suffix. - while true - if X.child_nodes == nothing - return get_iterated_op(X)(X.density, Query_high-Query_low+1) - end - - Current_mid = div(Current_low+Current_high,2) - if Query_high <= Current_mid - Current_high = Current_mid - X = get_left_child(X) - else if Query_low > Current_mid - Current_low = Current_mid+1 - X = get_right_child(X) - else - return get_op(X)(get_left_range(get_left_child(X), Query_low, Current_low,Current_high),get_right_range(get_right_child(X),Query_high, Current_low,Current_high)) - #Working in progress. - end - end -end - -function get_entire_range(X::Standard_Segment_tree_node, range) - #Working in progress. - if X.child_nodes == nothing - return get_iterated_op(X)(X.density, range) - else - return X.value - end -end - -function get_left_range(X::Standard_Segment_tree_node, Query_low, Current_low, Current_high) - answer = get_element_identity(X) - while true - if X.child_nodes == nothing - return (get_iterated_op(X)(X.density, Current_high-Query_low+1), answer) - end - - Current_mid = div(Current_low+Current_high,2) - if Query_low > Current_mid - Current_low = Current_mid+1 - X = get_right_child(X) - else - answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) - Current_high = Current_mid - X = get_left_child(X) - end - #Working in progress. - end - -end - -function get_right_range(X::Standard_Segment_tree_node, Query_high, Current_low,Current_high) - answer = get_element_identity(X) - while true - if X.child_nodes == nothing - return - end - - Current_mid = div(Current_low+Current_high,2) - if Query_high <= Current_mid - Query_high = Current_mid - X = get_left_child(X) - else - answer = get_op(X)(get_entire_range(get_left_child(X),Current_mid-Current_low+1), answer) - Current_low = Current_mid+1 - X = get_right_child(X) - end - #Working in progress. - end -end - -function set_range!(X::Standard_Segment_tree_node, Query_low, Query_high, Current_low, Current_high) - while true - if X.child_nodes == nothing - #Do something about it to set the range correctly. - #Perhaps construct empty segment tree nodes? - end - - Current_mid = div(Current_low+Current_high,2) - if Query_high <= Current_mid - Current_high = Current_mid - X = get_left_child(X) - else if Query_low > Current_mid - Current_low = Current_mid+1 - X = get_right_child(X) - else - #Time to set left range and set right range. - #Working in progress. - end - - end -end \ No newline at end of file From 55e527a541bb18ace175d7c6a5b562da0e7851bf Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 22:09:43 +0700 Subject: [PATCH 75/91] Update DataStructures.jl --- src/DataStructures.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/DataStructures.jl b/src/DataStructures.jl index cea3e4ad4..b21a5bd30 100644 --- a/src/DataStructures.jl +++ b/src/DataStructures.jl @@ -48,7 +48,6 @@ module DataStructures export MultiDict, enumerateall export RobinDict - export Segment_tree, get_range, set_range! export OrderedRobinDict, isordered export SwissDict @@ -74,11 +73,13 @@ module DataStructures include("default_dict.jl") include("dict_support.jl") include("trie.jl") - include("int_set.jl") - include("fenwick.jl") + include("segment_tree.jl") + + export Segment_tree, get_range, set_range! + include("list.jl") include("mutable_list.jl") include("balanced_tree.jl") From 0dec0c88cf69e9038029b23130cb216f7909c404 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 20 Jun 2022 22:11:21 +0700 Subject: [PATCH 76/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 8ad6b5ab1..f662b5794 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -39,7 +39,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "segment_tree" begin @testset "Add" begin - X1 = Segment_tree(100,UInt64,Base.:+) + X1 = Segment_tree(UInt64,100,Base.:+) a = zeros(UInt64, 100) change_range!(X1, 3,37,53) change_range!(X1, 9,23,45) @@ -56,7 +56,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. - X1 = Segment_tree(10000,UInt64, Base.:+) + X1 = Segment_tree(UInt64,10000, Base.:+) X2 = zeros(UInt64, 10000) for i in 1:10000 a = rand(1:10000) @@ -71,7 +71,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, end @testset "Xor_trial" begin - X1 = Segment_tree(10000,UInt64, xor) + X1 = Segment_tree(UInt64,10000, xor) X2 = zeros(UInt64, 10000) for i in 1:10000 a = rand(1:10000) @@ -87,7 +87,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "3x3_matrix_multiplication" begin #Float/etc should work fine as well. Just don't want to deal with precision issues. - X1 = Segment_tree(1000,Array{UInt64,2},*) + X1 = Segment_tree(Array{UInt64,2},1000,*) identity_matrix = zeros(UInt64,(3,3)) identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 #Vector of vector may not be the most efficient, but it should work without problem. From 84f3f64aac8cca1b60a9d0a9c0484ddeb71a9222 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sat, 2 Jul 2022 19:49:29 +0700 Subject: [PATCH 77/91] Fixing many bugs. I've fixed many bugs. Should only have a few left now. --- src/segment_tree.jl | 58 +++++++++++++++++++++++++-------------- test/test_segment_tree.jl | 31 +++++++++++---------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index bb6ab339e..ebbf9301e 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -85,6 +85,7 @@ struct artificial_identity end get_identity(x,y) = artificial_identity() get_identity(::Type{T}, ::typeof(+)) where {T<:Number} = zero(T) get_identity(::Type{T}, ::typeof(*)) where {T<:Number} = one(T) +get_identity(::Type{T}, ::typeof(xor)) where {T<:Integer} = zero(T) operation_with_identity(f) = (x,y)-> (x===artificial_identity()) ? y : (y===artificial_identity() ? x : f(x,y)) repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity()) ? artificial_identity() : f(base,time) @@ -108,6 +109,7 @@ struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{n stack::Vector{node_type} empty_node::node_type end +get_head(X::Segment_tree) = X.head sizeof(X::Segment_tree) = X.size function Segment_tree(type, size, op::Function, iterated_op::Function, identity) size = convert(Int,size) @@ -145,7 +147,7 @@ end @inline function get_range(X::Segment_tree,low,high) - + println("get range called from head from ", low, " to ", high) #The reason this is inlined is because there is only ONE line. #This is only a wrapping call to another function which is NOT inlined. return get_range(X.head,low,high,1,sizeof(X)) @@ -154,7 +156,9 @@ end @inline function set_range!(X::Segment_tree, low, high, value) #Same logic. Wrap the call. #The utility memories are here. + println("Set range called from head from ", low, " to ", high) set_range!(get_head(X),low,high,1,sizeof(X), value, X.stack, X.empty_node) + println("ending set range query") end get_left_child(X::Segment_tree_node) = X.child_nodes[1] @@ -182,6 +186,7 @@ function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Cur end function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) + println("get_left_range called from ", Current_low, " to ", Current_high) answer = get_element_identity(X) while true if is_terminal(X) #Is the terminal node. @@ -212,6 +217,7 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi end function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) + println("get_right_range called from ", Current_low, " to ", Current_high) answer = get_element_identity(X) while true if is_terminal(X) #Is the terminal node. @@ -249,6 +255,7 @@ construct_left_children! construct_right_children! =# function reconstruct_stack!(stack, empty_node, stack_begin, stack_end) + println("Debugging: reconstructing stack from ",stack_begin," to ", stack_end) for i in stack_end:-1:stack_begin node = stack[i] node.value = get_op(node)(get_left_child(node).value,get_right_child(node).value) @@ -291,7 +298,8 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu set_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) reconstruct_stack!(stack,empty_node,1,stack_top-1) #recompute the entire stack. This time with X. - #Working in progress. + #Does it work now? IDK. + return end end @@ -300,8 +308,13 @@ end function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) + println("set left range called from ", Current_low, " to ", Current_high) stack_top = old_stack_top while true + + + + if is_terminal(X) construct_left_children!(X,Query_low,Current_low,Current_high,value,stack,empty_node, stack_top) reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) @@ -332,12 +345,13 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h end function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) + println("set right range called from ", Current_low, " to ", Current_high) stack_top = old_stack_top while true if is_terminal(X) #Is the terminal node. #Same logic. construct_right_children!(X,Query_high,Current_low,Current_high,value,stack,empty_node,stack_top) - reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + #reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return end @@ -368,10 +382,11 @@ end function set_entire_range!(X::Segment_tree_node, range, value) X.density = value - X.value = get_iterated_op(X)(range, value) + X.value = get_iterated_op(X)(value, range) X.child_nodes = nothing end function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} + println("Construct children called from ", Current_low, " to ", Current_high) #= Supposedly start? Should Implicitly be here. @@ -390,7 +405,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h #Construct some children. left_child = T() right_child = T() - set_entire_range!(right_child, Current_high-Current_mid+1, old_density) + set_entire_range!(right_child, Current_high-Current_mid, old_density) X.child_nodes = (left_child, right_child) Current_high = Current_mid X = get_left_child(X) @@ -399,7 +414,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h left_child = T() right_child = T() - set_entire_range!(left_child, Current_mid-Current_low, old_density) + set_entire_range!(left_child, Current_mid-Current_low+1, old_density) X.child_nodes = (left_child, right_child) Current_low = Current_mid+1 X = get_right_child(X) @@ -409,9 +424,9 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h right_child = T() left_child.density = right_child.density = old_density X.child_nodes = (left_child, right_child) - construct_left_range!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) - construct_right_range!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) - reconstruct_stack!(stack,empty_node,1,stack_top-1) + construct_left_children!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) + construct_right_children!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return #recompute the entire stack. This time with X. end @@ -420,24 +435,25 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end -function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} +function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} + println("Construct left children called from ", Current_low, " to ", Current_high) stack_top = old_stack_top old_density = X.density while true stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) - decision_boundary = Current_mid + decision_boundary = Current_mid+1 if Query_low > decision_boundary #Same logic as get_left_range but with new constructed children. Current_low = decision_boundary #Get new children. left_child = T() right_child = T() - set_entire_range!(left_child, Current_mid-Current_low,old_density) + set_entire_range!(left_child, Current_mid-Current_low+1,old_density) #The left range is out of range and must be of old density X.child_nodes = (left_child,right_child) - Current_low = Current_mid+1 + #Current_low = Current_mid+1 X = get_right_child(X) #Now, this is happening again. elseif Query_low == decision_boundary @@ -445,8 +461,8 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va #This is a special condition where we can just set both left and right. left_child = T() right_child = T() - set_entire_range!(left_child, Current_mid-Current_low,old_density) - set_entire_range!(right_child, Current_high-Current_mid+1, value) + set_entire_range!(left_child, Current_mid-Current_low+1,old_density) + set_entire_range!(right_child, Current_high-Current_mid, value) X.child_nodes = (left_child,right_child) reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) #reconstruct_stack @@ -456,13 +472,15 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va #Set range using Range and value. left_child = T() right_child = T() - set_entire_range!(right_child, Current_high-Current_mid+1, value) + set_entire_range!(right_child, Current_high-Current_mid, value) + X.child_nodes = (left_child,right_child) Current_high = Current_mid X = get_left_child(X) end end end function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} + println("Construct right children called from ", Current_low, " to ", Current_high) #Something here? stack_top = old_stack_top old_density = X.density @@ -475,22 +493,22 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, #If Query_high == Current_mid (This means that it is EXACTLY half) left_child = T() right_child = T() - set_entire_range!(right_child, Current_high-Current_mid+1, old_density) + set_entire_range!(right_child, Current_high-Current_mid, old_density) X.child_nodes = (left_child,right_child) Current_high = Current_mid X = get_left_child(X) elseif Query_high == decision_boundary left_child = T() right_child = T() - set_entire_range!(left_child, Current_mid-Current_low,value) - set_entire_range!(right_child, Current_high-Current_mid+1, old_density) + set_entire_range!(left_child, Current_mid-Current_low+1,value) + set_entire_range!(right_child, Current_high-Current_mid, old_density) X.child_nodes = (left_child,right_child) reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return else left_child = T() right_child = T() - set_entire_range!(left_child, Current_high-Current_mid+1, value) + set_entire_range!(left_child, Current_mid-Current_low+1, value) X.child_nodes = (left_child,right_child) Current_low = Current_mid+1 X = get_right_child(X) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index f662b5794..b9767342e 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -41,18 +41,18 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "Add" begin X1 = Segment_tree(UInt64,100,Base.:+) a = zeros(UInt64, 100) - change_range!(X1, 3,37,53) - change_range!(X1, 9,23,45) - change_range!(X1, 5,2,21) + set_range!(X1, 37,53, 3) + #set_range!(X1, 23,45, 9) + #set_range!(X1, 2,21, 5) a[37:53] .= 3 - a[23:45] .= 9 - a[2:21] .= 5 + #a[23:45] .= 9 + #a[2:21] .= 5 @test sum(a[23:99]) == get_range(X1, 23,99) @test sum(a[55:87]) == get_range(X1, 55,87) @test sum(a[2:3]) == get_range(X1, 2, 3) @test sum(a[5:77]) == get_range(X1, 5,77) end - + @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. @@ -62,14 +62,14 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, a = rand(1:10000) b = rand(a:10000) c = rand(UInt64) - change_range!(X1,c,a,b) - X2[a:b] = c + set_range!(X1,a,b,c) + X2[a:b] .= c d = rand(1:10000) e = rand(d:10000) @test sum(X2[d:e]) == get_range(X1,d,e) end end - + @testset "Xor_trial" begin X1 = Segment_tree(UInt64,10000, xor) X2 = zeros(UInt64, 10000) @@ -77,8 +77,8 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, a = rand(1:10000) b = rand(a:10000) c = rand(UInt64) - change_range!(X1,c,a,b) - X2[a:b] = c + set_range!(X1,a,b,c) + X2[a:b] .= c d = rand(1:10000) e = rand(d:10000) @test reduce(xor,X2[d:e]) == get_range(X1,d,e) @@ -91,18 +91,21 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, identity_matrix = zeros(UInt64,(3,3)) identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 #Vector of vector may not be the most efficient, but it should work without problem. - X2 = [identity_matrix for i in 1:1000] + X2 = [copy(identity_matrix) for i in 1:1000] #Viewing without copying should be fine, as we won't mutate the arrays. #Static arrays recommended for serious uses of this. for i in 1:1000 a = rand(1:1000) b = rand(a:1000) c = rand(UInt64,(3,3)) - change_range!(X1,c,a,b) - X2[a:b] = c + set_range!(X1,a,b,c) + for j in a:b + X2[j] = copy(c) + end d = rand(1:1000) e = rand(d:1000) @test reduce(*,X2[d:e]) == get_range(X1,d,e) end end + end \ No newline at end of file From b9d4c91d47f64a6214795804a57a206f7eaabe35 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Sun, 3 Jul 2022 18:49:42 +0700 Subject: [PATCH 78/91] Fixing some more bugs. A few deep bugs remaining. --- src/segment_tree.jl | 76 +++++++++++++++++++++++++++++++-------- test/test_segment_tree.jl | 41 ++++++++++++++++++--- 2 files changed, 98 insertions(+), 19 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index ebbf9301e..250707f57 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -201,14 +201,18 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi decision_boundary = Current_mid+1 if Query_low > decision_boundary #Current_low = Current_mid+1 This is equivalent. + println("Skipping ", Current_low, " to ", Current_mid) Current_low = decision_boundary + X = get_right_child(X) elseif Query_low == decision_boundary #Wait a bit. - return get_op(X)(answer,get_entire_range(get_right_child(X))) + println("returning") + return get_op(X)(get_entire_range(get_right_child(X)), answer) else #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) (Except that the 2nd argument wasn't needed.) - answer = get_op(X)(answer,get_entire_range(get_right_child(X))) + println("Taking ", Current_mid+1, " to ", Current_high) + answer = get_op(X)(get_entire_range(get_right_child(X)), answer) Current_high = Current_mid X = get_left_child(X) end @@ -228,12 +232,15 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h decision_boundary = Current_mid #We write logics about variables. Let the compiler micro-optimize the registries. if Query_high < decision_boundary + println("Skipping ", Current_mid+1, " to ", Current_high) Current_high = decision_boundary X = get_left_child(X) elseif Query_high == decision_boundary - return get_op(X)(get_entire_range(get_left_child(X)), answer) + println("returning.") + return get_op(X)(answer, get_entire_range(get_left_child(X))) else - answer = get_op(X)(get_entire_range(get_left_child(X)), answer) + println("Taking ", Current_low, " to ", Current_mid) + answer = get_op(X)(answer, get_entire_range(get_left_child(X))) Current_low = Current_mid+1 X = get_right_child(X) end @@ -255,7 +262,7 @@ construct_left_children! construct_right_children! =# function reconstruct_stack!(stack, empty_node, stack_begin, stack_end) - println("Debugging: reconstructing stack from ",stack_begin," to ", stack_end) + #println("Debugging: reconstructing stack from ",stack_begin," to ", stack_end) for i in stack_end:-1:stack_begin node = stack[i] node.value = get_op(node)(get_left_child(node).value,get_right_child(node).value) @@ -272,7 +279,13 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu #Do something about it to set the range correctly. #Perhaps construct empty segment tree nodes? #Push the final into the stack. - construct_children!(X, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) + if(Current_low == Current_high) + X.density=X.value=value + else + construct_children!(X, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, stack_top) + end + + #What to do here? Not sure. reconstruct_stack!(stack,empty_node,1,stack_top-1) @@ -308,7 +321,7 @@ end function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) - println("set left range called from ", Current_low, " to ", Current_high) + #println("set left range called from ", Current_low, " to ", Current_high) stack_top = old_stack_top while true @@ -316,7 +329,11 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h if is_terminal(X) - construct_left_children!(X,Query_low,Current_low,Current_high,value,stack,empty_node, stack_top) + if(Current_low == Current_high) + X.density=X.value=value + else + construct_left_children!(X,Query_low,Current_low,Current_high,value,stack,empty_node, stack_top) + end reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return end @@ -345,13 +362,17 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h end function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) - println("set right range called from ", Current_low, " to ", Current_high) + #println("set right range called from ", Current_low, " to ", Current_high) stack_top = old_stack_top while true if is_terminal(X) #Is the terminal node. #Same logic. - construct_right_children!(X,Query_high,Current_low,Current_high,value,stack,empty_node,stack_top) - #reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + if(Current_low == Current_high) + X.density=X.value=value + else + construct_right_children!(X,Query_high,Current_low,Current_high,value,stack,empty_node,stack_top) + end + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return end @@ -386,7 +407,7 @@ function set_entire_range!(X::Segment_tree_node, range, value) X.child_nodes = nothing end function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - println("Construct children called from ", Current_low, " to ", Current_high) + #println("Construct children called from ", Current_low, " to ", Current_high) #= Supposedly start? Should Implicitly be here. @@ -408,6 +429,11 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h set_entire_range!(right_child, Current_high-Current_mid, old_density) X.child_nodes = (left_child, right_child) Current_high = Current_mid + if (Current_low == Current_mid) + left_child.density = left_child.value = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end X = get_left_child(X) elseif Query_low > Current_mid #Construct some children as well. @@ -417,6 +443,13 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h set_entire_range!(left_child, Current_mid-Current_low+1, old_density) X.child_nodes = (left_child, right_child) Current_low = Current_mid+1 + if (Current_low == Current_high) + #There is only ONE case now. + right_child.density = right_child.value = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end + X = get_right_child(X) else #Construct left and right children. @@ -436,7 +469,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - println("Construct left children called from ", Current_low, " to ", Current_high) + #println("Construct left children called from ", Current_low, " to ", Current_high) stack_top = old_stack_top old_density = X.density while true @@ -444,6 +477,8 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va stack_top += 1 Current_mid = get_middle(Current_low,Current_high) decision_boundary = Current_mid+1 + + #Case: if Current_low == Current_high if Query_low > decision_boundary #Same logic as get_left_range but with new constructed children. Current_low = decision_boundary @@ -475,12 +510,19 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va set_entire_range!(right_child, Current_high-Current_mid, value) X.child_nodes = (left_child,right_child) Current_high = Current_mid + if(Current_low == Current_mid) + left_child.density = left_child.value = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end + + X = get_left_child(X) end end end function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - println("Construct right children called from ", Current_low, " to ", Current_high) + #println("Construct right children called from ", Current_low, " to ", Current_high) #Something here? stack_top = old_stack_top old_density = X.density @@ -511,6 +553,12 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, set_entire_range!(left_child, Current_mid-Current_low+1, value) X.child_nodes = (left_child,right_child) Current_low = Current_mid+1 + if (Current_high == Current_mid) + right_child.density = right_child.value = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end + X = get_right_child(X) end end diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index b9767342e..a7e96575a 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -42,17 +42,48 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, X1 = Segment_tree(UInt64,100,Base.:+) a = zeros(UInt64, 100) set_range!(X1, 37,53, 3) - #set_range!(X1, 23,45, 9) - #set_range!(X1, 2,21, 5) + set_range!(X1, 23,45, 9) + set_range!(X1, 2,21, 5) a[37:53] .= 3 - #a[23:45] .= 9 - #a[2:21] .= 5 + a[23:45] .= 9 + a[2:21] .= 5 @test sum(a[23:99]) == get_range(X1, 23,99) @test sum(a[55:87]) == get_range(X1, 55,87) @test sum(a[2:3]) == get_range(X1, 2, 3) @test sum(a[5:77]) == get_range(X1, 5,77) end + @testset "Small_randomized_trial" begin + #Don't worry about the overflow. This is unsigned integer. + X1 = Segment_tree(UInt64,15, Base.:+) + X2 = zeros(UInt64, 15) + for i in 1:1000 + a = rand(1:15) + b = rand(a:15) + c = rand(UInt64) + set_range!(X1,a,b,c) + X2[a:b] .= c + d = rand(1:15) + e = rand(d:15) + @test sum(X2[d:e]) == get_range(X1,d,e) + end + + end + @testset "XL_array" begin + X1 = Segment_tree(UInt64,1000000, Base.:+) + X2 = zeros(UInt64, 1000000) + for i in 1:20 + a = rand(1:1000000) + b = rand(a:1000000) + c = rand(UInt64) + set_range!(X1,a,b,c) + X2[a:b] .= c + d = rand(1:1000000) + e = rand(d:1000000) + @test sum(X2[d:e]) == get_range(X1,d,e) + end + end + #= @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. @@ -107,5 +138,5 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test reduce(*,X2[d:e]) == get_range(X1,d,e) end end - + =# end \ No newline at end of file From 0c2c6db6dc4648a1adeaa3a5f01aad56a27f60a6 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:49:21 +0700 Subject: [PATCH 79/91] Desperate debug! Important restore point. --- src/segment_tree.jl | 57 ++++++++++++++++++++++++++++++++------- test/test_segment_tree.jl | 4 +-- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 250707f57..8c5c1ed56 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -156,9 +156,9 @@ end @inline function set_range!(X::Segment_tree, low, high, value) #Same logic. Wrap the call. #The utility memories are here. - println("Set range called from head from ", low, " to ", high) + println("Set range called from head from ", low, " to ", high, " setting value to ", value) set_range!(get_head(X),low,high,1,sizeof(X), value, X.stack, X.empty_node) - println("ending set range query") + #println("ending set range query") end get_left_child(X::Segment_tree_node) = X.child_nodes[1] @@ -201,17 +201,17 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi decision_boundary = Current_mid+1 if Query_low > decision_boundary #Current_low = Current_mid+1 This is equivalent. - println("Skipping ", Current_low, " to ", Current_mid) + #println("Skipping ", Current_low, " to ", Current_mid) Current_low = decision_boundary X = get_right_child(X) elseif Query_low == decision_boundary #Wait a bit. - println("returning") + #println("returning") return get_op(X)(get_entire_range(get_right_child(X)), answer) else #answer = get_op(X)(answer,get_entire_range(get_right_child(X, Current_high-Current_mid))) (Except that the 2nd argument wasn't needed.) - println("Taking ", Current_mid+1, " to ", Current_high) + #println("Taking ", Current_mid+1, " to ", Current_high) answer = get_op(X)(get_entire_range(get_right_child(X)), answer) Current_high = Current_mid X = get_left_child(X) @@ -232,14 +232,14 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h decision_boundary = Current_mid #We write logics about variables. Let the compiler micro-optimize the registries. if Query_high < decision_boundary - println("Skipping ", Current_mid+1, " to ", Current_high) + #println("Skipping ", Current_mid+1, " to ", Current_high) Current_high = decision_boundary X = get_left_child(X) elseif Query_high == decision_boundary - println("returning.") + #println("returning.") return get_op(X)(answer, get_entire_range(get_left_child(X))) else - println("Taking ", Current_low, " to ", Current_mid) + #println("Taking ", Current_low, " to ", Current_mid) answer = get_op(X)(answer, get_entire_range(get_left_child(X))) Current_low = Current_mid+1 X = get_right_child(X) @@ -445,9 +445,12 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_low = Current_mid+1 if (Current_low == Current_high) #There is only ONE case now. + + #= right_child.density = right_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return + =# end X = get_right_child(X) @@ -469,7 +472,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - #println("Construct left children called from ", Current_low, " to ", Current_high) + println("Construct left children called from ", Current_low, " to ", Current_high) stack_top = old_stack_top old_density = X.density while true @@ -511,6 +514,13 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va X.child_nodes = (left_child,right_child) Current_high = Current_mid if(Current_low == Current_mid) + if (Current_low == Current_high) + X.child_nodes = nothing + X.density = X.value = value + stack[stack_top-1] = empty_node + reconstruct_stack!(stack, empty_node, old_stack_top, stack_top-2) + return + end left_child.density = left_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return @@ -522,7 +532,7 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va end end function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - #println("Construct right children called from ", Current_low, " to ", Current_high) + println("Construct right children called from ", Current_low, " to ", Current_high) #Something here? stack_top = old_stack_top old_density = X.density @@ -554,6 +564,13 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, X.child_nodes = (left_child,right_child) Current_low = Current_mid+1 if (Current_high == Current_mid) + if (Current_low == Current_high) + X.child_nodes = nothing + X.density = X.value = value + stack[stack_top-1] = empty_node + reconstruct_stack!(stack, empty_node, old_stack_top, stack_top-2) + return + end right_child.density = right_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return @@ -570,3 +587,23 @@ function propagate_density!(X::Segment_tree_node) end =# + +function debug_print(X::Segment_tree) + println("Debug printing: ",1,"-",sizeof(X)) + debug_print(X.head, 1, 1, sizeof(X)) + println("end debug print") +end + +function debug_print(X::Segment_tree_node, indent, low, high) + println(repeat(" ", indent),"value: ", X.value) + if is_terminal(X) + println(repeat(" ", indent),"density: ", X.density) + else + middle = get_middle(low,high) + println(repeat(" ", indent),"left: ",low,"-",middle) + debug_print(get_left_child(X), indent+1, low, middle) + println(repeat(" ", indent),"right: ",middle+1,"-",high) + debug_print(get_right_child(X), indent+1, middle+1, high) + println(repeat(" ", indent),"end") + end +end diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index a7e96575a..b2b8fc7bf 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -68,7 +68,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, end end - + #= @testset "XL_array" begin X1 = Segment_tree(UInt64,1000000, Base.:+) X2 = zeros(UInt64, 1000000) @@ -83,7 +83,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test sum(X2[d:e]) == get_range(X1,d,e) end end - #= + @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. From a4655f6a7ffb8e2b72e3a0d8b81bceb631705f55 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Jul 2022 10:33:43 +0700 Subject: [PATCH 80/91] Writing a new debug tool. The debugging madness continues. --- src/segment_tree.jl | 27 +++++++++++++++++++++++---- test/test_segment_tree.jl | 4 ++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 8c5c1ed56..514918c6e 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -407,7 +407,7 @@ function set_entire_range!(X::Segment_tree_node, range, value) X.child_nodes = nothing end function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - #println("Construct children called from ", Current_low, " to ", Current_high) + println("Construct children called from ", Current_low, " to ", Current_high) #= Supposedly start? Should Implicitly be here. @@ -445,12 +445,9 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h Current_low = Current_mid+1 if (Current_low == Current_high) #There is only ONE case now. - - #= right_child.density = right_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return - =# end X = get_right_child(X) @@ -514,6 +511,7 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va X.child_nodes = (left_child,right_child) Current_high = Current_mid if(Current_low == Current_mid) + #= if (Current_low == Current_high) X.child_nodes = nothing X.density = X.value = value @@ -521,6 +519,7 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va reconstruct_stack!(stack, empty_node, old_stack_top, stack_top-2) return end + =# left_child.density = left_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return @@ -564,6 +563,7 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, X.child_nodes = (left_child,right_child) Current_low = Current_mid+1 if (Current_high == Current_mid) + #= if (Current_low == Current_high) X.child_nodes = nothing X.density = X.value = value @@ -571,6 +571,7 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, reconstruct_stack!(stack, empty_node, old_stack_top, stack_top-2) return end + =# right_child.density = right_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return @@ -607,3 +608,21 @@ function debug_print(X::Segment_tree_node, indent, low, high) println(repeat(" ", indent),"end") end end + +function check_consistency(X::Segment_tree) + consistency = check_consistency(X.head, 1, sizeof(X)) + if (!consistency) + println("This segment tree is currently not consistent with the invariant:.") + debug_print(X) + end + return consistency +end + +function check_consistency(X::Segment_tree_node, low, high) + if is_terminal(X) + return low <= high && get_iterated_op(X)(X.density,high-low+1) == X.value + else + middle = get_middle(low,high) + return check_consistency(get_left_child(X),low,middle) && check_consistency(get_right_child(X), middle+1, high) + end +end \ No newline at end of file diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index b2b8fc7bf..a7e96575a 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -68,7 +68,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, end end - #= + @testset "XL_array" begin X1 = Segment_tree(UInt64,1000000, Base.:+) X2 = zeros(UInt64, 1000000) @@ -83,7 +83,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test sum(X2[d:e]) == get_range(X1,d,e) end end - + #= @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. From a087c77a5bc3b68953b6d864ac425973bad227be Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Jul 2022 11:18:21 +0700 Subject: [PATCH 81/91] Fixing ONE bug. --- src/segment_tree.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 514918c6e..82f810440 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -451,12 +451,23 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end X = get_right_child(X) + + #elseif Query_low == Current_mid + #Something is wrong in this line. + else #Construct left and right children. left_child = T() right_child = T() - left_child.density = right_child.density = old_density X.child_nodes = (left_child, right_child) + if (Current_low == Current_mid) + left_child.density = right_child.density = value + left_child.value = right_child.value = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end + left_child.density = right_child.density = old_density + construct_left_children!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) construct_right_children!(get_right_child(X), Query_high, Current_mid+1, Current_high, value, stack, empty_node, stack_top) reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) @@ -561,8 +572,8 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, right_child = T() set_entire_range!(left_child, Current_mid-Current_low+1, value) X.child_nodes = (left_child,right_child) - Current_low = Current_mid+1 - if (Current_high == Current_mid) + + if (Current_low == Current_mid) #= if (Current_low == Current_high) X.child_nodes = nothing @@ -576,7 +587,7 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return end - + Current_low = Current_mid+1 X = get_right_child(X) end end From 41318827e153928c61f484036fdf148e3ad656b2 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Jul 2022 18:22:50 +0700 Subject: [PATCH 82/91] Fixing a VERY LARGE class of bugs. Only a few remaining. --- src/segment_tree.jl | 27 +++++++++------------------ test/test_segment_tree.jl | 4 ++-- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 82f810440..ae44f70c6 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -147,7 +147,7 @@ end @inline function get_range(X::Segment_tree,low,high) - println("get range called from head from ", low, " to ", high) + #println("get range called from head from ", low, " to ", high) #The reason this is inlined is because there is only ONE line. #This is only a wrapping call to another function which is NOT inlined. return get_range(X.head,low,high,1,sizeof(X)) @@ -156,7 +156,7 @@ end @inline function set_range!(X::Segment_tree, low, high, value) #Same logic. Wrap the call. #The utility memories are here. - println("Set range called from head from ", low, " to ", high, " setting value to ", value) + #println("Set range called from head from ", low, " to ", high, " setting value to ", value) set_range!(get_head(X),low,high,1,sizeof(X), value, X.stack, X.empty_node) #println("ending set range query") end @@ -186,7 +186,7 @@ function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Cur end function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) - println("get_left_range called from ", Current_low, " to ", Current_high) + #println("get_left_range called from ", Current_low, " to ", Current_high) answer = get_element_identity(X) while true if is_terminal(X) #Is the terminal node. @@ -221,7 +221,7 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi end function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) - println("get_right_range called from ", Current_low, " to ", Current_high) + #println("get_right_range called from ", Current_low, " to ", Current_high) answer = get_element_identity(X) while true if is_terminal(X) #Is the terminal node. @@ -251,16 +251,6 @@ end return X.value end -#= -Plan: - -set_range!. -set_left_range!. -set_right_range! -construct_children! -construct_left_children! -construct_right_children! -=# function reconstruct_stack!(stack, empty_node, stack_begin, stack_end) #println("Debugging: reconstructing stack from ",stack_begin," to ", stack_end) for i in stack_end:-1:stack_begin @@ -407,7 +397,7 @@ function set_entire_range!(X::Segment_tree_node, range, value) X.child_nodes = nothing end function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - println("Construct children called from ", Current_low, " to ", Current_high) + #println("Construct children called from ", Current_low, " to ", Current_high) #= Supposedly start? Should Implicitly be here. @@ -480,7 +470,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - println("Construct left children called from ", Current_low, " to ", Current_high) + #println("Construct left children called from ", Current_low, " to ", Current_high) stack_top = old_stack_top old_density = X.density while true @@ -492,11 +482,12 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va #Case: if Current_low == Current_high if Query_low > decision_boundary #Same logic as get_left_range but with new constructed children. - Current_low = decision_boundary + #Get new children. left_child = T() right_child = T() set_entire_range!(left_child, Current_mid-Current_low+1,old_density) + Current_low = decision_boundary #The left range is out of range and must be of old density X.child_nodes = (left_child,right_child) #Current_low = Current_mid+1 @@ -542,7 +533,7 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va end end function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} - println("Construct right children called from ", Current_low, " to ", Current_high) + #println("Construct right children called from ", Current_low, " to ", Current_high) #Something here? stack_top = old_stack_top old_density = X.density diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index a7e96575a..d96de1168 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -83,7 +83,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test sum(X2[d:e]) == get_range(X1,d,e) end end - #= + @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. @@ -138,5 +138,5 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test reduce(*,X2[d:e]) == get_range(X1,d,e) end end - =# + end \ No newline at end of file From fa3c2670fcc9c78a0590154cb50feddd0f112f53 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Mon, 11 Jul 2022 18:41:32 +0700 Subject: [PATCH 83/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index d96de1168..1ac8a3a0c 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -72,7 +72,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "XL_array" begin X1 = Segment_tree(UInt64,1000000, Base.:+) X2 = zeros(UInt64, 1000000) - for i in 1:20 + for i in 1:1000 a = rand(1:1000000) b = rand(a:1000000) c = rand(UInt64) @@ -89,7 +89,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, #Don't worry about the overflow. This is unsigned integer. X1 = Segment_tree(UInt64,10000, Base.:+) X2 = zeros(UInt64, 10000) - for i in 1:10000 + for i in 1:100000 a = rand(1:10000) b = rand(a:10000) c = rand(UInt64) @@ -104,7 +104,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "Xor_trial" begin X1 = Segment_tree(UInt64,10000, xor) X2 = zeros(UInt64, 10000) - for i in 1:10000 + for i in 1:100000 a = rand(1:10000) b = rand(a:10000) c = rand(UInt64) @@ -125,7 +125,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, X2 = [copy(identity_matrix) for i in 1:1000] #Viewing without copying should be fine, as we won't mutate the arrays. #Static arrays recommended for serious uses of this. - for i in 1:1000 + for i in 1:10000 a = rand(1:1000) b = rand(a:1000) c = rand(UInt64,(3,3)) From fdcd8a7e9b3c07705f84b9a9cca39b08314ef946 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Thu, 14 Jul 2022 20:33:23 +0700 Subject: [PATCH 84/91] "Finished" except something with matmul? --- src/segment_tree.jl | 27 ++++++++-- test/test_segment_tree.jl | 107 ++++++++++++++++++++++++++++++++++---- 2 files changed, 121 insertions(+), 13 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index ae44f70c6..7a70acf7d 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -75,6 +75,7 @@ repeat_op(base::Number, time::Integer, ::typeof(*)) = base^time repeat_op(base::T, time::Integer, ::typeof(xor)) where {T<:Integer} = iseven(time) ? zero(T) : base repeat_op(base::Integer, ::Integer, ::typeof(&)) = base repeat_op(base::Integer, ::Integer, ::typeof(|)) = base +repeat_op(base::String, time::Integer, ::typeof(*)) = repeat(base, time) #I luv multiple dispatch! @@ -86,6 +87,7 @@ get_identity(x,y) = artificial_identity() get_identity(::Type{T}, ::typeof(+)) where {T<:Number} = zero(T) get_identity(::Type{T}, ::typeof(*)) where {T<:Number} = one(T) get_identity(::Type{T}, ::typeof(xor)) where {T<:Integer} = zero(T) +get_identity(::Type{T}, ::typeof(*)) where {T<:String} = ()->"" operation_with_identity(f) = (x,y)-> (x===artificial_identity()) ? y : (y===artificial_identity() ? x : f(x,y)) repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity()) ? artificial_identity() : f(base,time) @@ -100,7 +102,11 @@ mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegm return new{Dtype,Op,iterated_op,identity}(nothing) end end -get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = identity + +process_identity(x) = x +process_identity(x::Function) = x() +get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = process_identity(identity) + struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{node_type} size::Int @@ -112,9 +118,10 @@ end get_head(X::Segment_tree) = X.head sizeof(X::Segment_tree) = X.size function Segment_tree(type, size, op::Function, iterated_op::Function, identity) + #println(type) size = convert(Int,size) head = Segment_tree_node{type, op, iterated_op, identity}() - head.value = head.density = identity + head.value = head.density = process_identity(identity) empty_node = Segment_tree_node{type, op, iterated_op, identity}() stack = Vector(undef,65) for i in 1:65 @@ -455,7 +462,16 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h left_child.value = right_child.value = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) return + + elseif (Current_mid+1 == Current_high) + left_child.density = old_density + construct_left_children!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) + right_child.density = right_child.value = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end + left_child.density = right_child.density = old_density construct_left_children!(get_left_child(X), Query_low, Current_low, Current_mid, value, stack, empty_node, stack_top) @@ -615,7 +631,7 @@ function check_consistency(X::Segment_tree) consistency = check_consistency(X.head, 1, sizeof(X)) if (!consistency) println("This segment tree is currently not consistent with the invariant:.") - debug_print(X) + #debug_print(X) end return consistency end @@ -625,6 +641,9 @@ function check_consistency(X::Segment_tree_node, low, high) return low <= high && get_iterated_op(X)(X.density,high-low+1) == X.value else middle = get_middle(low,high) - return check_consistency(get_left_child(X),low,middle) && check_consistency(get_right_child(X), middle+1, high) + return (check_consistency(get_left_child(X),low,middle) + && check_consistency(get_right_child(X), middle+1, high) && + X.value == get_op(X)(get_left_child(X).value, get_right_child(X).value) + ) end end \ No newline at end of file diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 1ac8a3a0c..28da97c85 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -20,6 +20,17 @@ This code belongs to me (it's my early julia codes) but you could've written thi Just a literal implementation of Quarternion based on its definition, no optimization or other methods. =# +#= +function naive_reduce_matrix_mul(x) + identity_matrix = zeros(UInt64,(3,3)) + identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 + ans = identity_matrix + for i in x + ans = ans*i + end + return ans +end +=# struct Quarternion{T<:Real} @@ -52,6 +63,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test sum(a[2:3]) == get_range(X1, 2, 3) @test sum(a[5:77]) == get_range(X1, 5,77) end + @testset "Small_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. X1 = Segment_tree(UInt64,15, Base.:+) @@ -72,7 +84,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "XL_array" begin X1 = Segment_tree(UInt64,1000000, Base.:+) X2 = zeros(UInt64, 1000000) - for i in 1:1000 + for i in 1:100 a = rand(1:1000000) b = rand(a:1000000) c = rand(UInt64) @@ -89,7 +101,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, #Don't worry about the overflow. This is unsigned integer. X1 = Segment_tree(UInt64,10000, Base.:+) X2 = zeros(UInt64, 10000) - for i in 1:100000 + for i in 1:10000 a = rand(1:10000) b = rand(a:10000) c = rand(UInt64) @@ -104,7 +116,7 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @testset "Xor_trial" begin X1 = Segment_tree(UInt64,10000, xor) X2 = zeros(UInt64, 10000) - for i in 1:100000 + for i in 1:10000 a = rand(1:10000) b = rand(a:10000) c = rand(UInt64) @@ -115,28 +127,105 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, @test reduce(xor,X2[d:e]) == get_range(X1,d,e) end end - + @testset "Vector_add" begin + X1 = Segment_tree(Array{UInt64,1},1000, +) + identity_vec = zeros(UInt64,5) + #Vector of vector may not be the most efficient, but it should work without problem. + X2 = [identity_vec for i in 1:1000] + #Viewing without copying should be fine, as we won't mutate the arrays. + #Static arrays recommended for serious uses of this. + for i in 1:10000 + a = rand(1:1000) + b = rand(a:1000) + c = rand(UInt64,5) + set_range!(X1,a,b,c) + for j in a:b + X2[j] = c + end + d = rand(1:1000) + e = rand(d:1000) + + if (reduce(+,X2[d:e]) != identity_vec) + #println(d," ", e) + @test reduce(+,X2[d:e]) == get_range(X1,d,e) + end + + #= + if (naive_reduce_matrix_mul(X2[d:e]) != identity_matrix) + println(d," ", e) + @test naive_reduce_matrix_mul(X2[d:e]) == get_range(X1,d,e) + end + =# + end + end + + @testset "3x3_matrix_multiplication" begin #Float/etc should work fine as well. Just don't want to deal with precision issues. - X1 = Segment_tree(Array{UInt64,2},1000,*) + X1 = Segment_tree(Array{UInt64,2},1000, *) identity_matrix = zeros(UInt64,(3,3)) identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 #Vector of vector may not be the most efficient, but it should work without problem. - X2 = [copy(identity_matrix) for i in 1:1000] + X2 = [identity_matrix for i in 1:1000] #Viewing without copying should be fine, as we won't mutate the arrays. #Static arrays recommended for serious uses of this. for i in 1:10000 a = rand(1:1000) b = rand(a:1000) c = rand(UInt64,(3,3)) - set_range!(X1,a,b,c) + set_range!(X1,a,b,copy(c)) for j in a:b X2[j] = copy(c) end d = rand(1:1000) e = rand(d:1000) - @test reduce(*,X2[d:e]) == get_range(X1,d,e) + + if (reduce(*,X2[d:e]) != identity_matrix) + #println(d," ", e) + @test reduce(*,X2[d:e]) == get_range(X1,d,e) + end + + #= + if (naive_reduce_matrix_mul(X2[d:e]) != identity_matrix) + println(d," ", e) + @test naive_reduce_matrix_mul(X2[d:e]) == get_range(X1,d,e) + end + =# + end + end + @testset "String_concat" begin + String_choice = ["A", "B", "C", "D", "E"] + X1 = Segment_tree(String, 10000, Base.:*) + X2 = ["" for i in 1:10000] + for i in 1:10000 + + a = rand(1:10000) + b = rand(a:10000) + c = String_choice[rand(1:5)] + set_range!(X1, a, b, c) + X2[a:b] .= c + d = rand(1:10000) + e = rand(d:10000) + @test get_range(X1, d, e) == reduce(*, X2[d:e]) + end + end + @testset "Quarternion_test" begin + test_type = Quarternion{UInt64} + identity = test_type(1,0,0,0) + X1 = Segment_tree(test_type, 10000, Base.:*; identity=identity) + X2 = [identity for i in 1:10000] + for i in 1:10000 + a = rand(1:10000) + b = rand(a:10000) + c = test_type(rand(UInt64,4)...) + set_range!(X1, a, b, c) + for j in a:b + X2[j] = c + end + d = rand(1:10000) + e = rand(d:10000) + @test get_range(X1, d, e) == reduce(*, X2[d:e]) + end end - end \ No newline at end of file From 72ad6d5f68e3e008209d238c2b12338b84b896ab Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Thu, 14 Jul 2022 20:57:27 +0700 Subject: [PATCH 85/91] Update test_segment_tree.jl --- test/test_segment_tree.jl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 28da97c85..838f5b371 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -48,6 +48,18 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, a.real*b.k + b.real*a.k + a.i*b.j - a.j*b.i, ) +function test_matmul(a,b) + ans = zeros(UInt64,(3,3)) + for i in 1:3 + for j in 1:3 + for k in 1:3 + ans[i,j] += a[i,k] * b[k,j] + end + end + end + return ans +end + @testset "segment_tree" begin @testset "Add" begin X1 = Segment_tree(UInt64,100,Base.:+) @@ -194,14 +206,15 @@ Quarternion(a.real*b.real - a.i*b.i - a.j*b.j - a.k*b.k, end end @testset "String_concat" begin - String_choice = ["A", "B", "C", "D", "E"] + String_choice = ["A", "B", "C", "D", "E", "AA", "BFFG","ATL", "Moon", "Hey"] + #The words are random. The acronym's reference are coincidental. X1 = Segment_tree(String, 10000, Base.:*) X2 = ["" for i in 1:10000] for i in 1:10000 a = rand(1:10000) b = rand(a:10000) - c = String_choice[rand(1:5)] + c = String_choice[rand(1:10)] set_range!(X1, a, b, c) X2[a:b] .= c d = rand(1:10000) From 6b544ec6d787fd24b7c253cf6684b08a5ac9cdab Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 19 Jul 2022 09:33:13 +0700 Subject: [PATCH 86/91] Finally! Finished! Screw the RNG! --- src/segment_tree.jl | 10 +++++ test/test_segment_tree.jl | 80 ++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index 7a70acf7d..d6c3224b4 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -567,6 +567,16 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, Current_high = Current_mid X = get_left_child(X) elseif Query_high == decision_boundary + + if (Current_low == Current_high) + stack[stack_top] = empty_node + stack_top -= 1 + X.value = X.density = value + reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) + return + end + + left_child = T() right_child = T() set_entire_range!(left_child, Current_mid-Current_low+1,value) diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 838f5b371..1d6cdcf60 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -31,6 +31,7 @@ function naive_reduce_matrix_mul(x) return ans end =# +import Random.MersenneTwister struct Quarternion{T<:Real} @@ -61,6 +62,7 @@ function test_matmul(a,b) end @testset "segment_tree" begin + rng = MersenneTwister(1234) #A strong rng needed. @testset "Add" begin X1 = Segment_tree(UInt64,100,Base.:+) a = zeros(UInt64, 100) @@ -81,13 +83,13 @@ end X1 = Segment_tree(UInt64,15, Base.:+) X2 = zeros(UInt64, 15) for i in 1:1000 - a = rand(1:15) - b = rand(a:15) - c = rand(UInt64) + a = rand(rng,1:15) + b = rand(rng,a:15) + c = rand(rng,UInt64) set_range!(X1,a,b,c) X2[a:b] .= c - d = rand(1:15) - e = rand(d:15) + d = rand(rng,1:15) + e = rand(rng,d:15) @test sum(X2[d:e]) == get_range(X1,d,e) end @@ -97,13 +99,13 @@ end X1 = Segment_tree(UInt64,1000000, Base.:+) X2 = zeros(UInt64, 1000000) for i in 1:100 - a = rand(1:1000000) - b = rand(a:1000000) - c = rand(UInt64) + a = rand(rng,1:1000000) + b = rand(rng,a:1000000) + c = rand(rng,UInt64) set_range!(X1,a,b,c) X2[a:b] .= c - d = rand(1:1000000) - e = rand(d:1000000) + d = rand(rng,1:1000000) + e = rand(rng,d:1000000) @test sum(X2[d:e]) == get_range(X1,d,e) end end @@ -114,13 +116,13 @@ end X1 = Segment_tree(UInt64,10000, Base.:+) X2 = zeros(UInt64, 10000) for i in 1:10000 - a = rand(1:10000) - b = rand(a:10000) - c = rand(UInt64) + a = rand(rng,1:10000) + b = rand(rng,a:10000) + c = rand(rng,UInt64) set_range!(X1,a,b,c) X2[a:b] .= c - d = rand(1:10000) - e = rand(d:10000) + d = rand(rng,1:10000) + e = rand(rng,d:10000) @test sum(X2[d:e]) == get_range(X1,d,e) end end @@ -129,13 +131,13 @@ end X1 = Segment_tree(UInt64,10000, xor) X2 = zeros(UInt64, 10000) for i in 1:10000 - a = rand(1:10000) - b = rand(a:10000) + a = rand(rng,1:10000) + b = rand(rng,a:10000) c = rand(UInt64) set_range!(X1,a,b,c) X2[a:b] .= c - d = rand(1:10000) - e = rand(d:10000) + d = rand(rng,1:10000) + e = rand(rng,d:10000) @test reduce(xor,X2[d:e]) == get_range(X1,d,e) end end @@ -147,15 +149,15 @@ end #Viewing without copying should be fine, as we won't mutate the arrays. #Static arrays recommended for serious uses of this. for i in 1:10000 - a = rand(1:1000) - b = rand(a:1000) - c = rand(UInt64,5) + a = rand(rng,1:1000) + b = rand(rng,a:1000) + c = rand(rng,UInt64,5) set_range!(X1,a,b,c) for j in a:b X2[j] = c end - d = rand(1:1000) - e = rand(d:1000) + d = rand(rng,1:1000) + e = rand(rng,d:1000) if (reduce(+,X2[d:e]) != identity_vec) #println(d," ", e) @@ -182,15 +184,15 @@ end #Viewing without copying should be fine, as we won't mutate the arrays. #Static arrays recommended for serious uses of this. for i in 1:10000 - a = rand(1:1000) - b = rand(a:1000) - c = rand(UInt64,(3,3)) + a = rand(rng,1:1000) + b = rand(rng,a:1000) + c = rand(rng,UInt64,(3,3)) set_range!(X1,a,b,copy(c)) for j in a:b X2[j] = copy(c) end - d = rand(1:1000) - e = rand(d:1000) + d = rand(rng,1:1000) + e = rand(rng,d:1000) if (reduce(*,X2[d:e]) != identity_matrix) #println(d," ", e) @@ -212,13 +214,13 @@ end X2 = ["" for i in 1:10000] for i in 1:10000 - a = rand(1:10000) - b = rand(a:10000) - c = String_choice[rand(1:10)] + a = rand(rng,1:10000) + b = rand(rng,a:10000) + c = String_choice[rand(rng,1:10)] set_range!(X1, a, b, c) X2[a:b] .= c - d = rand(1:10000) - e = rand(d:10000) + d = rand(rng,1:10000) + e = rand(rng,d:10000) @test get_range(X1, d, e) == reduce(*, X2[d:e]) end end @@ -228,15 +230,15 @@ end X1 = Segment_tree(test_type, 10000, Base.:*; identity=identity) X2 = [identity for i in 1:10000] for i in 1:10000 - a = rand(1:10000) - b = rand(a:10000) - c = test_type(rand(UInt64,4)...) + a = rand(rng,1:10000) + b = rand(rng,a:10000) + c = test_type(rand(rng,UInt64,4)...) set_range!(X1, a, b, c) for j in a:b X2[j] = c end - d = rand(1:10000) - e = rand(d:10000) + d = rand(rng,1:10000) + e = rand(rng,d:10000) @test get_range(X1, d, e) == reduce(*, X2[d:e]) end From e78608d5e6e4a0890e27e5f7c7e0b3f0bfc6efa3 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 19 Jul 2022 11:32:43 +0700 Subject: [PATCH 87/91] Renaming and adding inbounds. Finishing up. --- src/segment_tree.jl | 96 +++++++++++++++++++-------------------- test/test_segment_tree.jl | 18 ++++---- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/segment_tree.jl b/src/segment_tree.jl index d6c3224b4..a9c99cd32 100644 --- a/src/segment_tree.jl +++ b/src/segment_tree.jl @@ -31,11 +31,11 @@ Knowledge of abstract algebra should be put to use. TODO: Consider adding cases of equal as a separate case. =# -abstract type Abstractsegmenttreenode{Dtype, Op, iterated_op} end +abstract type AbstractSegmentTreeNode{Dtype, Op, iterated_op} end abstract type Abstractsegmenttree{node_type} end -get_dtype(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype -get_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op -get_iterated_op(::Abstractsegmenttreenode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op +get_dtype(::AbstractSegmentTreeNode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Dtype +get_op(::AbstractSegmentTreeNode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = Op +get_iterated_op(::AbstractSegmentTreeNode{Dtype,Op,iterated_op}) where {Dtype, Op, iterated_op} = iterated_op get_middle(low, high) = div(low+high,2) @@ -92,45 +92,45 @@ operation_with_identity(f) = (x,y)-> (x===artificial_identity()) ? y : (y===arti repeat_op_with_identity(f) = (base,time) -> (base===artificial_identity()) ? artificial_identity() : f(base,time) -mutable struct Segment_tree_node{Dtype, Op, iterated_op, identity}<:Abstractsegmenttreenode{Dtype,Op,iterated_op} - child_nodes::Union{NTuple{2,Segment_tree_node{Dtype, Op, iterated_op, identity}},Nothing} +mutable struct SegmentTreeNode{Dtype, Op, iterated_op, identity}<:AbstractSegmentTreeNode{Dtype,Op,iterated_op} + child_nodes::Union{NTuple{2,SegmentTreeNode{Dtype, Op, iterated_op, identity}},Nothing} #Either both children are valid or none is valid. value::Dtype density::Dtype #Implicitly have information about where it represents. - function Segment_tree_node{Dtype,Op,iterated_op,identity}() where {Dtype,Op,iterated_op,identity} + function SegmentTreeNode{Dtype,Op,iterated_op,identity}() where {Dtype,Op,iterated_op,identity} return new{Dtype,Op,iterated_op,identity}(nothing) end end process_identity(x) = x process_identity(x::Function) = x() -get_element_identity(::Segment_tree_node{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = process_identity(identity) +get_element_identity(::SegmentTreeNode{Dtype, Op, iterated_op, identity}) where {Dtype, Op, iterated_op, identity} = process_identity(identity) -struct Segment_tree{node_type<:Abstractsegmenttreenode} <: Abstractsegmenttree{node_type} +struct SegmentTree{node_type<:AbstractSegmentTreeNode} <: Abstractsegmenttree{node_type} size::Int head::node_type #The stack will be used each time it is required. stack::Vector{node_type} empty_node::node_type end -get_head(X::Segment_tree) = X.head -sizeof(X::Segment_tree) = X.size -function Segment_tree(type, size, op::Function, iterated_op::Function, identity) +get_head(X::SegmentTree) = X.head +sizeof(X::SegmentTree) = X.size +function SegmentTree(type, size, op::Function, iterated_op::Function, identity) #println(type) size = convert(Int,size) - head = Segment_tree_node{type, op, iterated_op, identity}() + head = SegmentTreeNode{type, op, iterated_op, identity}() head.value = head.density = process_identity(identity) - empty_node = Segment_tree_node{type, op, iterated_op, identity}() + empty_node = SegmentTreeNode{type, op, iterated_op, identity}() stack = Vector(undef,65) for i in 1:65 - stack[i] = empty_node + @inbounds stack[i] = empty_node end - return Segment_tree{Segment_tree_node{type,op,iterated_op,identity}}(size,head, stack, empty_node) + return SegmentTree{SegmentTreeNode{type,op,iterated_op,identity}}(size,head, stack, empty_node) end -function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothing) +function SegmentTree(type::Type, size, op; iterated_op=nothing, identity=nothing) #A bit annoying but local scope must take place. new_op = op if iterated_op===nothing @@ -148,19 +148,19 @@ function Segment_tree(type::Type, size, op; iterated_op=nothing, identity=nothin else new_identity = identity end - return Segment_tree(type,size,new_op,new_iterated_op,new_identity) + return SegmentTree(type,size,new_op,new_iterated_op,new_identity) end -@inline function get_range(X::Segment_tree,low,high) +@inline function get_range(X::SegmentTree,low,high) #println("get range called from head from ", low, " to ", high) #The reason this is inlined is because there is only ONE line. #This is only a wrapping call to another function which is NOT inlined. return get_range(X.head,low,high,1,sizeof(X)) end -@inline function set_range!(X::Segment_tree, low, high, value) +@inline function set_range!(X::SegmentTree, low, high, value) #Same logic. Wrap the call. #The utility memories are here. #println("Set range called from head from ", low, " to ", high, " setting value to ", value) @@ -168,10 +168,10 @@ end #println("ending set range query") end -get_left_child(X::Segment_tree_node) = X.child_nodes[1] -get_right_child(X::Segment_tree_node) = X.child_nodes[2] -is_terminal(X::Segment_tree_node) = (X.child_nodes===nothing) -function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high) +get_left_child(X::SegmentTreeNode) = X.child_nodes[1] +get_right_child(X::SegmentTreeNode) = X.child_nodes[2] +is_terminal(X::SegmentTreeNode) = (X.child_nodes===nothing) +function get_range(X::SegmentTreeNode, Query_low, Query_high, Current_low, Current_high) while true if is_terminal(X) #Is the terminal node. return get_iterated_op(X)(X.density, Query_high-Query_low+1) @@ -192,7 +192,7 @@ function get_range(X::Segment_tree_node, Query_low, Query_high, Current_low, Cur end end -function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_high) +function get_left_range(X::SegmentTreeNode, Query_low, Current_low, Current_high) #println("get_left_range called from ", Current_low, " to ", Current_high) answer = get_element_identity(X) while true @@ -227,7 +227,7 @@ function get_left_range(X::Segment_tree_node, Query_low, Current_low, Current_hi end -function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_high) +function get_right_range(X::SegmentTreeNode, Query_high, Current_low,Current_high) #println("get_right_range called from ", Current_low, " to ", Current_high) answer = get_element_identity(X) while true @@ -254,21 +254,21 @@ function get_right_range(X::Segment_tree_node, Query_high, Current_low,Current_h end end -@inline function get_entire_range(X::Segment_tree_node) +@inline function get_entire_range(X::SegmentTreeNode) return X.value end function reconstruct_stack!(stack, empty_node, stack_begin, stack_end) #println("Debugging: reconstructing stack from ",stack_begin," to ", stack_end) for i in stack_end:-1:stack_begin - node = stack[i] + @inbounds node = stack[i] node.value = get_op(node)(get_left_child(node).value,get_right_child(node).value) - stack[i] = empty_node + @inbounds stack[i] = empty_node end end -function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) +function set_range!(X::SegmentTreeNode, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node) #Working in progress. stack_top = 1 #The top of the stack where you can change. while true @@ -293,7 +293,7 @@ function set_range!(X::Segment_tree_node, Query_low, Query_high, Current_low, Cu return end - stack[stack_top] = X + @inbounds stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid @@ -317,7 +317,7 @@ end -function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) +function set_left_range!(X::SegmentTreeNode, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) #println("set left range called from ", Current_low, " to ", Current_high) stack_top = old_stack_top while true @@ -335,7 +335,7 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h return end #Push the stack here? - stack[stack_top] = X + @inbounds stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) decision_boundary = Current_mid+1 @@ -358,7 +358,7 @@ function set_left_range!(X::Segment_tree_node, Query_low, Current_low, Current_h end end -function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) +function set_right_range!(X::SegmentTreeNode, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) #println("set right range called from ", Current_low, " to ", Current_high) stack_top = old_stack_top while true @@ -373,7 +373,7 @@ function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current return end - stack[stack_top] = X + @inbounds stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) decision_boundary = Current_mid @@ -398,12 +398,12 @@ function set_right_range!(X::Segment_tree_node, Query_high, Current_low, Current end end -function set_entire_range!(X::Segment_tree_node, range, value) +function set_entire_range!(X::SegmentTreeNode, range, value) X.density = value X.value = get_iterated_op(X)(value, range) X.child_nodes = nothing end -function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} +function construct_children!(X::T, Query_low, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:SegmentTreeNode} #println("Construct children called from ", Current_low, " to ", Current_high) #= Supposedly start? @@ -416,7 +416,7 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h old_density = X.density while true #old_density = X.density - stack[stack_top] = X + @inbounds stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) if Query_high <= Current_mid @@ -485,12 +485,12 @@ function construct_children!(X::T, Query_low, Query_high, Current_low, Current_h end -function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} +function construct_left_children!(X::T, Query_low, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:SegmentTreeNode} #println("Construct left children called from ", Current_low, " to ", Current_high) stack_top = old_stack_top old_density = X.density while true - stack[stack_top] = X + @inbounds stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) decision_boundary = Current_mid+1 @@ -548,13 +548,13 @@ function construct_left_children!(X::T, Query_low, Current_low, Current_high, va end end end -function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:Segment_tree_node} +function construct_right_children!(X::T, Query_high, Current_low, Current_high, value, stack, empty_node, old_stack_top) where {T<:SegmentTreeNode} #println("Construct right children called from ", Current_low, " to ", Current_high) #Something here? stack_top = old_stack_top old_density = X.density while true - stack[stack_top] = X + @inbounds stack[stack_top] = X stack_top += 1 Current_mid = get_middle(Current_low,Current_high) decision_boundary = Current_mid @@ -569,7 +569,7 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, elseif Query_high == decision_boundary if (Current_low == Current_high) - stack[stack_top] = empty_node + @inbounds stack[stack_top] = empty_node stack_top -= 1 X.value = X.density = value reconstruct_stack!(stack,empty_node,old_stack_top,stack_top-1) @@ -611,19 +611,19 @@ function construct_right_children!(X::T, Query_high, Current_low, Current_high, end #= -function propagate_density!(X::Segment_tree_node) +function propagate_density!(X::SegmentTreeNode) get_left_child(X).density = get_right_child(X).density end =# -function debug_print(X::Segment_tree) +function debug_print(X::SegmentTree) println("Debug printing: ",1,"-",sizeof(X)) debug_print(X.head, 1, 1, sizeof(X)) println("end debug print") end -function debug_print(X::Segment_tree_node, indent, low, high) +function debug_print(X::SegmentTreeNode, indent, low, high) println(repeat(" ", indent),"value: ", X.value) if is_terminal(X) println(repeat(" ", indent),"density: ", X.density) @@ -637,7 +637,7 @@ function debug_print(X::Segment_tree_node, indent, low, high) end end -function check_consistency(X::Segment_tree) +function check_consistency(X::SegmentTree) consistency = check_consistency(X.head, 1, sizeof(X)) if (!consistency) println("This segment tree is currently not consistent with the invariant:.") @@ -646,7 +646,7 @@ function check_consistency(X::Segment_tree) return consistency end -function check_consistency(X::Segment_tree_node, low, high) +function check_consistency(X::SegmentTreeNode, low, high) if is_terminal(X) return low <= high && get_iterated_op(X)(X.density,high-low+1) == X.value else diff --git a/test/test_segment_tree.jl b/test/test_segment_tree.jl index 1d6cdcf60..6491e8ac2 100644 --- a/test/test_segment_tree.jl +++ b/test/test_segment_tree.jl @@ -64,7 +64,7 @@ end @testset "segment_tree" begin rng = MersenneTwister(1234) #A strong rng needed. @testset "Add" begin - X1 = Segment_tree(UInt64,100,Base.:+) + X1 = SegmentTree(UInt64,100,Base.:+) a = zeros(UInt64, 100) set_range!(X1, 37,53, 3) set_range!(X1, 23,45, 9) @@ -80,7 +80,7 @@ end @testset "Small_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. - X1 = Segment_tree(UInt64,15, Base.:+) + X1 = SegmentTree(UInt64,15, Base.:+) X2 = zeros(UInt64, 15) for i in 1:1000 a = rand(rng,1:15) @@ -96,7 +96,7 @@ end end @testset "XL_array" begin - X1 = Segment_tree(UInt64,1000000, Base.:+) + X1 = SegmentTree(UInt64,1000000, Base.:+) X2 = zeros(UInt64, 1000000) for i in 1:100 a = rand(rng,1:1000000) @@ -113,7 +113,7 @@ end @testset "Large_randomized_trial" begin #Don't worry about the overflow. This is unsigned integer. - X1 = Segment_tree(UInt64,10000, Base.:+) + X1 = SegmentTree(UInt64,10000, Base.:+) X2 = zeros(UInt64, 10000) for i in 1:10000 a = rand(rng,1:10000) @@ -128,7 +128,7 @@ end end @testset "Xor_trial" begin - X1 = Segment_tree(UInt64,10000, xor) + X1 = SegmentTree(UInt64,10000, xor) X2 = zeros(UInt64, 10000) for i in 1:10000 a = rand(rng,1:10000) @@ -142,7 +142,7 @@ end end end @testset "Vector_add" begin - X1 = Segment_tree(Array{UInt64,1},1000, +) + X1 = SegmentTree(Array{UInt64,1},1000, +) identity_vec = zeros(UInt64,5) #Vector of vector may not be the most efficient, but it should work without problem. X2 = [identity_vec for i in 1:1000] @@ -176,7 +176,7 @@ end @testset "3x3_matrix_multiplication" begin #Float/etc should work fine as well. Just don't want to deal with precision issues. - X1 = Segment_tree(Array{UInt64,2},1000, *) + X1 = SegmentTree(Array{UInt64,2},1000, *) identity_matrix = zeros(UInt64,(3,3)) identity_matrix[1,1] = identity_matrix[2,2] = identity_matrix[3,3] = 1 #Vector of vector may not be the most efficient, but it should work without problem. @@ -210,7 +210,7 @@ end @testset "String_concat" begin String_choice = ["A", "B", "C", "D", "E", "AA", "BFFG","ATL", "Moon", "Hey"] #The words are random. The acronym's reference are coincidental. - X1 = Segment_tree(String, 10000, Base.:*) + X1 = SegmentTree(String, 10000, Base.:*) X2 = ["" for i in 1:10000] for i in 1:10000 @@ -227,7 +227,7 @@ end @testset "Quarternion_test" begin test_type = Quarternion{UInt64} identity = test_type(1,0,0,0) - X1 = Segment_tree(test_type, 10000, Base.:*; identity=identity) + X1 = SegmentTree(test_type, 10000, Base.:*; identity=identity) X2 = [identity for i in 1:10000] for i in 1:10000 a = rand(rng,1:10000) From 83070f8d365eca1b4f4dae13ddb1987f776ca1c7 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 19 Jul 2022 19:39:10 +0700 Subject: [PATCH 88/91] Create bench_segment_tree.jl --- benchmark/bench_segment_tree.jl | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 benchmark/bench_segment_tree.jl diff --git a/benchmark/bench_segment_tree.jl b/benchmark/bench_segment_tree.jl new file mode 100644 index 000000000..6346b076e --- /dev/null +++ b/benchmark/bench_segment_tree.jl @@ -0,0 +1,122 @@ +using DataStructures +using BenchmarkTools +using Random + + + + + + +#The two can be interspersed as you like, but these could be separate too. +rng = Random.MersenneTwister(182936851) +Trials_count = 10000000 +Tree_size = 3000000 +Seg_tree = SegmentTree(UInt64, Tree_size, +) + +function fill_array!(rng, Trials_count, Seg_tree, Tree_size) + for i in 1:Trials_count + a = rand(rng,1:Tree_size) + b = rand(rng,a:Tree_size) + c = rand(rng, UInt64) + set_range!(Seg_tree,a,b,c) + end +end + +function use_array(rng, Trials_count, Seg_tree, Tree_size) + ans = UInt64(0) + for i in 1:Trials_count + a = rand(rng,1:Tree_size) + b = rand(rng,a:Tree_size) + ans += get_range(Seg_tree,a,b) + end + return ans +end + +function fill_use_array!(rng, Trials_count, Seg_tree, Tree_size) + ans = UInt64(0) + for i in 1:Trials_count + a = rand(rng,1:Tree_size) + b = rand(rng,a:Tree_size) + c = rand(rng, UInt64) + set_range!(Seg_tree,a,b,c) + d = rand(rng,1:Tree_size) + e = rand(rng,a:Tree_size) + ans += get_range(Seg_tree,d,e) + end + return ans +end + +function bench_rng_time(rng, Tree_size) + for i in 1:Trials_count + a = rand(rng,1:Tree_size) + b = rand(rng,a:Tree_size) + c = rand(rng, UInt64) + end +end + +function bench_rng_time_2(rng, Tree_size) + for i in 1:Trials_count + a = rand(rng,1:Tree_size) + b = rand(rng,a:Tree_size) + end +end + +function bench_rng_time_3(rng, Tree_size) + for i in 1:Trials_count + a = rand(rng,1:Tree_size) + b = rand(rng,a:Tree_size) + c = rand(rng, UInt64) + #set_range!(Seg_tree,a,b,c) + d = rand(rng,1:Tree_size) + e = rand(rng,a:Tree_size) + end +end + +println("Filling array:") +@time fill_array!(rng, Trials_count, Seg_tree, Tree_size) +println("rng use time:") +@time bench_rng_time(rng,Tree_size) +println("Using array:") +@time a1 = use_array(rng, Trials_count, Seg_tree, Tree_size) +println("rng use time:") +@time bench_rng_time_2(rng,Tree_size) +println("Filling and using array:") +@time a2 = fill_use_array!(rng, Trials_count, Seg_tree, Tree_size) +println("rng use time:") +@time bench_rng_time_3(rng,Tree_size) + +println("To ensure things are correct. ", a1, " ", a2) + + +#= +Bench times +My old c++ code. +Time to fill array: 19.5439 +Time to use array: 14.9069 +Rng_time_usage: 1.33407 +Test passed + +My New Julia code. + +Filling array: + 42.910419 seconds (938.36 M allocations: 27.966 GiB, 10.03% gc time, 0.05% compilation time) +rng use time: + 0.889469 seconds (30.02 M allocations: 611.754 MiB, 7.59% gc time, 3.92% compilation time) +Using array: + 1.517290 seconds (28.90 k allocations: 1.763 MiB, 0.99% compilation time) +rng use time: + 0.828135 seconds (30.02 M allocations: 611.670 MiB, 7.77% gc time, 1.66% compilation time) +Filling and using array: + 45.114268 seconds (938.49 M allocations: 27.970 GiB, 9.70% gc time, 0.11% compilation time) +rng use time: + 1.060329 seconds (30.03 M allocations: 611.882 MiB, 6.14% gc time, 2.44% compilation time) +To ensure things are correct. 3311231602528483331 15847214091098195660 + + +The old c++ code was twice as fast playing with set_range!, but Julia's get_range is much faster. + +My Julia code. + + +=# + From d2d935f3d3086033fb557986cee2ea3680b084f1 Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 19 Jul 2022 19:42:11 +0700 Subject: [PATCH 89/91] Moving benchmark code. --- {benchmark => test}/bench_segment_tree.jl | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {benchmark => test}/bench_segment_tree.jl (100%) diff --git a/benchmark/bench_segment_tree.jl b/test/bench_segment_tree.jl similarity index 100% rename from benchmark/bench_segment_tree.jl rename to test/bench_segment_tree.jl From 1ff9784f369c82bb8de762eb58e88c469f4f34bd Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Tue, 19 Jul 2022 19:46:34 +0700 Subject: [PATCH 90/91] Update bench_segment_tree.jl --- test/bench_segment_tree.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bench_segment_tree.jl b/test/bench_segment_tree.jl index 6346b076e..9b4ee17ff 100644 --- a/test/bench_segment_tree.jl +++ b/test/bench_segment_tree.jl @@ -113,7 +113,7 @@ rng use time: To ensure things are correct. 3311231602528483331 15847214091098195660 -The old c++ code was twice as fast playing with set_range!, but Julia's get_range is much faster. +The old c++ code was about twice as fast playing with set_range!, but Julia's get_range is much faster. My Julia code. From 617fe3ba7f5a9dcbdae33167e904896ce259adda Mon Sep 17 00:00:00 2001 From: AliceRoselia <63040919+AliceRoselia@users.noreply.github.com> Date: Wed, 20 Jul 2022 10:45:00 +0700 Subject: [PATCH 91/91] Create segment_tree.md --- docs/src/segment_tree.md | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/src/segment_tree.md diff --git a/docs/src/segment_tree.md b/docs/src/segment_tree.md new file mode 100644 index 000000000..a9eaf224a --- /dev/null +++ b/docs/src/segment_tree.md @@ -0,0 +1,51 @@ +# SegmentTree + +The Segment tree is a data structure implicitly representing an array with a reduce operation. It has two operations. +set_range Sets the value of the array from a to b. +get_range calculates the reduced value of the sub-array from element a to element b, using the provided operation. +The array is implicit. + +# Constructor + +The recommended way is to use the constructor function as follow + +```julia +function SegmentTree(type::Type, size, op; iterated_op=nothing, identity=nothing) +# type: the type of the argument. +# size: the array size. +# op: the function taking two arguments of type specified, outputting one answer of that type. (function (type,type)->type) +# Must be associative. That is, op(op(a,b),c) must be equal to op(a, op(b,c)) for every a, b, and c. +# +# iterated_op: optional function, taking two arguments, equivalent to reducing the same value to a single value +# For example, the iterated_op of +(addition) would be *(multiplication) and the iterated_op of *(multiplication) would be ^(exponentiation). +# If not provided and specialized repeat_op not possible, it would fall back to using the "exponentiation by squaring" rule. +# function iterated_op(base, n) +# identity: the element with the property op(a, identity) == op(identity, a) == a for all a. +# If not provided, and no specialized identity is made, +# a singleton struct called "artificial_identity" will be used and the operations will be altered slightly to handle these cases. +# That means that the value stored would be a union of the type you specified and this special type. +# If the identity is not of bits type (can be tested with isbits), must instead be represented via a function ()->identity. + +#Implicitly sets the array to identity for every element. +``` +# API +The recommended API uses. Other methods implement the inner working of the data structure and should not be used. +```julia +function get_range(X::SegmentTree,low,high) +#returns reduce(op, array[low:high]) implicitly. O(logn) complexity where n is the size of the array. +function set_range!(X::SegmentTree, low, high, value) +#Equivalent to setting every element of the array from array[low] to array[high] to value "value". O(logn) complexity. +``` + +# Correctness +This was tested on multiple test cases. + +# Benchmark +This segment tree has a slower, but still acceptable performance on set_range! compared to my old c++ code, +but a very fast get_range performance. + +# Abstract Segment trees +This file provides a baseline abstract Segment tree as a baseline structure for those who want to make their own variants. +Please note that since the segment tree is not a single algorithm, but a set of algorithms, there will be many variants supporting different operations +with varying complexity. The author simply provides one basic variant of it, but feel free to extend the code. +