コード例 #1
0
def flatten(expr, depth=-1, head=None):
    """
    flattens an Expression
      - a negative depth allows for infinite recursion
      - only flattens subexpressions with given head
    """
    assert isinstance(expr, Expression)
    if depth == 0:
        return expr

    if head is None:
        head = expr.head
    assert isinstance(head, BaseExpression)     # head could be Expression

    leaves = []
    for leaf in expr.leaves:
        if leaf.head.same(head):
            assert isinstance(leaf, Expression)
            for leaf2 in leaf.leaves:
                if isinstance(leaf2, Expression):
                    leaves.append(flatten(leaf2, head=head, depth=depth-1))
                else:
                    leaves.append(leaf2)
        else:
            if isinstance(leaf, Expression):
                leaves.append(flatten(leaf, head=head, depth=depth-1))
            else:
                leaves.append(leaf)
    expr = Expression(head)
    expr.leaves = leaves
    return expr
コード例 #2
0
ファイル: definitions.py プロジェクト: sn6uv/rmathics
 def set_context_path(self, context_path):
     """
     set $ContextPath given a list of str
     """
     assert isinstance(context_path, list)
     assert all([isinstance(c, str) for c in context_path])
     ownvalues = Expression(Symbol('System`List'))
     ownvalues.leaves = [String(c) for c in context_path]
     self.set_ownvalues('System`$ContextPath', ownvalues)
コード例 #3
0
ファイル: definitions.py プロジェクト: sn6uv/rmathics
 def set_ownvalues(self, name, ownvalues):
     assert isinstance(name, str) and isinstance(ownvalues, BaseExpression)
     name = self.lookup_name(name)
     defn = self.get_definition(name)
     defn.ownvalues = Expression(
         Symbol('System`List'),
         Expression(
             Symbol('System`RuleDelayed'),
             Expression(Symbol('System`HoldPattern'), Symbol(name)),
             ownvalues))
コード例 #4
0
ファイル: evaluation.py プロジェクト: sn6uv/rmathics
def evaluate(expr, definitions=Definitions()):
    messages = []
    result = expr
    if isinstance(expr, Expression):
            # Evaluate head
            head, head_messages = evaluate(expr.head, definitions)
            messages.extend(head_messages)

            # Evaluate leaves
            leaves = []
            for leaf in expr.leaves:
                leaf, leaf_messages = evaluate(leaf, definitions)
                messages.extend(leaf_messages)
                leaves.append(leaf)

            # Build the result
            result = Expression(head)
            result.leaves = leaves

            # Apply transformations for Orderless, Listable, Flat
            if isinstance(head, Symbol):
                head_attributes = definitions.get_attributes(head.get_name())
                if 'Listable' in head_attributes:
                    result, thread_messages = thread(result)
                    messages.extend(thread_messages)
                if 'Orderless' in head_attributes:
                    result = sort(result)
                if 'Flat' in head_attributes:
                    result = flatten(result)

    elif isinstance(expr, Atom):
        if isinstance(expr, Symbol):
            # Apply user definitions
            # TODO OwnValues
            # TODO UpValues
            # TODO DownValues

            # Apply builtin definitions
            # TODO
            pass
        result = expr

    if expr.same(result):
        result = _builtin_evaluate(expr, definitions)
        return (result, messages)
    else:
        result, result_messages = evaluate(result, definitions)
        messages.extend(result_messages)
        return (result, messages)
コード例 #5
0
def evaluate(expr, definitions=Definitions()):
    messages = []
    result = expr
    if isinstance(expr, Expression):
        # Evaluate head
        head, head_messages = evaluate(expr.head, definitions)
        messages.extend(head_messages)

        # Evaluate leaves
        leaves = []
        for leaf in expr.leaves:
            leaf, leaf_messages = evaluate(leaf, definitions)
            messages.extend(leaf_messages)
            leaves.append(leaf)

        # Build the result
        result = Expression(head)
        result.leaves = leaves

        # Apply transformations for Orderless, Listable, Flat
        if isinstance(head, Symbol):
            head_attributes = definitions.get_attributes(head.get_name())
            if 'Listable' in head_attributes:
                result, thread_messages = thread(result)
                messages.extend(thread_messages)
            if 'Orderless' in head_attributes:
                result = sort(result)
            if 'Flat' in head_attributes:
                result = flatten(result)

    elif isinstance(expr, Atom):
        if isinstance(expr, Symbol):
            # Apply user definitions
            # TODO OwnValues
            # TODO UpValues
            # TODO DownValues

            # Apply builtin definitions
            # TODO
            pass
        result = expr

    if expr.same(result):
        result = _builtin_evaluate(expr, definitions)
        return (result, messages)
    else:
        result, result_messages = evaluate(result, definitions)
        messages.extend(result_messages)
        return (result, messages)
コード例 #6
0
ファイル: definitions.py プロジェクト: sn6uv/rmathics
 def set_attributes(self, name, attributes):
     assert isinstance(name, str)
     assert isinstance(attributes, list)
     assert all([isinstance(attr, str) and attr in known_attributes
                 for attr in attributes])
     name = self.lookup_name(name)
     defn = self.get_definition(name)
     defn.attributes = Expression(Symbol('System`List'))
     defn.attributes.leaves = [Symbol('System`' + attribute)
                               for attribute in attributes]
コード例 #7
0
def thread(expr, head=Symbol('System`List')):
    """
    threads an Expression
      - given expr=f[args], thread over args whose head matches head
      - args whose heads don't match are repeated
    """
    assert isinstance(expr, Expression)
    assert isinstance(head, BaseExpression)

    messages = []
    args = expr.leaves
    exprhead = expr.head

    # indices of args with matching heads
    match_indices = [i for i, arg in enumerate(args) if arg.head.same(head)]

    if match_indices == []:     # nothing to thread over
        return expr, messages
    else:
        thread_len = len(args[match_indices[0]].leaves)

    # check all matching args have the same length
    for i in match_indices:
        if len(args[i].leaves) != thread_len:
            messages.append(('Thread', 'tdlen'))
            return expr, messages

    # args with heads that don't match are repeated thread_len times
    new_args = []
    for i, arg in enumerate(args):
        if i in match_indices:
            new_args.append(arg.leaves)
        else:
            new_args.append(thread_len * [arg])

    assert all([len(arg) == thread_len for arg in new_args])

    # thread over args
    leaves = []
    for i in range(thread_len):
        expr = Expression(exprhead)
        expr.leaves = [arg[i] for arg in new_args]
        leaves.append(expr)
    result = Expression(head)
    result.leaves = leaves
    return result, messages
コード例 #8
0
ファイル: definitions.py プロジェクト: sn6uv/rmathics
 def __init__(self,
              rules=Expression(Symbol('System`List')),
              ownvalues=Expression(Symbol('System`List')),
              downvalues=Expression(Symbol('System`List')),
              subvalues=Expression(Symbol('System`List')),
              upvalues=Expression(Symbol('System`List')),
              formatvalues=Expression(Symbol('System`List')),
              messages=Expression(Symbol('System`List')),
              attributes=Expression(Symbol('System`List')),
              options=Expression(Symbol('System`List')),
              nvalues=Expression(Symbol('System`List')),
              defaultvalues=Expression(Symbol('System`List'))):
     self.rules = rules
     self.ownvalues = ownvalues
     self.downvalues = downvalues
     self.subvalues = subvalues
     self.upvalues = upvalues
     self.formatvalues = formatvalues
     self.messages = messages
     self.attributes = attributes
     self.options = options
     self.nvalues = nvalues
     self.defaultvalues = defaultvalues
コード例 #9
0
ファイル: definitions.py プロジェクト: sn6uv/rmathics
            'downvalues: %s, formats: %s, attributes: %s>') % (
                self.downvalues, self.formatvalues, self.attributes)
        return s.encode('unicode_escape')

builtins = []
def builtin(patt):
    assert isinstance(patt, BaseExpression)
    def wrapper(func):
        builtins.append((patt, func))
        return func
    return wrapper


@builtin(Expression(Symbol('System`Plus'),
    Expression(Symbol('System`Pattern'), Symbol('x0'), Expression(Symbol('System`BlankNullSequence'), Symbol('System`Integer'))),
    Expression(Symbol('System`Pattern'), Symbol('x1'), Expression(Symbol('System`BlankNullSequence'), Symbol('System`Rational'))),
    Expression(Symbol('System`Pattern'), Symbol('x2'), Expression(Symbol('System`BlankNullSequence'), Symbol('System`Real'))),
))
def plus(mappings):
    ints = mappings['x0']
    rats = mappings['x1']
    reals = mappings['x2']

    assert ints.head.same(Symbol('System`Sequence'))
    assert rats.head.same(Symbol('System`Sequence'))
    assert reals.head.same(Symbol('System`Sequence'))

    ints = ints.leaves
    rats = rats.leaves
    reals = reals.leaves
コード例 #10
0
ファイル: pattern.py プロジェクト: sn6uv/rmathics
def _match_seq(exprs, patts, definitions):
    """
    matches a list of expressions against a list of patterns

    We match by pairing each pattern to a list of expressions
      - BlankSequence matches to one or more expression
      - BlankNullSequence matches to zero or more
      - everything else (including Blank[]) matches to exactly one expression

    Try to match the 'everything else' first. It's more efficient this way.

    returns (bool, {str: BaseExpression}) like the function match above.
    """
    if len(patts) == len(exprs) == 0:
        return True, {}

    patti, name = -1, None
    for i, patt in enumerate(patts):
        if patt.head.same(Symbol('System`Pattern')):
            if len(patt.leaves) != 2:
                # TODO message Pattern::argr:
                return False, {}
            name2, patt2 = patt.leaves
            if patt2.head.same(Symbol('System`BlankSequence')):
                continue
            if patt2.head.same(Symbol('System`BlankNullSequence')):
                continue
            else:
                name = name2.get_name()
                patti = i
                break
        if patt.head.same(Symbol('System`BlankSequence')):
            continue
        elif patt.head.same(Symbol('System`BlankNullSequence')):
            continue
        else:
            patti = i
            break
    if patti >= 0:       # everything else
        patt = patts[patti]
        if patt.head.same(Symbol('System`Pattern')):
            patt = patt.leaves[0]
        for expri, expr in enumerate(exprs):
            match0, mapping0 = match(expr, patt, definitions)
            if match0:
                match1, mapping1 = _match_seq(
                    exprs[:expri], patts[:patti], definitions)
                match2, mapping2 = _match_seq(
                    exprs[expri+1:], patts[patti+1:], definitions)
                try:
                    if match1 and match2:
                        mapping = _merge_dicts(mapping1, mapping2)
                        mapping = _merge_dicts(mapping, mapping0)
                        if name is not None:
                            mapping = _merge_dicts(mapping, {name: expr})
                        return True, mapping
                except ValueError:
                    pass
        return False, {}

    for i, patt in enumerate(patts):
        if patt.head.same(Symbol('System`Pattern')):
            assert len(patt.leaves) == 2
            name2, patt2 = patt.leaves
            if patt2.head.same(Symbol('System`BlankSequence')):
                name = name2.get_name()
                patti = i
                break
        if patt.head.same(Symbol('System`BlankSequence')):
            patti = i
            break
    if patti >= 0:
        patt = patts[patti]
        if patt.head.same(Symbol('System`Pattern')):
            patt = patt.leaves[1]
        for match_len in range(1, len(exprs)+1):
            # begin looking for length 1 matches
            for start_pos in range(len(exprs)+1-match_len):
                if len(patt.leaves) == 0:
                    pass
                elif len(patt.leaves) == 1:
                    if not all([expr.head.same(patt.leaves[0]) for expr in
                                exprs[start_pos:start_pos+match_len]]):
                        continue
                else:
                    raise ValueError
                match0, mapping0 = _match_seq(
                    exprs[:start_pos], patts[:patti], definitions)
                match1, mapping1 = _match_seq(
                    exprs[start_pos+match_len:], patts[patti+1:], definitions)
                expr = Expression(Symbol('System`Sequence'))
                expr.leaves = exprs[start_pos:start_pos+match_len]
                try:
                    mapping = _merge_dicts(mapping0, mapping1)
                    if match0 and match1:
                        if name is not None:
                            mapping = _merge_dicts(mapping, {name: expr})
                        return True, mapping
                except ValueError:
                    pass
        return False, {}

    if patts == []:
        assert exprs != []
        return False, {}
    patti = 0
    patt = patts[patti]
    if patt.head.same(Symbol('System`Pattern')):
            assert len(patt.leaves) == 2
            name2, patt2 = patt.leaves
            name = name2.get_name()
            assert patt2.head.same(Symbol('System`BlankNullSequence'))
            patt = patt2
    else:
        assert patt.head.same(Symbol('System`BlankNullSequence'))
    for match_len in range(0, len(exprs)+1):
        # begin looking for length 0 matches
        for start_pos in range(len(exprs)+1-match_len):
            if len(patt.leaves) == 0:
                pass
            elif len(patt.leaves) == 1:
                if not all([expr.head.same(patt.leaves[0]) for expr in
                            exprs[start_pos:start_pos+match_len]]):
                    continue
            else:
                raise ValueError
            match0, mapping0 = _match_seq(
                exprs[:start_pos], patts[:patti], definitions)
            match1, mapping1 = _match_seq(
                exprs[start_pos+match_len:], patts[patti+1:], definitions)
            expr = Expression(Symbol('System`Sequence'))
            expr.leaves = exprs[start_pos:start_pos+match_len]
            try:
                mapping = _merge_dicts(mapping0, mapping1)
                if match0 and match1:
                    if name is not None:
                        mapping = _merge_dicts(mapping, {name: expr})
                    return True, mapping
            except ValueError:
                pass
    return False, {}
コード例 #11
0
def _match_seq(exprs, patts, definitions):
    """
    matches a list of expressions against a list of patterns

    We match by pairing each pattern to a list of expressions
      - BlankSequence matches to one or more expression
      - BlankNullSequence matches to zero or more
      - everything else (including Blank[]) matches to exactly one expression

    Try to match the 'everything else' first. It's more efficient this way.

    returns (bool, {str: BaseExpression}) like the function match above.
    """
    if len(patts) == len(exprs) == 0:
        return True, {}

    patti, name = -1, None
    for i, patt in enumerate(patts):
        if patt.head.same(Symbol('System`Pattern')):
            if len(patt.leaves) != 2:
                # TODO message Pattern::argr:
                return False, {}
            name2, patt2 = patt.leaves
            if patt2.head.same(Symbol('System`BlankSequence')):
                continue
            if patt2.head.same(Symbol('System`BlankNullSequence')):
                continue
            else:
                name = name2.get_name()
                patti = i
                break
        if patt.head.same(Symbol('System`BlankSequence')):
            continue
        elif patt.head.same(Symbol('System`BlankNullSequence')):
            continue
        else:
            patti = i
            break
    if patti >= 0:  # everything else
        patt = patts[patti]
        if patt.head.same(Symbol('System`Pattern')):
            patt = patt.leaves[0]
        for expri, expr in enumerate(exprs):
            match0, mapping0 = match(expr, patt, definitions)
            if match0:
                match1, mapping1 = _match_seq(exprs[:expri], patts[:patti],
                                              definitions)
                match2, mapping2 = _match_seq(exprs[expri + 1:],
                                              patts[patti + 1:], definitions)
                try:
                    if match1 and match2:
                        mapping = _merge_dicts(mapping1, mapping2)
                        mapping = _merge_dicts(mapping, mapping0)
                        if name is not None:
                            mapping = _merge_dicts(mapping, {name: expr})
                        return True, mapping
                except ValueError:
                    pass
        return False, {}

    for i, patt in enumerate(patts):
        if patt.head.same(Symbol('System`Pattern')):
            assert len(patt.leaves) == 2
            name2, patt2 = patt.leaves
            if patt2.head.same(Symbol('System`BlankSequence')):
                name = name2.get_name()
                patti = i
                break
        if patt.head.same(Symbol('System`BlankSequence')):
            patti = i
            break
    if patti >= 0:
        patt = patts[patti]
        if patt.head.same(Symbol('System`Pattern')):
            patt = patt.leaves[1]
        for match_len in range(1, len(exprs) + 1):
            # begin looking for length 1 matches
            for start_pos in range(len(exprs) + 1 - match_len):
                if len(patt.leaves) == 0:
                    pass
                elif len(patt.leaves) == 1:
                    if not all([
                            expr.head.same(patt.leaves[0])
                            for expr in exprs[start_pos:start_pos + match_len]
                    ]):
                        continue
                else:
                    raise ValueError
                match0, mapping0 = _match_seq(exprs[:start_pos], patts[:patti],
                                              definitions)
                match1, mapping1 = _match_seq(exprs[start_pos + match_len:],
                                              patts[patti + 1:], definitions)
                expr = Expression(Symbol('System`Sequence'))
                expr.leaves = exprs[start_pos:start_pos + match_len]
                try:
                    mapping = _merge_dicts(mapping0, mapping1)
                    if match0 and match1:
                        if name is not None:
                            mapping = _merge_dicts(mapping, {name: expr})
                        return True, mapping
                except ValueError:
                    pass
        return False, {}

    if patts == []:
        assert exprs != []
        return False, {}
    patti = 0
    patt = patts[patti]
    if patt.head.same(Symbol('System`Pattern')):
        assert len(patt.leaves) == 2
        name2, patt2 = patt.leaves
        name = name2.get_name()
        assert patt2.head.same(Symbol('System`BlankNullSequence'))
        patt = patt2
    else:
        assert patt.head.same(Symbol('System`BlankNullSequence'))
    for match_len in range(0, len(exprs) + 1):
        # begin looking for length 0 matches
        for start_pos in range(len(exprs) + 1 - match_len):
            if len(patt.leaves) == 0:
                pass
            elif len(patt.leaves) == 1:
                if not all([
                        expr.head.same(patt.leaves[0])
                        for expr in exprs[start_pos:start_pos + match_len]
                ]):
                    continue
            else:
                raise ValueError
            match0, mapping0 = _match_seq(exprs[:start_pos], patts[:patti],
                                          definitions)
            match1, mapping1 = _match_seq(exprs[start_pos + match_len:],
                                          patts[patti + 1:], definitions)
            expr = Expression(Symbol('System`Sequence'))
            expr.leaves = exprs[start_pos:start_pos + match_len]
            try:
                mapping = _merge_dicts(mapping0, mapping1)
                if match0 and match1:
                    if name is not None:
                        mapping = _merge_dicts(mapping, {name: expr})
                    return True, mapping
            except ValueError:
                pass
    return False, {}