Esempio n. 1
0
    def match_leaf(self, yield_func, leaf, rest_leaves, rest_expression, vars,
                   expression, attributes, evaluation, leaf_index=1,
                   leaf_count=None, first=False, fully=True, depth=1,
                   wrap_oneid=True):

        if rest_expression is None:
            rest_expression = ([], [])

        evaluation.check_stopped()

        match_count = leaf.get_match_count(vars)
        leaf_candidates = leaf.get_match_candidates(
            rest_expression[1],  # leaf.candidates,
            expression, attributes, evaluation, vars)

        if len(leaf_candidates) < match_count[0]:
            return

        # STRANGE: candidate in leaf_candidates causes BusError for
        # Real ^ Integer (e.g. 2.0^3) when not converted to a set!
        leaf_candidates = set(leaf_candidates)

        candidates = rest_expression[1]

        # "Artificially" only use more leaves than specified for some kind
        # of pattern.
        # TODO: This could be further optimized!
        try_flattened = ('Flat' in attributes) and (leaf.get_head_name() in (
            'Pattern', 'PatternTest', 'Condition', 'Optional',
            'Blank', 'BlankSequence', 'BlankNullSequence', 'Alternatives',
            'OptionsPattern', 'Repeated', 'RepeatedNull'))

        if try_flattened:
            set_lengths = (match_count[0], None)
        else:
            set_lengths = match_count

        # try_flattened is used later to decide whether wrapping of leaves
        # into one operand may occur.
        # This can of course also be when flat and same head.
        try_flattened = try_flattened or ((
            'Flat' in attributes) and leaf.get_head() == expression.head)

        less_first = len(rest_leaves) > 0

        if 'Orderless' in attributes:
            sets = None
            if leaf.get_head_name() == 'Pattern':
                varname = leaf.leaves[0].get_name()
                existing = vars.get(varname, None)
                if existing is not None:
                    head = existing.get_head()
                    if (head.get_name() == 'Sequence' or (
                            'Flat' in attributes and
                            head == expression.get_head())):
                        needed = existing.leaves
                    else:
                        needed = [existing]
                    available = candidates[:]
                    for needed_leaf in needed:
                        if (needed_leaf in available and        # nopep8
                            needed_leaf in leaf_candidates):
                            available.remove(needed_leaf)
                        else:
                            return
                    sets = [(needed, ([], available))]

            if sets is None:
                sets = subsets(candidates, included=leaf_candidates,
                               less_first=less_first, *set_lengths)
        else:
            sets = subranges(candidates, flexible_start=first and not fully,
                             included=leaf_candidates, less_first=less_first,
                             *set_lengths)

        # print "Match %s in %s" % (leaf, expression)

        if rest_leaves:
            next_leaf = rest_leaves[0]
            next_rest_leaves = rest_leaves[1:]
        next_depth = depth + 1
        next_index = leaf_index + 1

        for items, items_rest in sets:
            # try:
            # print (u"  " + u", ".join(unicode(item)
            #        for item in items)).encode('utf-8')
            # except
            # Include wrappings like Plus[a, b] only if not all items taken
            # - in that case we would match the same expression over and over.

            include_flattened = (try_flattened and
                                 0 < len(items) < len(expression.leaves))

            # Don't try flattened when the expression would remain the same!

            def leaf_yield(next_vars, next_rest):
                # if next_rest is None:
                #    next_rest = ([], [])
                # yield_func(next_vars, (rest_expression[0] + items_rest[0],
                # next_rest[1]))
                if next_rest is None:
                    yield_func(
                        next_vars,
                        (rest_expression[0] + items_rest[0], []))
                else:
                    yield_func(
                        next_vars,
                        (rest_expression[0] + items_rest[0], next_rest[1]))

            def match_yield(new_vars, _):
                if rest_leaves:
                    self.match_leaf(
                        leaf_yield, next_leaf, next_rest_leaves, items_rest,
                        new_vars, expression, attributes, evaluation,
                        fully=fully, depth=next_depth, leaf_index=next_index,
                        leaf_count=leaf_count, wrap_oneid=wrap_oneid)
                else:
                    if not fully or (not items_rest[0] and not items_rest[1]):
                        yield_func(new_vars, items_rest)

            def yield_wrapping(item):
                leaf.match(match_yield, item, vars, evaluation, fully=True,
                           head=expression.head, leaf_index=leaf_index,
                           leaf_count=leaf_count, wrap_oneid=wrap_oneid)

            self.get_wrappings(
                yield_wrapping, items, match_count[1], expression, attributes,
                include_flattened=include_flattened)
Esempio n. 2
0
    def match_leaf(self,
                   yield_func,
                   leaf,
                   rest_leaves,
                   rest_expression,
                   vars,
                   expression,
                   attributes,
                   evaluation,
                   leaf_index=1,
                   leaf_count=None,
                   first=False,
                   fully=True,
                   depth=1,
                   wrap_oneid=True):

        if rest_expression is None:
            rest_expression = ([], [])

        evaluation.check_stopped()

        match_count = leaf.get_match_count(vars)
        leaf_candidates = leaf.get_match_candidates(
            rest_expression[1],  # leaf.candidates,
            expression,
            attributes,
            evaluation,
            vars)

        if len(leaf_candidates) < match_count[0]:
            return

        candidates = rest_expression[1]

        # "Artificially" only use more leaves than specified for some kind
        # of pattern.
        # TODO: This could be further optimized!
        try_flattened = (('System`Flat' in attributes)
                         and (leaf.get_head_name() in (system_symbols(
                             'Pattern', 'PatternTest', 'Condition', 'Optional',
                             'Blank', 'BlankSequence', 'BlankNullSequence',
                             'Alternatives', 'OptionsPattern', 'Repeated',
                             'RepeatedNull'))))

        if try_flattened:
            set_lengths = (match_count[0], None)
        else:
            set_lengths = match_count

        # try_flattened is used later to decide whether wrapping of leaves
        # into one operand may occur.
        # This can of course also be when flat and same head.
        try_flattened = try_flattened or (('System`Flat' in attributes) and
                                          leaf.get_head() == expression.head)

        less_first = len(rest_leaves) > 0

        if 'System`Orderless' in attributes:
            # we only want leaf_candidates to be a set if we're orderless.
            # otherwise, constructing a set() is very slow for large lists.
            # performance test case:
            # x = Range[100000]; Timing[Combinatorica`BinarySearch[x, 100]]
            leaf_candidates = set(leaf_candidates)  # for fast lookup

            sets = None
            if leaf.get_head_name() == 'System`Pattern':
                varname = leaf.leaves[0].get_name()
                existing = vars.get(varname, None)
                if existing is not None:
                    head = existing.get_head()
                    if (head.get_name() == 'System`Sequence'
                            or ('System`Flat' in attributes
                                and head == expression.get_head())):
                        needed = existing.leaves
                    else:
                        needed = [existing]
                    available = candidates[:]
                    for needed_leaf in needed:
                        if (needed_leaf in available and  # nopep8
                                needed_leaf in leaf_candidates):
                            available.remove(needed_leaf)
                        else:
                            return
                    sets = [(needed, ([], available))]

            if sets is None:
                sets = subsets(candidates,
                               included=leaf_candidates,
                               less_first=less_first,
                               *set_lengths)
        else:
            sets = subranges(candidates,
                             flexible_start=first and not fully,
                             included=leaf_candidates,
                             less_first=less_first,
                             *set_lengths)

        if rest_leaves:
            next_leaf = rest_leaves[0]
            next_rest_leaves = rest_leaves[1:]
        next_depth = depth + 1
        next_index = leaf_index + 1

        for items, items_rest in sets:
            # Include wrappings like Plus[a, b] only if not all items taken
            # - in that case we would match the same expression over and over.

            include_flattened = (try_flattened
                                 and 0 < len(items) < len(expression.leaves))

            # Don't try flattened when the expression would remain the same!

            def leaf_yield(next_vars, next_rest):
                # if next_rest is None:
                #    next_rest = ([], [])
                # yield_func(next_vars, (rest_expression[0] + items_rest[0],
                # next_rest[1]))
                if next_rest is None:
                    yield_func(next_vars,
                               (rest_expression[0] + items_rest[0], []))
                else:
                    yield_func(
                        next_vars,
                        (rest_expression[0] + items_rest[0], next_rest[1]))

            def match_yield(new_vars, _):
                if rest_leaves:
                    self.match_leaf(leaf_yield,
                                    next_leaf,
                                    next_rest_leaves,
                                    items_rest,
                                    new_vars,
                                    expression,
                                    attributes,
                                    evaluation,
                                    fully=fully,
                                    depth=next_depth,
                                    leaf_index=next_index,
                                    leaf_count=leaf_count,
                                    wrap_oneid=wrap_oneid)
                else:
                    if not fully or (not items_rest[0] and not items_rest[1]):
                        yield_func(new_vars, items_rest)

            def yield_wrapping(item):
                leaf.match(match_yield,
                           item,
                           vars,
                           evaluation,
                           fully=True,
                           head=expression.head,
                           leaf_index=leaf_index,
                           leaf_count=leaf_count,
                           wrap_oneid=wrap_oneid)

            self.get_wrappings(yield_wrapping,
                               items,
                               match_count[1],
                               expression,
                               attributes,
                               include_flattened=include_flattened)
Esempio n. 3
0
    def match_leaf(self,
                   yield_func,
                   leaf,
                   rest_leaves,
                   rest_expression,
                   vars,
                   expression,
                   attributes,
                   evaluation,
                   leaf_index=1,
                   leaf_count=None,
                   first=False,
                   fully=True,
                   depth=1,
                   wrap_oneid=True):

        if rest_expression is None:
            rest_expression = ([], [])

        evaluation.check_stopped()

        match_count = leaf.get_match_count(vars)
        leaf_candidates = leaf.get_match_candidates(
            rest_expression[1],  # leaf.candidates,
            expression,
            attributes,
            evaluation,
            vars)

        if len(leaf_candidates) < match_count[0]:
            return

        # STRANGE: candidate in leaf_candidates causes BusError for
        # Real ^ Integer (e.g. 2.0^3) when not converted to a set!
        leaf_candidates = set(leaf_candidates)

        candidates = rest_expression[1]

        # "Artificially" only use more leaves than specified for some kind
        # of pattern.
        # TODO: This could be further optimized!
        try_flattened = ('Flat' in attributes) and (leaf.get_head_name() in (
            'Pattern', 'PatternTest', 'Condition', 'Optional', 'Blank',
            'BlankSequence', 'BlankNullSequence', 'Alternatives',
            'OptionsPattern', 'Repeated', 'RepeatedNull'))

        if try_flattened:
            set_lengths = (match_count[0], None)
        else:
            set_lengths = match_count

        # try_flattened is used later to decide whether wrapping of leaves
        # into one operand may occur.
        # This can of course also be when flat and same head.
        try_flattened = try_flattened or (
            ('Flat' in attributes) and leaf.get_head() == expression.head)

        less_first = len(rest_leaves) > 0

        if 'Orderless' in attributes:
            sets = None
            if leaf.get_head_name() == 'Pattern':
                varname = leaf.leaves[0].get_name()
                existing = vars.get(varname, None)
                if existing is not None:
                    head = existing.get_head()
                    if (head.get_name() == 'Sequence'
                            or ('Flat' in attributes
                                and head == expression.get_head())):
                        needed = existing.leaves
                    else:
                        needed = [existing]
                    available = candidates[:]
                    for needed_leaf in needed:
                        if (needed_leaf in available and  # nopep8
                                needed_leaf in leaf_candidates):
                            available.remove(needed_leaf)
                        else:
                            return
                    sets = [(needed, ([], available))]

            if sets is None:
                sets = subsets(candidates,
                               included=leaf_candidates,
                               less_first=less_first,
                               *set_lengths)
        else:
            sets = subranges(candidates,
                             flexible_start=first and not fully,
                             included=leaf_candidates,
                             less_first=less_first,
                             *set_lengths)

        # print "Match %s in %s" % (leaf, expression)

        if rest_leaves:
            next_leaf = rest_leaves[0]
            next_rest_leaves = rest_leaves[1:]
        next_depth = depth + 1
        next_index = leaf_index + 1

        for items, items_rest in sets:
            # try:
            # print (u"  " + u", ".join(unicode(item)
            #        for item in items)).encode('utf-8')
            # except
            # Include wrappings like Plus[a, b] only if not all items taken
            # - in that case we would match the same expression over and over.

            include_flattened = (try_flattened
                                 and 0 < len(items) < len(expression.leaves))

            # Don't try flattened when the expression would remain the same!

            def leaf_yield(next_vars, next_rest):
                # if next_rest is None:
                #    next_rest = ([], [])
                # yield_func(next_vars, (rest_expression[0] + items_rest[0],
                # next_rest[1]))
                if next_rest is None:
                    yield_func(next_vars,
                               (rest_expression[0] + items_rest[0], []))
                else:
                    yield_func(
                        next_vars,
                        (rest_expression[0] + items_rest[0], next_rest[1]))

            def match_yield(new_vars, _):
                if rest_leaves:
                    self.match_leaf(leaf_yield,
                                    next_leaf,
                                    next_rest_leaves,
                                    items_rest,
                                    new_vars,
                                    expression,
                                    attributes,
                                    evaluation,
                                    fully=fully,
                                    depth=next_depth,
                                    leaf_index=next_index,
                                    leaf_count=leaf_count,
                                    wrap_oneid=wrap_oneid)
                else:
                    if not fully or (not items_rest[0] and not items_rest[1]):
                        yield_func(new_vars, items_rest)

            def yield_wrapping(item):
                leaf.match(match_yield,
                           item,
                           vars,
                           evaluation,
                           fully=True,
                           head=expression.head,
                           leaf_index=leaf_index,
                           leaf_count=leaf_count,
                           wrap_oneid=wrap_oneid)

            self.get_wrappings(yield_wrapping,
                               items,
                               match_count[1],
                               expression,
                               attributes,
                               include_flattened=include_flattened)
Esempio n. 4
0
    def match_leaf(self, yield_func, leaf, rest_leaves, rest_expression, vars,
                   expression, attributes, evaluation, leaf_index=1,
                   leaf_count=None, first=False, fully=True, depth=1,
                   wrap_oneid=True):

        if rest_expression is None:
            rest_expression = ([], [])

        evaluation.check_stopped()

        match_count = leaf.get_match_count(vars)
        leaf_candidates = leaf.get_match_candidates(
            rest_expression[1],  # leaf.candidates,
            expression, attributes, evaluation, vars)

        if len(leaf_candidates) < match_count[0]:
            return

        candidates = rest_expression[1]

        # "Artificially" only use more leaves than specified for some kind
        # of pattern.
        # TODO: This could be further optimized!
        try_flattened = (('System`Flat' in attributes) and (leaf.get_head_name() in (
            system_symbols(
                'Pattern', 'PatternTest', 'Condition', 'Optional', 'Blank',
                'BlankSequence', 'BlankNullSequence', 'Alternatives',
                'OptionsPattern', 'Repeated', 'RepeatedNull'))))

        if try_flattened:
            set_lengths = (match_count[0], None)
        else:
            set_lengths = match_count

        # try_flattened is used later to decide whether wrapping of leaves
        # into one operand may occur.
        # This can of course also be when flat and same head.
        try_flattened = try_flattened or ((
            'System`Flat' in attributes) and leaf.get_head() == expression.head)

        less_first = len(rest_leaves) > 0

        if 'System`Orderless' in attributes:
            # we only want leaf_candidates to be a set if we're orderless.
            # otherwise, constructing a set() is very slow for large lists.
            # performance test case:
            # x = Range[100000]; Timing[Combinatorica`BinarySearch[x, 100]]
            leaf_candidates = set(leaf_candidates)  # for fast lookup

            sets = None
            if leaf.get_head_name() == 'System`Pattern':
                varname = leaf.leaves[0].get_name()
                existing = vars.get(varname, None)
                if existing is not None:
                    head = existing.get_head()
                    if (head.get_name() == 'System`Sequence' or (
                            'System`Flat' in attributes and
                            head == expression.get_head())):
                        needed = existing.leaves
                    else:
                        needed = [existing]
                    available = candidates[:]
                    for needed_leaf in needed:
                        if (needed_leaf in available and        # nopep8
                            needed_leaf in leaf_candidates):
                            available.remove(needed_leaf)
                        else:
                            return
                    sets = [(needed, ([], available))]

            if sets is None:
                sets = subsets(candidates, included=leaf_candidates,
                               less_first=less_first, *set_lengths)
        else:
            sets = subranges(candidates, flexible_start=first and not fully,
                             included=leaf_candidates, less_first=less_first,
                             *set_lengths)

        if rest_leaves:
            next_leaf = rest_leaves[0]
            next_rest_leaves = rest_leaves[1:]
        next_depth = depth + 1
        next_index = leaf_index + 1

        for items, items_rest in sets:
            # Include wrappings like Plus[a, b] only if not all items taken
            # - in that case we would match the same expression over and over.

            include_flattened = (try_flattened and
                                 0 < len(items) < len(expression.leaves))

            # Don't try flattened when the expression would remain the same!

            def leaf_yield(next_vars, next_rest):
                # if next_rest is None:
                #    next_rest = ([], [])
                # yield_func(next_vars, (rest_expression[0] + items_rest[0],
                # next_rest[1]))
                if next_rest is None:
                    yield_func(
                        next_vars,
                        (rest_expression[0] + items_rest[0], []))
                else:
                    yield_func(
                        next_vars,
                        (rest_expression[0] + items_rest[0], next_rest[1]))

            def match_yield(new_vars, _):
                if rest_leaves:
                    self.match_leaf(
                        leaf_yield, next_leaf, next_rest_leaves, items_rest,
                        new_vars, expression, attributes, evaluation,
                        fully=fully, depth=next_depth, leaf_index=next_index,
                        leaf_count=leaf_count, wrap_oneid=wrap_oneid)
                else:
                    if not fully or (not items_rest[0] and not items_rest[1]):
                        yield_func(new_vars, items_rest)

            def yield_wrapping(item):
                leaf.match(match_yield, item, vars, evaluation, fully=True,
                           head=expression.head, leaf_index=leaf_index,
                           leaf_count=leaf_count, wrap_oneid=wrap_oneid)

            self.get_wrappings(
                yield_wrapping, items, match_count[1], expression, attributes,
                include_flattened=include_flattened)