8def equidistant_splitting(peano_tree: Tree,
9 number_of_subtrees: int,
13 if number_of_subtrees <= 1:
14 return no_split_result(
15 f
"No splitting requested (number_of_subtrees = {number_of_subtrees})."
18 total_leaves = peano_tree.number_of_leaves
21 print(
"No leaf nodes found in subtree 0 to split.")
25 leaves_per_subtree, remaining_leaves = divmod(total_leaves, number_of_subtrees)
29 leaves_per_subtree + (1
if subtree_id < remaining_leaves
else 0)
30 for subtree_id
in range(number_of_subtrees)
35 f
"Splitting tree '{peano_tree._name}' into "
36 f
"{number_of_subtrees} subtrees (staged workflow)"
38 print(f
"Found {total_leaves} leaf nodes across all levels for decomposition")
39 print(f
"Target decomposition: {leaves_per_subtree} leaves per subtree, {remaining_leaves} extra leaves that have to be distributed among other trees")
40 print(f
"Decomposition plan: {decomposition}")
46 number_of_subtrees: int,
54 This splitting starts from a perfect splitting as we find it in
55 equidistant_splitting(), but then it picks partitions of the type
56 @f$ 1 \\cdot 3^{kd}, 2 \\cdot 3^{kd}, ..., (3^d-1) \\cdot 3^{kd}, 1 \\cdot 3^{(k+1)d}, 2 \\cdot 3^{(k+1)d}, ... @f$
60 - Determine optimal number of splittings
61 - Introduce a residual counter. As the number of leaves typically does not
62 exactly fit to number_of_subtrees, this is the remainder of the modulo
64 - Identify smallest chunk from sequence above that literally just fits.
65 - Add the cells that should have been added to this chunk (due to the
66 optimal decomposition) but cannot be added (due to the quantisation from
67 the sequence above) to the residual.
68 - Next step, increase the optimum threshold by the residual.
72 if number_of_subtrees <= 1:
73 return no_split_result(
74 f
"No splitting requested (number_of_subtrees = {number_of_subtrees})."
77 total_leaves = peano_tree.number_of_leaves
80 print(
"No leaf nodes found in subtree 0 to split.")
84 optimal_leaves_per_subtree, residual_leaves = divmod(total_leaves, number_of_subtrees)
88 for i
in range(number_of_subtrees):
90 current_step_size = 3**dimension
91 while (current_chunk<optimal_leaves_per_subtree+residual_leaves):
92 if current_chunk == current_step_size * 3**dimension:
93 current_step_size *= 3**dimension
94 current_chunk += current_step_size
95 current_chunk -= current_step_size
96 residual_leaves += optimal_leaves_per_subtree - current_chunk
97 assert residual_leaves>=0,
"residual leaves = {}".format(residual_leaves)
98 decomposition.append(current_chunk)
99 print(f
"append {current_chunk} and maintain residual {residual_leaves} with optimum {optimal_leaves_per_subtree}. New target {optimal_leaves_per_subtree+residual_leaves}")
101 decomposition[-1] += residual_leaves
103 assert sum(decomposition)==total_leaves,
"{} vs {}".format(sum(decomposition),total_leaves)
107 f
"Splitting tree '{peano_tree._name}' into "
108 f
"{number_of_subtrees} subtrees (staged workflow)"
110 print(f
"Found {total_leaves} leaf nodes across all levels for decomposition")
111 print(f
"Target decomposition: {optimal_leaves_per_subtree} leaves per subtree")
112 print(f
"Decomposition plan: {decomposition}")