<commit_before>
from basic import Basic, S, C
from operations import AssocOp
from methods import RelMeths, ArithMeths
from cache import cacheit

from symbol import Symbol, Wild, Temporary
# from numbers import Number    /cyclic/
# from mul import Mul    /cyclic/
# from function import FunctionClass    /cyclic/

class Add(AssocOp, RelMeths, ArithMeths):

    precedence = Basic.Add_precedence

    is_Add = True

    @classmethod
    def flatten(cls, seq):
        """ 
        Takes the sequence "seq" of nested Adds and returns a flatten list.
        
        Returns: (commutative_part, noncommutative_part, lambda_args,
            order_symbols)

        Applies associativity, all terms are commutable with respect to
        addition.
        """
        terms = {}      # term -> coeff
                        # e.g. x**2 -> 5   for ... + 5*x**2 + ...

        coeff = S.Zero  # standalone term
                        # e.g. 3 + ...
        lambda_args = None
        order_factors = []
        while seq:
            o = seq.pop(0)
            #if o.is_Function:
            #    if o.nargs is not None:
            #        o, lambda_args = o.with_dummy_arguments(lambda_args)

            # O(x)
            if o.is_Order:
                for o1 in order_factors:
                    if o1.contains(o):
                        o = None
                        break
                if o is None:
                    continue
                order_factors = [o]+[o1 for o1 in order_factors if not o.contains(o1)]
                continue

            # 3
            if o.is_Number:
                coeff += o
                continue

            # Add([...])
            if o.is_Add:
                seq = list(o.args) + seq
                continue

            # Mul([...])
            if o.is_Mul:
                c = o.args[0]

                # 3*...
                if c.is_Number:
                    if c is S.One:
                        s = o
                    else:
                        s = Mul(*o.args[1:])
                else:
                    c = S.One
                    s = o

            # everything else
            else:
                c = S.One
                s = o


            # now we have:
            # o = c*s, where
            #
            # c is a Number
            # s is an expression with number factor extracted

            # let's collect terms with the same s, so e.g.
            # 2*x**2 + 3*x**2  ->  5*x**2
            if terms.has_key(s):
                terms[s] += c
            else:
                terms[s] = c


        # now let's construct new args:
        # [2*x**2, x**3, 7*x**4, pi, ...]
        newseq = []
        noncommutative = False
        for s,c in terms.items():
            # 0*s
            if c is S.Zero:
                continue
            # 1*s
            elif c is S.One:
                newseq.append(s)
            # c*s
            else:
                newseq.append(Mul(c,s))
            noncommutative = noncommutative or not s.is_commutative

        # deal with nan, oo, -oo, etc...
        if coeff is S.NaN:
            newseq = [coeff]
        elif (coeff is S.Infinity) or (coeff is S.NegativeInfinity):
            newseq = [coeff] + [f for f in newseq if not f.is_real]
        elif coeff is not S.Zero:
            newseq.insert(0, coeff)

        # process O(x)
        if order_factors:
            newseq2 = []
            for t in newseq:
                for o in order_factors:
                    if o.contains(t):
                        t = None
                        break
                if t is not None:
                    newseq2.append(t)
            newseq = newseq2 + order_factors

        # order args canonically
        newseq.sort(Basic.compare)

        # we are done
        if noncommutative:
            return [],newseq,lambda_args,None
        else:
            return newseq,[],lambda_args,None

    def tostr(self, level=0):
        coeff, rest = self.as_coeff_factors()

        # Now we need to sort the factors in Add, which are in "rest". Any
        # ordering is fine, but some ordering looks better and some looks bad.

        # This particular solution is slow, but it ensures a sane ordering. It
        # can of course be improved:
        rest = list(rest)
        rest.sort(Basic.compare)

        l = []
        precedence = self.precedence
        if coeff is not S.Zero:
            l.append(coeff.tostr(precedence))
        for factor in rest:
            f = factor.tostr()
            if f.startswith('-'):
                if l:
                    l.extend(['-',f[1:]])<commit_msg>Use faster sorting algorithm in Add.flatten.<commit_after>
from basic import Basic, S, C
from operations import AssocOp
from methods import RelMeths, ArithMeths
from cache import cacheit

from symbol import Symbol, Wild, Temporary
# from numbers import Number    /cyclic/
# from mul import Mul    /cyclic/
# from function import FunctionClass    /cyclic/

class Add(AssocOp, RelMeths, ArithMeths):

    precedence = Basic.Add_precedence

    is_Add = True

    @classmethod
    def flatten(cls, seq):
        """ 
        Takes the sequence "seq" of nested Adds and returns a flatten list.
        
        Returns: (commutative_part, noncommutative_part, lambda_args,
            order_symbols)

        Applies associativity, all terms are commutable with respect to
        addition.
        """
        terms = {}      # term -> coeff
                        # e.g. x**2 -> 5   for ... + 5*x**2 + ...

        coeff = S.Zero  # standalone term
                        # e.g. 3 + ...
        lambda_args = None
        order_factors = []
        while seq:
            o = seq.pop(0)
            #if o.is_Function:
            #    if o.nargs is not None:
            #        o, lambda_args = o.with_dummy_arguments(lambda_args)

            # O(x)
            if o.is_Order:
                for o1 in order_factors:
                    if o1.contains(o):
                        o = None
                        break
                if o is None:
                    continue
                order_factors = [o]+[o1 for o1 in order_factors if not o.contains(o1)]
                continue

            # 3
            if o.is_Number:
                coeff += o
                continue

            # Add([...])
            if o.is_Add:
                seq = list(o.args) + seq
                continue

            # Mul([...])
            if o.is_Mul:
                c = o.args[0]

                # 3*...
                if c.is_Number:
                    if c is S.One:
                        s = o
                    else:
                        s = Mul(*o.args[1:])
                else:
                    c = S.One
                    s = o

            # everything else
            else:
                c = S.One
                s = o


            # now we have:
            # o = c*s, where
            #
            # c is a Number
            # s is an expression with number factor extracted

            # let's collect terms with the same s, so e.g.
            # 2*x**2 + 3*x**2  ->  5*x**2
            if terms.has_key(s):
                terms[s] += c
            else:
                terms[s] = c


        # now let's construct new args:
        # [2*x**2, x**3, 7*x**4, pi, ...]
        newseq = []
        noncommutative = False
        for s,c in terms.items():
            # 0*s
            if c is S.Zero:
                continue
            # 1*s
            elif c is S.One:
                newseq.append(s)
            # c*s
            else:
                newseq.append(Mul(c,s))
            noncommutative = noncommutative or not s.is_commutative

        # deal with nan, oo, -oo, etc...
        if coeff is S.NaN:
            newseq = [coeff]
        elif (coeff is S.Infinity) or (coeff is S.NegativeInfinity):
            newseq = [coeff] + [f for f in newseq if not f.is_real]
        elif coeff is not S.Zero:
            newseq.insert(0, coeff)

        # process O(x)
        if order_factors:
            newseq2 = []
            for t in newseq:
                for o in order_factors:
                    if o.contains(t):
                        t = None
                        break
                if t is not None:
                    newseq2.append(t)
            newseq = newseq2 + order_factors

        # order args canonically
        # Currently we sort things using hashes, as it is quite fast. A better
        # solution is not to sort things at all - but this needs some more
        # fixing.
        newseq.sort(key=hash)

        # we are done
        if noncommutative:
            return [],newseq,lambda_args,None
        else:
            return newseq,[],lambda_args,None

    def tostr(self, level=0):
        coeff, rest = self.as_coeff_factors()

        # Now we need to sort the factors in Add, which are in "rest". Any
        # ordering is fine, but some ordering looks better and some looks bad.

        # This particular solution is slow, but it ensures a sane ordering. It
        # can of course be improved:
        rest = list(rest)
        rest.sort(Basic.compare)

        l = []
        precedence = self.precedence
        if coeff is not S.Zero:
            l.append(coeff.tostr(precedence))
        for factor in rest:
            f = factor.tostr()
            if f.startswith('-'):
                if l:
                    l.extend(['-',f[1:]])
{'fraction_non_alphanumeric': 0.08831578947368421, 'fraction_numerical': 0.007157894736842105, 'mean_word_length': 1.1250279579512414, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2801812', 'n_tokens_mistral': 2807, 'n_tokens_neox': 2607, 'n_words': 837}