@@ -88,9 +88,70 @@ iscanonical(t::RootedTree) = t.iscanonical
88
88
# TODO : Validate rooted tree in constructor?
89
89
90
90
Base. copy (t:: RootedTree ) = RootedTree (copy (t. level_sequence), t. iscanonical)
91
+ Base. similar (t:: RootedTree ) = RootedTree (similar (t. level_sequence), true )
91
92
Base. isempty (t:: RootedTree ) = isempty (t. level_sequence)
92
93
Base. empty (t:: RootedTree ) = RootedTree (empty (t. level_sequence), iscanonical (t))
93
94
95
+ @inline function Base. copy! (t_dst:: RootedTree , t_src:: RootedTree )
96
+ copy! (t_dst. level_sequence, t_src. level_sequence)
97
+ return t_dst
98
+ end
99
+
100
+ """
101
+ unsafe_deleteat!(t::AbstractRootedTree, i)
102
+
103
+ Delete the node `i` from the rooted tree `t`. This is an unsafe operation
104
+ since the rooted tree will not necessarily be in canonical representation
105
+ afterwards, even if the corresponding flag of `t` is set. Use with caution!
106
+
107
+ !!! warn "Internal interface"
108
+ This function is considered to be an internal implementation detail and
109
+ will not necessarily be stable.
110
+ """
111
+ @inline function unsafe_deleteat! (t:: RootedTree , i)
112
+ deleteat! (t. level_sequence, i)
113
+ return t
114
+ end
115
+
116
+ """
117
+ unsafe_resize!(t::AbstractRootedTree, n::Integer)
118
+
119
+ Resize the rooted tree `t` to `n` nodes. This is an unsafe operation
120
+ since the rooted tree will not necessarily be in canonical representation
121
+ afterwards, even if the corresponding flag of `t` is set. Use with caution!
122
+
123
+ !!! warn "Internal interface"
124
+ This function is considered to be an internal implementation detail and
125
+ will not necessarily be stable.
126
+ """
127
+ @inline function unsafe_resize! (t:: RootedTree , n:: Integer )
128
+ resize! (t. level_sequence, n)
129
+ return t
130
+ end
131
+
132
+ """
133
+ unsafe_copyto!(t_dst::AbstractRootedTree, dst_offset,
134
+ t_src::AbstractRootedTree, src_offset, N)
135
+
136
+ Copy `N`` nodes from `t_src` starting at offset `src_offset` to `t_dst`
137
+ starting at offset `dst_offset`. The types of the rooted trees must match.
138
+ For example, you cannot copy a [`ColoredRootedTree`](@ref) to a
139
+ [`RootedTree`](@ref).
140
+
141
+ This is an unsafe operation since the rooted tree `t_dst` will not necessarily
142
+ be in canonical representation afterwards, even if the corresponding flag
143
+ of `t_dst` is set. Use with caution!
144
+
145
+ !!! warn "Internal interface"
146
+ This function is considered to be an internal implementation detail and
147
+ will not necessarily be stable.
148
+ """
149
+ @inline function unsafe_copyto! (t_dst:: RootedTree , dst_offset,
150
+ t_src:: RootedTree , src_offset, N)
151
+ copyto! (t_dst. level_sequence, dst_offset, t_src. level_sequence, src_offset, N)
152
+ return t_dst
153
+ end
154
+
94
155
95
156
# #function RootedTree(sequence::Vector{T}, valid::Bool)
96
157
# function RootedTree(sequence::Array{T,1})
526
587
527
588
528
589
# partitions
529
- # TODO : partitions; add documentation in the README to make them public API
530
590
"""
531
591
partition_forest(t::RootedTree, edge_set)
532
592
582
642
583
643
584
644
"""
585
- PartitionForestIterator(t::RootedTree , edge_set)
645
+ PartitionForestIterator(t::AbstractRootedTree , edge_set)
586
646
587
647
Lazy iterator representation of the [`partition_forest`](@ref) of the rooted
588
648
tree `t`.
@@ -601,30 +661,30 @@ Section 2.3 of
601
661
Foundations of Computational Mathematics
602
662
[DOI: 10.1007/s10208-010-9065-1](https://doi.org/10.1007/s10208-010-9065-1)
603
663
"""
604
- struct PartitionForestIterator{T, V, Tree<: RootedTree{T, V} }
605
- t :: Tree
606
- level_sequence :: V
664
+ struct PartitionForestIterator{Tree<: AbstractRootedTree }
665
+ t_iter :: Tree # return value from `iterate`
666
+ t_temp :: Tree # internal temporary buffer
607
667
edge_set:: Vector{Bool}
608
668
end
609
669
610
- function PartitionForestIterator (t:: RootedTree , edge_set)
611
- level_sequence = copy (t. level_sequence )
612
- t_iterate = RootedTree ( copy (level_sequence), true )
613
- PartitionForestIterator (t_iterate, level_sequence , copy (edge_set))
670
+ function PartitionForestIterator (t:: AbstractRootedTree , edge_set)
671
+ t_iter = copy (t)
672
+ t_temp = copy (t )
673
+ PartitionForestIterator (t_iter, t_temp , copy (edge_set))
614
674
end
615
675
616
676
Base. IteratorSize (:: Type{<:PartitionForestIterator} ) = Base. HasLength ()
617
677
Base. length (forest:: PartitionForestIterator ) = count (== (false ), forest. edge_set) + 1
618
- Base. eltype (:: Type{PartitionForestIterator{T, V, Tree}} ) where {T, V, Tree} = Tree
678
+ Base. eltype (:: Type{PartitionForestIterator{Tree}} ) where {Tree} = Tree
619
679
620
680
@inline function Base. iterate (forest:: PartitionForestIterator )
621
681
iterate (forest, lastindex (forest. edge_set))
622
682
end
623
683
624
684
@inline function Base. iterate (forest:: PartitionForestIterator , search_start)
625
- t = forest. t
685
+ t_iter = forest. t_iter
686
+ t_temp = forest. t_temp
626
687
edge_set = forest. edge_set
627
- level_sequence = forest. level_sequence
628
688
629
689
# We use `search_start = typemin(Int)` to indicate that we have already
630
690
# returned the final tree in the previous call.
@@ -636,31 +696,31 @@ end
636
696
637
697
# There are no further edges to remove and we can return the final tree.
638
698
if edge_to_remove === nothing
639
- resize! (t . level_sequence, length (level_sequence ))
640
- copy! (t . level_sequence, level_sequence )
641
- canonical_representation! (t )
642
- return (t , typemin (Int))
699
+ unsafe_resize! (t_iter, order (t_temp ))
700
+ copy! (t_iter, t_temp )
701
+ canonical_representation! (t_iter )
702
+ return (t_iter , typemin (Int))
643
703
end
644
704
645
705
# On to the next subtree
646
706
# Remember the convention node = edge + 1
647
707
subtree_root_index = edge_to_remove + 1
648
- subtree_last_index = _subtree_last_index (subtree_root_index, level_sequence)
708
+ subtree_last_index = _subtree_last_index (subtree_root_index, t_temp . level_sequence)
649
709
subtree_length = subtree_last_index - subtree_root_index + 1
650
710
651
711
# Since we search from the end, there is no additional edge that needs to
652
712
# be removed in the current subtree. Thus, we can return it as the next
653
713
# iterate of the partition forest
654
- resize! (t . level_sequence , subtree_length)
655
- copyto! (t . level_sequence , 1 , level_sequence , subtree_root_index, subtree_length)
656
- canonical_representation! (t )
714
+ unsafe_resize! (t_iter , subtree_length)
715
+ unsafe_copyto! (t_iter , 1 , t_temp , subtree_root_index, subtree_length)
716
+ canonical_representation! (t_iter )
657
717
658
- # Now, we can remove the next subtree iterate from the active `level_sequence`
659
- # and `edge_set`.
660
- deleteat! (level_sequence , subtree_root_index: subtree_last_index)
718
+ # Now, we can remove the next subtree iterate from the active
719
+ # level sequence in `t_temp` and the `edge_set`.
720
+ unsafe_deleteat! (t_temp , subtree_root_index: subtree_last_index)
661
721
deleteat! (edge_set, subtree_root_index- 1 : subtree_last_index- 1 )
662
722
663
- return (t , edge_to_remove - 1 )
723
+ return (t_iter , edge_to_remove - 1 )
664
724
end
665
725
666
726
# necessary for simple and convenient use since the iterates may be modified
@@ -674,36 +734,37 @@ function Base.collect(forest::PartitionForestIterator)
674
734
end
675
735
676
736
677
- # TODO : partitions; add documentation in the README to make them public API
678
737
"""
679
- partition_skeleton(t::RootedTree , edge_set)
738
+ partition_skeleton(t::AbstractRootedTree , edge_set)
680
739
681
- Form the partition skeleton of the rooted tree `t`, i.e., the rooted tree obtained
682
- by contracting each tree of the partition forest to a single vertex and re-establishing
683
- the edges removed to obtain the partition forest.
740
+ Form the partition skeleton of the rooted tree `t`, i.e., the rooted tree
741
+ obtained by contracting each tree of the partition forest to a single vertex
742
+ and re-establishing the edges removed to obtain the partition forest.
684
743
685
744
See also [`partition_forest`](@ref) and [`PartitionIterator`](@ref).
686
745
687
746
# References
688
747
689
- Section 2.3 of
748
+ Section 2.3 (and Section 6.1 for colored trees) of
690
749
- Philippe Chartier, Ernst Hairer, Gilles Vilmart (2010)
691
750
Algebraic Structures of B-series.
692
751
Foundations of Computational Mathematics
693
752
[DOI: 10.1007/s10208-010-9065-1](https://doi.org/10.1007/s10208-010-9065-1)
694
753
"""
695
- function partition_skeleton (t:: RootedTree , edge_set)
754
+ function partition_skeleton (t:: AbstractRootedTree , edge_set)
696
755
@boundscheck begin
697
- @assert length (t . level_sequence ) == length (edge_set) + 1
756
+ @assert order (t ) == length (edge_set) + 1
698
757
end
699
758
700
759
edge_set_copy = copy (edge_set)
701
- skeleton = RootedTree ( copy (t. level_sequence), true )
702
- return partition_skeleton! (skeleton. level_sequence , edge_set_copy)
760
+ skeleton = copy (t)
761
+ return partition_skeleton! (skeleton, edge_set_copy)
703
762
end
704
763
705
764
# internal in-place version of partition_skeleton modifying the inputs
706
- function partition_skeleton! (level_sequence, edge_set)
765
+ function partition_skeleton! (skeleton:: AbstractRootedTree , edge_set)
766
+ level_sequence = skeleton. level_sequence
767
+
707
768
# Iterate over all edges that shall be kept/contracted.
708
769
# We start the iteration at the end since this will result in less memory
709
770
# moves because we have already reduced the size of the vectors when reaching
@@ -725,19 +786,18 @@ function partition_skeleton!(level_sequence, edge_set)
725
786
end
726
787
727
788
# Remove the root node
728
- deleteat! (level_sequence , subtree_root_index)
789
+ unsafe_deleteat! (skeleton , subtree_root_index)
729
790
deleteat! (edge_set, edge_to_contract)
730
791
731
792
edge_to_contract = findprev (edge_set, edge_to_contract - 1 )
732
793
end
733
794
734
795
# The level sequence `level_sequence` will not automatically be a canonical
735
796
# representation.
736
- return rootedtree! (level_sequence )
797
+ canonical_representation! (skeleton )
737
798
end
738
799
739
800
740
- # TODO : partitions; add documentation in the README to make them public API
741
801
"""
742
802
all_partitions(t::RootedTree)
743
803
784
844
785
845
786
846
"""
787
- PartitionIterator(t::RootedTree )
847
+ PartitionIterator(t::AbstractRootedTree )
788
848
789
849
Iterator over all partition forests and skeletons of the rooted tree `t`.
790
850
This is basically a pure iterator version of [`all_partitions`](@ref).
@@ -804,29 +864,32 @@ Section 2.3 of
804
864
Foundations of Computational Mathematics
805
865
[DOI: 10.1007/s10208-010-9065-1](https://doi.org/10.1007/s10208-010-9065-1)
806
866
"""
807
- struct PartitionIterator{T, Tree <: RootedTree{T} }
808
- t:: Tree
809
- forest:: PartitionForestIterator{T, Vector{T}, RootedTree{T, Vector{T}} }
810
- skeleton:: RootedTree{T, Vector{T}}
867
+ struct PartitionIterator{TreeInput <: AbstractRootedTree , TreeOutput <: AbstractRootedTree }
868
+ t:: TreeInput
869
+ forest:: PartitionForestIterator{TreeOutput }
870
+ skeleton:: TreeOutput
811
871
edge_set:: Vector{Bool}
812
872
edge_set_tmp:: Vector{Bool}
813
873
end
814
874
815
- function PartitionIterator (t:: Tree ) where {T, Tree <: RootedTree{T} }
816
- skeleton = RootedTree ( Vector {T} (undef, order (t)), true )
875
+ function PartitionIterator (t:: AbstractRootedTree )
876
+ skeleton = similar (t )
817
877
edge_set = Vector {Bool} (undef, order (t) - 1 )
818
878
edge_set_tmp = similar (edge_set)
819
879
820
- t_forest = RootedTree ( Vector {T} (undef, order (t)), true )
821
- level_sequence = similar (t_forest . level_sequence )
822
- forest = PartitionForestIterator (t_forest, level_sequence , edge_set_tmp)
823
- PartitionIterator {T, Tree } (t, forest, skeleton, edge_set, edge_set_tmp)
880
+ t_forest = similar (t )
881
+ t_temp_forest = similar (t )
882
+ forest = PartitionForestIterator (t_forest, t_temp_forest , edge_set_tmp)
883
+ PartitionIterator {typeof(t), typeof(skeleton) } (t, forest, skeleton, edge_set, edge_set_tmp)
824
884
end
825
885
826
886
# Allocate global buffer for `PartitionIterator` for each thread
827
887
const PARTITION_ITERATOR_BUFFER_FOREST_T = Vector {Vector{Int}} ()
888
+ const PARTITION_ITERATOR_BUFFER_FOREST_T_COLORS = Vector {Vector{Bool}} ()
828
889
const PARTITION_ITERATOR_BUFFER_FOREST_LEVEL_SEQUENCE = Vector {Vector{Int}} ()
890
+ const PARTITION_ITERATOR_BUFFER_FOREST_COLOR_SEQUENCE = Vector {Vector{Bool}} ()
829
891
const PARTITION_ITERATOR_BUFFER_SKELETON = Vector {Vector{Int}} ()
892
+ const PARTITION_ITERATOR_BUFFER_SKELETON_COLORS = Vector {Vector{Bool}} ()
830
893
const PARTITION_ITERATOR_BUFFER_EDGE_SET = Vector {Vector{Bool}} ()
831
894
const PARTITION_ITERATOR_BUFFER_EDGE_SET_TMP = Vector {Vector{Bool}} ()
832
895
@@ -856,15 +919,16 @@ function PartitionIterator(t::RootedTree{Int, Vector{Int}})
856
919
857
920
skeleton = RootedTree (buffer_skeleton, true )
858
921
t_forest = RootedTree (buffer_forest_t, true )
859
- forest = PartitionForestIterator (t_forest, level_sequence, edge_set_tmp)
860
- PartitionIterator {Int, RootedTree{Int, Vector{Int}}} (
922
+ t_temp_forest = RootedTree (level_sequence, true )
923
+ forest = PartitionForestIterator (t_forest, t_temp_forest, edge_set_tmp)
924
+ PartitionIterator {typeof(t), RootedTree{Int, Vector{Int}}} (
861
925
t, forest, skeleton, edge_set, edge_set_tmp)
862
926
end
863
927
864
928
865
929
Base. IteratorSize (:: Type{<:PartitionIterator} ) = Base. HasLength ()
866
930
Base. length (partitions:: PartitionIterator ) = 2 ^ length (partitions. edge_set)
867
- Base. eltype (:: Type{PartitionIterator{T, Tree }} ) where {T, Tree } = Tuple{Vector{RootedTree{T, Vector{T}}}, RootedTree{T, Vector{T}} }
931
+ Base. eltype (:: Type{PartitionIterator{TreeInput, TreeOutput }} ) where {TreeInput, TreeOutput } = Tuple{PartitionForestIterator{TreeOutput}, TreeOutput }
868
932
869
933
@inline function Base. iterate (partitions:: PartitionIterator )
870
934
edge_set_value = 0
@@ -888,26 +952,26 @@ end
888
952
# avoiding some allocations.
889
953
resize! (edge_set_tmp, length (edge_set))
890
954
copy! (edge_set_tmp, edge_set)
891
- resize ! (skeleton. level_sequence , order (t))
892
- copy! (skeleton. level_sequence , t. level_sequence )
893
- partition_skeleton! (skeleton. level_sequence , edge_set_tmp)
955
+ unsafe_resize ! (skeleton, order (t))
956
+ copy! (skeleton, t)
957
+ partition_skeleton! (skeleton, edge_set_tmp)
894
958
895
959
# Compute the partition forest.
896
960
# The following is a more efficient version of
897
961
# forest = partition_forest(t, edge_set)
898
962
# avoiding some allocations and using a lazy iterator.
899
963
resize! (edge_set_tmp, length (edge_set))
900
964
copy! (edge_set_tmp, edge_set)
901
- resize ! (forest. level_sequence , order (t))
902
- copy! (forest. level_sequence , t. level_sequence )
965
+ unsafe_resize ! (forest. t_temp , order (t))
966
+ copy! (forest. t_temp , t)
903
967
904
968
905
969
((forest, skeleton), edge_set_value + 1 )
906
970
end
907
971
908
972
# necessary for simple and convenient use since the iterates may be modified
909
- function Base. collect (partitions:: PartitionIterator )
910
- iterates = Vector {eltype(partitions) } ()
973
+ function Base. collect (partitions:: PartitionIterator{TreeInput, TreeOutput} ) where {TreeInput, TreeOutput}
974
+ iterates = Vector {Tuple{Vector{TreeOutput}, TreeOutput} } ()
911
975
sizehint! (iterates, length (partitions))
912
976
for (forest, skeleton) in partitions
913
977
push! (iterates, (collect (forest), copy (skeleton)))
918
982
919
983
920
984
# splittings
921
- # TODO : splittings; add documentation in the README to make them public API
922
985
"""
923
986
all_splittings(t::RootedTree)
924
987
@@ -1290,10 +1353,16 @@ function __init__()
1290
1353
# PartitionIterator
1291
1354
Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_FOREST_T,
1292
1355
Vector {Int} (undef, BUFFER_LENGTH))
1356
+ Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_FOREST_T_COLORS,
1357
+ Vector {Int} (undef, BUFFER_LENGTH))
1293
1358
Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_FOREST_LEVEL_SEQUENCE,
1294
1359
Vector {Int} (undef, BUFFER_LENGTH))
1360
+ Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_FOREST_COLOR_SEQUENCE,
1361
+ Vector {Bool} (undef, BUFFER_LENGTH))
1295
1362
Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_SKELETON,
1296
1363
Vector {Int} (undef, BUFFER_LENGTH))
1364
+ Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_SKELETON_COLORS,
1365
+ Vector {Bool} (undef, BUFFER_LENGTH))
1297
1366
Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_EDGE_SET,
1298
1367
Vector {Bool} (undef, BUFFER_LENGTH))
1299
1368
Threads. resize_nthreads! (PARTITION_ITERATOR_BUFFER_EDGE_SET_TMP,
0 commit comments