def racc(self, f, unit_f): """Makes a rightward accumulation of the values in the current instance rAcc (+) (RNode a ts) = let rs = scanl (+) [root ts[i] | i in [1 .. #ts]] in RNode unit_(+) [setroot (rAcc (+) ts[i]) r[i] | i in [1 .. #ts]] Parameters ---------- f : callable A function to accumulate the value of the current instance with the current accumulator unit_f A value such as, forall value, f(value, unit_f) = value """ rv = self.get_children().map(lambda x: x.get_value()) rs = rv.scanl(f, unit_f) ch = SList() ch0 = self.get_children() for i in range(0, ch0.length()): c = ch0[i] cs = c.racc(f, unit_f) cs.set_value(rs[i]) ch.append(cs) return RNode(unit_f, ch)
def test_r2b_1(): ch = SList() ch.append(RNode(2)) ch.append(RNode(3)) rn = RNode(1, ch) res = rn.r2b() exp = Node(1, Node(2, Leaf(None), Node(3, Leaf(None), Leaf(None))), Leaf(None)) assert res == exp
def random_list(frdm, size): """ Generates a random list of the given ``size``. Each element is generated by a call to ``frdm``. ``size`` should be strictly positive. :param frdm: callable :param size: int :return: list """ assert size >= 0 res = SList([]) for _ in range(size): res.append(frdm()) return res
def zip(self, rt): """Zip the values contained in a second RTree with the ones in the current instance Precondition ------------- The lengths of self.children and rt.children should be equal Parameters ---------- rt : :obj:`RTree` The RTree to zip with the current instance """ ch1 = self.get_children() ch2 = rt.get_children() assert ch1.length() == ch2.length( ), "The rose trees cannot be zipped (not the same shape)" ch = SList([]) for i in range(0, ch1.length()): ch.append(ch1[i].zip(ch2)) v = (self.get_value(), rt.get_value()) return RNode(v, ch)
def distribute_tree(lt, n): total_size = lt.map(fun.one, fun.one).reduce(fun.add, fun.idt, fun.add, fun.add, fun.add) avg_elements = int(total_size / n) # Definition of global_index and distribution global_index = SList([]) distribution = SList.init(lambda x: 0, n) current_pid = 0 nb_segs = 1 seg = lt[0] seg_length = seg.length() acc_size = seg_length global_index.append((0, seg_length)) for seg_i in range(1, lt.length()): seg = lt[seg_i] curr_seg_length = seg.length() # We need to give all the rest to the last processor if seg_i == lt.length() - 1: distribution[current_pid] = (nb_segs + 1) global_index.append((acc_size, curr_seg_length)) else: if current_pid == n - 1: nb_segs += 1 global_index.append((acc_size, curr_seg_length)) acc_size = acc_size + curr_seg_length else: curr_seg_length = seg.length() if abs(avg_elements - (acc_size + curr_seg_length)) > abs(avg_elements - acc_size): distribution[current_pid] = nb_segs global_index.append((0, curr_seg_length)) acc_size = curr_seg_length nb_segs = 1 current_pid += 1 else: nb_segs += 1 global_index.append((acc_size, curr_seg_length)) acc_size = acc_size + curr_seg_length return distribution, global_index
def deserialization(self): """Get a binary tree from its linear representation """ def __graft(bt, lbt, rbt): val = bt.get_value() if bt.is_node(): return Node(val, __graft(bt.get_left(), lbt, rbt), __graft(bt.get_right(), lbt, rbt)) else: # bt.is_leaf() return Node(val, lbt, rbt) if val.is_critical() else bt def __remove_annotation(bt): v = bt.get_value() return Leaf(v.get_value()) if bt.is_leaf() else Node( v.get_value(), __remove_annotation(bt.get_left()), __remove_annotation(bt.get_right())) def __lv2ibt(segment): stack = [] has_crit_b = False if segment.empty(): raise EmptyError( "An empty Segment cannot be transformed into a BTree") for i in range(segment.length() - 1, -1, -1): v = segment[i] if v.is_leaf(): stack.append(Leaf(v)) elif v.is_critical(): stack.append(Leaf(v)) if has_crit_b: raise IllFormedError( "A ill-formed Segment cannot be transformed into a BTree" ) else: has_crit_b = True else: if len(stack) < 2: raise IllFormedError( "A ill-formed Segment cannot be transformed into a BTree" ) lv = stack.pop() rv = stack.pop() stack.append(Node(v, lv, rv)) if len(stack) != 1: raise IllFormedError( "A ill-formed Segment cannot be transformed into a BTree") else: return has_crit_b, stack[0] def __rev_segment_to_trees(lb, glob): stack = [] for i in range(lb.length() - 1, -1, -1): if glob[i] == TAG_LEAF: stack.append(lb[i]) else: # gt[i] == VTag_Node lbt = stack.pop() rbt = stack.pop() stack.append(__graft(lb[i], lbt, rbt)) if len(stack) != 1: raise IllFormedError( "A ill-formed list of incomplete BTree cannot be transformed into a BTree" ) else: return stack[0] gt = SList() list_of_btree = SList() for seg in self: (has_crit, bt_i) = __lv2ibt(seg) list_of_btree.append(bt_i) if has_crit: gt.append(TAG_NODE) else: gt.append(TAG_LEAF) return __remove_annotation(__rev_segment_to_trees(list_of_btree, gt))
class RNode: """ A class used to represent a Rose Tree (a tree with an arbitrary shape) ... Methods ------- b2r(bt) Create a RNode instance from a BTree get_children() Get the children of the current RNode add_children(c) Add a children to the ones of the current RNode is_leaf() Indicates if the current RNode has no children, and then can be considered as a leaf is_node() Indicates if the current RNode has children, and then can be considered as a node get_value() Get the value of the current RNode set_value(v) Set a new value for the current RNode map(f) Applies a function to every values contained in the current instance reduce(f, g) Reduce the current instance into a single value using two operators uacc(f, g) Makes an upward accumulation of the values in a the current instance using two operators dacc(f, unit_f) Makes an downward accumulation of the values in a the current instance zip(rt) Zip the values contained in a second RTree with the ones in the current instance map2(rt, f) Zip the values contained in a second RTree with the ones in the current instance using a function racc(f, unit_f) Makes a rightward accumulation of the values in the current instance lacc(f, unit_f) Makes a leftward accumulation of the values in the current instance r2b() Get a BTree from the current instance """ def __init__(self, value, ts=None): if isinstance(value, BTree): if value == Leaf(None): raise ConstructorError( "A RTree cannot be constructed from a single Leaf that " "contains None") # Create a RTree from a BTree bt = value rt = RNode.b2r(bt) self.value = rt.get_value() self.children = rt.get_children() else: self.value = value if ts is None: self.children = SList([]) else: self.children = SList(ts) @staticmethod def b2r(bt): """ Create a RNode instance from a BTree """ def aux(btree): if btree.is_leaf(): val = btree.get_value() if val is None: return SList() return SList([RNode(val)]) n = btree.get_value() left = btree.get_left() right = btree.get_right() res_l = aux(left) res_r = aux(right) res_head = RNode(n, res_l) res_r.insert(0, res_head) return res_r return aux(bt)[0] def __str__(self): res = "rnode " + str(self.value) + "[" ch = self.get_children() for i in range(0, self.get_children().length()): if i == ch.length() - 1: res = res + str(ch[i]) else: res = res + str(ch[i]) + ", " return res + "]" def __eq__(self, other): if isinstance(other, RNode): ch1 = self.get_children() ch2 = other.get_children() if ch1.length() != ch2.length(): return False for i in range(0, ch1.length()): if ch1[i] != ch2[i]: return False return self.get_value() == other.get_value() return False def is_leaf(self): """Indicates if the current RNode has no children, and then can be considered as a leaf """ return len(self.children) == 0 def is_node(self): """Indicates if the current RNode has children, and then can be considered as a node """ return len(self.children) != 0 def get_children(self): """Get the children of the current RNode """ return self.children def add_children(self, c): """Add a children to the ones of the current RNode Parameters ---------- c The children to add """ self.children.append(c) def get_value(self): """Get the value of the current RNode """ return self.value def set_value(self, v): """Set a new value for the current RNode Parameters ---------- v The new value to set """ self.value = v def map(self, f): """Applies a function to every values contained in the current instance Parameters ---------- f : callable The function to apply to every values of the current instance """ v = f(self.get_value()) # To each element of the list of children, we apply the RNode.map function ch = self.children.map(lambda x: x.map(f)) return RNode(v, ch) def reduce(self, f, g): """Reduce the current instance into a single value using two operators Parameters ---------- f : callable A binary operator to combine all sub reduction of the children of the current instance into an intermediate reduction g : callable A binary operator to combine the value of the current instance with the intermediate reduction """ if not self.children: return self.get_value() # We calculate the reduction of each childen reductions = self.children.map(lambda x: x.reduce(f, g)) # We combine every sub reductions using g red = reductions[0] for i in range(1, reductions.length()): red = g(red, reductions[i]) # The final reduction is the result of the combination of sub reductions and the value of # the current instance return f(self.get_value(), red) def uacc(self, f, g): """Makes an upward accumulation of the values in a the current instance using two operators Parameters ---------- f : callable A binary operator to combine all top values from the accumulation within the children of the current instance into an intermediate accumulation g : callable A binary operator to combine the value of the current instance with the intermediate accumulation """ v = self.reduce(f, g) ch = self.children.map(lambda x: x.uacc(f, g)) return RNode(v, ch) def dacc(self, f, unit_f): """Makes an downward accumulation of the values in a the current instance Parameters ---------- f : callable A function to accumulate the value of the current instance with the current accumulator unit_f A value such as, forall value, f(value, unit_f) = value """ def dacc2(t, fct, c): # Auxiliary function to make an accumulation with an arbitrary accumulator return RNode( c, t.children.map(lambda x: dacc2(x, fct, fct(c, t.get_value())))) # Since the accumulator changes at each iteration, we need to use a changing parameter, not # defined in dacc. # Use of an auxiliary function, with as a first accumulator, unit_f return dacc2(self, f, unit_f) def zip(self, rt): """Zip the values contained in a second RTree with the ones in the current instance Precondition ------------- The lengths of self.children and rt.children should be equal Parameters ---------- rt : :obj:`RTree` The RTree to zip with the current instance """ ch1 = self.get_children() ch2 = rt.get_children() assert ch1.length() == ch2.length( ), "The rose trees cannot be zipped (not the same shape)" ch = SList([]) for i in range(0, ch1.length()): ch.append(ch1[i].zip(ch2)) v = (self.get_value(), rt.get_value()) return RNode(v, ch) def map2(self, rt, f): """Zip the values contained in a second RTree with the ones in the current instance using a function Precondition ------------- The lengths of self.children and rt.children should be equal Parameters ---------- rt : :obj:`RTree` The RTree to zip with the current instance f : callable A function to zip values """ ch1 = self.get_children() ch2 = rt.get_children() assert ch1.length() == ch2.length( ), "The rose trees cannot be zipped (not the same shape)" ch = SList([]) for i in range(0, ch1.length()): ch.append(ch1[i].map2(ch2, f)) v = f(self.get_value(), rt.get_value()) return RNode(v, ch) def racc(self, f, unit_f): """Makes a rightward accumulation of the values in the current instance rAcc (+) (RNode a ts) = let rs = scanl (+) [root ts[i] | i in [1 .. #ts]] in RNode unit_(+) [setroot (rAcc (+) ts[i]) r[i] | i in [1 .. #ts]] Parameters ---------- f : callable A function to accumulate the value of the current instance with the current accumulator unit_f A value such as, forall value, f(value, unit_f) = value """ rv = self.get_children().map(lambda x: x.get_value()) rs = rv.scanl(f, unit_f) ch = SList() ch0 = self.get_children() for i in range(0, ch0.length()): c = ch0[i] cs = c.racc(f, unit_f) cs.set_value(rs[i]) ch.append(cs) return RNode(unit_f, ch) def lacc(self, f, unit_f): """Makes a leftward accumulation of the values in the current instance lAcc (+) (RNode a ts) = let rs = scanp (+) [root ts[i] | i in [1 .. #ts]] in RNode unit_(+) [setroot (lAcc (+) ts[i]) r[i] | i in [1 .. #ts]] Parameters ---------- f : callable A function to accumulate the value of the current instance with the current accumulator unit_f A value such as, forall value, f(value, unit_f) = value """ rv = self.get_children().map(lambda x: x.get_value()) rs = rv.scanp(f, unit_f) ch = SList() ch0 = self.get_children() for i in range(0, ch0.length()): c = ch0[i] cs = c.lacc(f, unit_f) cs.set_value(rs[i]) ch.append(cs) return RNode(unit_f, ch) def r2b(self): """Get a BTree from the current instance """ def r2b1(t, ss): a = t.get_value() left = r2b2(t.get_children()) right = r2b2(ss) return Node(a, left, right) def r2b2(ts): if not ts: return Leaf(None) h = ts[0] t = ts[1:] return r2b1(h, t) return r2b1(self, SList())