Example #1
0
 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]
Example #2
0
 def __node_uacc_local_compute(stack, d, phi, v, psi_l, res, psi_r, i, k):
     """Computes when the value is a node"""
     if len(stack) < 2:
         raise IllFormedError(
             "uacc_local cannot be applied if there is a node that does not have two children "
             "in the current instance")
     # We get the values of two sub upward accumulation
     lv = stack.pop()
     rv = stack.pop()
     if d == 0:
         # The current node is an ancestor of a critical value by the left
         # That is, there is a critical value on its left children in a BTree representation
         # We process and stack the value of a partial accumulation
         val = phi(v.get_value())
         stack.append(psi_l(lv, val, rv))
         res[i] = None
     elif d == 1:
         # The current node is an ancestor of a critical value by the left
         # That is, there is a critical value on its left children in a BTree representation
         # We process and stack the value of a partial accumulation
         val = phi(v.get_value())
         stack.append(psi_r(lv, val, rv))
         res[i] = None
         d = 0
     else:
         # We did not meet a critical value, we can process a normal upward accumulation with k
         val = k(lv, v.get_value(), rv)
         res[i] = TaggedValue(val, v.get_tag())
         stack.append(val)
         d = d - 1
     return d, stack, res
Example #3
0
    def dacc_local(self, gl, gr, c):
        """Computes local downward accumulation for the current instance using an
        accumulative parameter resulting of a global downward accumulation

        Parameters
        ----------
        gl : callable
            Function to make a downward accumulation to the left
        gr : callable
            Function to make a downward accumulation to the right
        c
            Initial value of the accumulator

        Raises
        ------
        IllFormedError:
            If the current instance does not represent a correct linearized subtree
            That is there are several leaves that doesn't have a parent in a BTree representation
            or if there is not a value to accumulate from above
        """
        # We update not finished accumulation locally using the value from the parent in the global
        # representation of a linearized tree
        stack = [c]
        res = Segment([None] * self.length())
        for i in range(self.length()):
            v = self[i]
            if v.is_leaf() or v.is_critical():
                if len(stack) == 0:
                    raise IllFormedError(
                        "dacc_local cannot be applied if there are two leaf values, or critical "
                        "values that do not have a parent")
                # We get the accumulated value passed from the last parent
                val = stack.pop()
                res[i] = TaggedValue(val, v.get_tag())
            else:  # v.is_node()
                if len(stack) == 0:
                    raise IllFormedError(
                        "dacc_local cannot be applied if there is not a value to accumulate from "
                        "above")
                val = stack.pop()
                # We get the accumulated value passed from the last parent
                # And two new ones, one for the left children, and one to the right, using
                # the gr and gl functions
                res[i] = TaggedValue(val, v.get_tag())
                stack.append(gr(val, v.get_value()))
                stack.append(gl(val, v.get_value()))
        return res
Example #4
0
    def uacc_update(self, seg2, k, lc, rc):
        """Makes an update of the current accumulation, using initial values and the top
         accumulated values

        Precondition
        -------------
        The lengths of self and seg2 should be equal

        Parameters
        ----------
        seg2 : :obj:`Segment`
            Result of a local accumulation
        k : callable
            The function used to reduce a BTree into a single value
        lc
            Top value of the left children in a global structure
        rc
            Top value of the left children in a global structure

        Raises
        ------
        IllFormedError
            If the current instance does not represent a correct linearized subtree
            That is there is a node that doesn't have two children
        """
        assert self.length() == seg2.length(), "uacc_update cannot needs to " \
                                               "Segment of same size as input"
        stack = [rc, lc]
        d = MINUS_INFINITY
        res = Segment([None] * self.length())
        for i in reversed(range(seg2.length())):
            v1 = self[i]
            v2 = seg2[i]
            # We update the accumulation from seg2
            # We stack the values already updated to process updates on nodes
            if v1.is_leaf():
                # The result of the accumulation is the node made in seg2
                res[i] = v2
                stack.append(v2.get_value())
                d = d + 1
            elif v1.is_node():
                res, stack, d = self.__node_uacc_update_compute(
                    stack, d, res, k, v1, v2, i)
            else:  # v1.is_critical()
                if len(stack) < 2:
                    raise IllFormedError(
                        "uacc_update cannot be applied if there is a node that "
                        "does not have two children in the current instance")
                # We need two sub accumulation values to process the accumulation of a critical node
                lv = stack.pop()
                rv = stack.pop()
                val = k(lv, v1.get_value(), rv)
                res[i] = TaggedValue(val, v1.get_tag())
                stack.append(val)
                d = 0
        return res
Example #5
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"
         )
     return stack[0]
Example #6
0
    def dacc_global(self, psi_d, c):
        """Performs sequential downwards accumulation

        Precondition
        -------------
        self should bot have critical nodes

        Parameters
        ----------
        psi_d : callable
            A function used to respect the closure property on gr and gl (initial functions used for up accumulation)
            to make partial downward accumulation
        c
            Initial value of the accumulator

        Raises
        ------
        IllFormedError
            If the current instance does not represent a correct linearized subtree
            That is there are several leaves that doesn't have a parent in a BTree representation
        """
        stack = [c]
        res = Segment([None] * self.length())
        assert not self.has_critical(
        ), "dacc_global cannot be applied to Segment which contains a critical node"

        for i in range(self.length()):
            v = self[i]
            if len(stack) == 0:
                raise IllFormedError(
                    "dacc_global cannot be applied to ill-formed Segments that is two leaf values do not have a parent"
                )
            # We add the previous accumulation as a new value of our result
            val = stack.pop()
            res[i] = TaggedValue(val, v.get_tag())

            # If the current value is node, we need to update the value to pass to the right, and left children
            # These values are contained in the stack
            if v.is_node():
                (to_l, to_r) = v.get_value()
                stack.append(psi_d(val, to_r))
                stack.append(psi_d(val, to_l))
        return res
Example #7
0
    def uacc_global(self, psi_n):
        """Performs sequential upwards accumulation

        Precondition
        -------------
        self should not have critical nodes

        Parameters
        ----------
        psi_n : callable
            A function used to respect the closure property on k (the initial function used for accumulation)
            to allow partial computation

        Raises
        ------
        IllformedError
            If the current instance does not represent a correct linearized subtree
            That is there is a node that doesn't have two children
        """
        assert not self.has_critical(
        ), "uacc_global cannot be applied to a Segments which contains a critical"

        stack = []
        res = Segment([None] * self.length())
        for i in reversed(range(self.length())):
            g = self[i]
            # We process a global accumulation using a stack to store previous accumulation,
            # to get them for the accumulation on nodes
            if g.is_leaf():
                res[i] = g
                val = g.get_value()
            else:  # g.is_node()
                if len(stack) < 2:
                    raise IllFormedError(
                        "uacc_global cannot be applied if there is a node that does not have two children "
                        "in the current instance")
                lv = stack.pop()
                rv = stack.pop()
                val = psi_n(lv, g.get_value(), rv)
                res[i] = TaggedValue(val, g.get_tag())
            stack.append(val)
        # We get the top value of the accumulation
        return res
Example #8
0
    def reduce_global(self, psi_n):
        """Makes a global reduction using local reductions of Segments

        Precondition
        -------------
        self should empty, and should not have critical nodes

        Parameters
        ----------
        psi_n : callable
            A function used to respect the closure property on k
            (the initial function used for reduction) to allow partial computation

        Raises
        ------
        IllFormedError
            If the current instance does not represent a list of top values of a correct
            list of subtrees
            That is for each node, there is not exist two children, of there is a critical
            value in the current instance
        """
        assert not self.has_critical(), "reduce_global cannot be applied to a" \
                                        "Segments which contains a critical"
        assert self != [], "reduce_global cannot be applied to an empty Segment"
        stack = []
        for g in reversed(self):
            # We stack every value we already reduced
            if g.is_leaf():
                # Nothing to calculate, we only stack the value
                stack.append(g.get_value())
            else:  # g.is_node()
                # We get two sub reductions to make a total reduction of the current node
                if len(stack) < 2:
                    raise IllFormedError(
                        "reduce_global cannot be applied if there is a node that"
                        "does not have two children in the current instance")
                lv = stack.pop()
                rv = stack.pop()
                # We process and stack a reduction
                stack.append(psi_n(lv, g.get_value(), rv))
        top = stack.pop()
        return top
Example #9
0
 def __node_uacc_update_compute(stack, d, res, k, v1, v2, i):
     """Computes when the value is a node"""
     if len(stack) < 2:
         raise IllFormedError(
             "uacc_update cannot be applied if there is a node that does not have two children "
             "in the current instance")
     # We need two sub accumulation values to process the accumulation of a node
     lv = stack.pop()
     rv = stack.pop()
     if d in (0, 1):
         # We met a critical value before, so the accumulation is not completed yet
         val = k(lv, v1.get_value(), rv)
         res[i] = TaggedValue(val, v1.get_tag())
         stack.append(val)
         d = 0
     else:
         # We did not meet a critical value before, so the accumulation is completed yet
         res[i] = v2
         stack.append(v2.get_value())
         d = d - 1
     return res, stack, d
Example #10
0
 def __node_reduce_local_compute(stack, d, k, psi_l, phi, v, psi_r):
     """Computes when the value is a node"""
     if len(stack) < 2:
         raise IllFormedError(
             "reduce_local cannot be applied if there is a node that does not have "
             "two children in the current instance")
     # We get two sub-reductions to make a reduction with the current node value
     lv = stack.pop()
     rv = stack.pop()
     if d == 0:
         # The current node is an ancestor of a critical value by the left
         # That is, there is a critical value on its left children in a BTree representation
         # We process and stack a partial reduction
         stack.append(psi_l(lv, phi(v.get_value()), rv))
     elif d == 1:
         # The current node is an ancestor of a critical value by the right
         # That is, there is a critical value on its right children in a BTree representation
         # We process and stack a partial reduction
         stack.append(psi_r(lv, phi(v.get_value()), rv))
         d = 0
     else:
         # We did not meet a critical value, we process and stack a normal reduction
         stack.append(k(lv, v.get_value(), rv))
     return stack, d
Example #11
0
    def uacc_local(self, k, phi, psi_l, psi_r):
        """Computes local upwards accumulation and reduction

        Precondition
        -------------
        self should empty

        Parameters
        ----------
        k : callable
            The function used to reduce a BTree into a single value
        phi : callable
            A function used to respect the closure property
        psi_l : callable
            A function used to respect the closure property to make partial computation on the left
        psi_r : callable
            A function used to respect the closure property to make partial computation on the right

        Raises
        ------
        IllFormedError
            If the current instance does not represent a correct linearized subtree
            That is there is a node that doesn't have two children which can be either a leaf value or a critical value
        """
        assert self != [], "uacc_local cannot be applied to an empty Segment"
        stack = []
        d = MINUS_INFINITY
        res = Segment([None] * self.length())
        has_crit = False
        for i in reversed(range(self.length())):
            v = self[i]
            # We stack all the values of previous accumulation
            if v.is_leaf():
                res[i] = v
                stack.append(v.get_value())
                d = d + 1

            elif v.is_node():
                if len(stack) < 2:
                    raise IllFormedError(
                        "uacc_local cannot be applied if there is a node that does not have two children "
                        "in the current instance")
                # We get the values of two sub upward accumulation
                lv = stack.pop()
                rv = stack.pop()
                if d == 0:
                    # The current node is an ancestor of a critical value by the left
                    # That is, there is a critical value on its left children in a BTree representation
                    # We process and stack the value of a partial accumulation
                    val = phi(v.get_value())
                    stack.append(psi_l(lv, val, rv))
                    res[i] = None
                elif d == 1:
                    # The current node is an ancestor of a critical value by the left
                    # That is, there is a critical value on its left children in a BTree representation
                    # We process and stack the value of a partial accumulation
                    val = phi(v.get_value())
                    stack.append(psi_r(lv, val, rv))
                    res[i] = None
                    d = 0
                else:
                    # We did not meet a critical value, we can process a normal upward accumulation with k
                    val = k(lv, v.get_value(), rv)
                    res[i] = TaggedValue(val, v.get_tag())
                    stack.append(val)
                    d = d - 1

            else:  # v.is_critical()
                # The current value is critical. We make a partial accumulation with phi and stack the result
                stack.append(phi(v.get_value()))
                res[i] = None
                d = 0
                has_crit = True

        top = stack.pop()
        tag = "N" if has_crit else "L"
        # We return both the top values for following global upward accumulation, and the current accumulated subtree
        return TaggedValue(top, tag), res
Example #12
0
    def reduce_local(self, k, phi, psi_l, psi_r):
        """Reduces a local Segment into a value

        Precondition
        -------------
        self should not be empty

        Parameters
        ----------
        k : callable
            The function used to reduce a BTree into a single value
        phi : callable
            A function used to respect the closure property
        psi_l : callable
            A function used to respect the closure property to make partial computation on the left
        psi_r : callable
            A function used to respect the closure property to make partial computation on the right

        Raises
        ------
        IllFormedError
            If the current instance does not represent a correct linearized subtree
            That is there is a node that does not have two children which can be either a leaf value or a critical value
        """
        assert self != [], "reduce_local cannot be applied to an empty Segment"
        stack = []
        d = MINUS_INFINITY
        has_critical = False
        for v in reversed(self):
            # Starts by the end, that is the most deep leaves
            # We stack every elements we already reduced
            if v.is_leaf():
                # We cannot reduce a leaf value
                stack.append(v.get_value())
                d = d + 1
            elif v.is_node():
                if len(stack) < 2:
                    raise IllFormedError(
                        "reduce_local cannot be applied if there is a node that does not have"
                        "two children in the current instance")
                # We get two sub-reductions to make a reduction with the current node value
                lv = stack.pop()
                rv = stack.pop()
                if d == 0:
                    # The current node is an ancestor of a critical value by the left
                    # That is, there is a critical value on its left children in a BTree representation
                    # We process and stack a partial reduction
                    stack.append(psi_l(lv, phi(v.get_value()), rv))
                elif d == 1:
                    # The current node is an ancestor of a critical value by the right
                    # That is, there is a critical value on its right children in a BTree representation
                    # We process and stack a partial reduction
                    stack.append(psi_r(lv, phi(v.get_value()), rv))
                    d = 0
                else:
                    # We did not meet a critical value, we process and stack a normal reduction
                    stack.append(k(lv, v.get_value(), rv))
            else:  # v.is_critical()
                # we process and stack the reduction of critical value
                stack.append(phi(v.get_value()))
                has_critical = True
                d = 0
        top = stack.pop()
        if has_critical:
            # The current instance represented a node in the global structure of a linearized tree
            return TaggedValue(top, "N")
        else:
            # The current instance represented a leaf in the global structure of a linearized tree
            return TaggedValue(top, "L")