Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
    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))
Ejemplo n.º 7
0
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())