Exemplo n.º 1
0
    def _print_Function(self, e):
        """Print a Function object.

        :param e: The expression.
        :rtype : bce.dom.mathml.all.Base
        :return: The printed MathML object.
        """

        assert isinstance(e, _sympy.Function)

        #  Check the function.
        fn_object = _mexp_function.find_sympy_function(e.func.__name__)
        if fn_object is None:
            raise RuntimeError("Unsupported function: \"%s\"." %
                               e.func.__name__)
        if fn_object.get_argument_count() != len(e.args):
            raise RuntimeError("Argument count mismatch.")

        #  Build the node.
        node = _mathml.RowComponent()
        node.append_object(_mathml.TextComponent(
            fn_object.get_function_name()))
        node.append_object(
            _mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
        for arg_id in range(0, len(e.args)):
            arg_value = e.args[arg_id]
            node.append_object(self.doprint(arg_value))
            if arg_id + 1 != len(e.args):
                node.append_object(
                    _mathml.OperatorComponent(_mathml.OPERATOR_SEPARATOR))
        node.append_object(
            _mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))

        return node
Exemplo n.º 2
0
def _print_super_electronic(
        charge,
        mexp_parser,
        mexp_protected_header_enabled=False,
        mexp_protected_header_prefix="X"
):
    """Print electronic charge value.

    :type mexp_parser: bce.parser.interface.mexp_parser.MathExpressionParserInterface
    :type mexp_protected_header_enabled: bool
    :type mexp_protected_header_prefix: str
    :param charge: The charge number.
    :param mexp_parser: The math expression parser.
    :param mexp_protected_header_enabled: Whether the MEXP protected headers are enabled.
    :param mexp_protected_header_prefix: The prefix of the MEXP protected headers.
    :rtype : bce.dom.mathml.all.Base
    :return: The printed MathML node.
    """

    #  Print the positivity part.
    if charge.is_negative:
        charge = -charge
        positivity = _mathml.OperatorComponent(_mathml.OPERATOR_MINUS)
    else:
        positivity = _mathml.OperatorComponent(_mathml.OPERATOR_PLUS)

    #  Simplify.
    charge = charge.simplify()

    if charge == _math_constant.ONE:
        return positivity
    else:
        #  Initialize a row component to contain the printing result.
        r = _mathml.RowComponent()

        #  Print the charge part.
        r.append_object(_print_operand(
            charge,
            True,
            mexp_parser,
            mexp_protected_header_enabled=mexp_protected_header_enabled,
            mexp_protected_header_prefix=mexp_protected_header_prefix
        ))

        #  Add the positivity flag.
        r.append_object(positivity)

        return r
Exemplo n.º 3
0
def _print_operand(
        value,
        need_wrapping,
        mexp_parser,
        mexp_protected_header_enabled=False,
        mexp_protected_header_prefix="X"
):
    """Print an operand.

    :type need_wrapping: bool
    :type mexp_parser: bce.parser.interface.mexp_parser.MathExpressionParserInterface
    :type mexp_protected_header_enabled: bool
    :type mexp_protected_header_prefix: str
    :param value: The operand value.
    :param need_wrapping: Set to True if you need to wrap the expression when it is neither an integer nor a symbol.
    :param mexp_parser: The math expression parser.
    :param mexp_protected_header_enabled: Whether the MEXP protected headers are enabled.
    :param mexp_protected_header_prefix: The prefix of the MEXP protected headers.
    :rtype : bce.dom.mathml.all.Base
    :return: The printed MathML node.
    """

    #  Simplify.
    value = value.simplify()

    if value.is_Integer:
        return _mathml.NumberComponent(str(value))
    else:
        if need_wrapping and not (value.is_Integer or value.is_Symbol):
            #  Use a pair of parentheses to wrap the printed expression.
            r = _mathml.RowComponent()
            r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
            r.append_object(mexp_parser.print_out(
                value,
                printer_type=_interface_printer.PRINTER_TYPE_MATHML,
                protected_header_enabled=mexp_protected_header_enabled,
                protected_header_prefix=mexp_protected_header_prefix
            ))
            r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))
            return r
        else:
            return mexp_parser.print_out(
                value,
                printer_type=_interface_printer.PRINTER_TYPE_MATHML,
                protected_header_enabled=mexp_protected_header_enabled,
                protected_header_prefix=mexp_protected_header_prefix
            )
Exemplo n.º 4
0
def print_ast(
        root_node,
        mexp_parser,
        mexp_protected_header_enabled=False,
        mexp_protected_header_prefix="X"
):
    """Print an AST to BCE expression.

    :type root_node: bce.parser.ast.molecule.ASTNodeHydrateGroup | bce.parser.ast.molecule.ASTNodeMolecule
    :type mexp_parser: bce.parser.interface.mexp_parser.MathExpressionParserInterface
    :type mexp_protected_header_enabled: bool
    :type mexp_protected_header_prefix: str
    :param root_node: The root node of the AST.
    :param mexp_parser: The math expression parser.
    :param mexp_protected_header_enabled: Whether the MEXP protected headers are enabled.
    :param mexp_protected_header_prefix: The prefix of the MEXP protected headers.
    :rtype : bce.dom.mathml.all.Base
    :return: The printed expression.
    """

    #  Get the printing order.
    work_order = _ml_ast_bfs.do_bfs(root_node, True)

    #  Initialize the printed result container.
    printed = {}

    for work_node in work_order:
        if work_node.is_hydrate_group():
            assert isinstance(work_node, _ml_ast_base.ASTNodeHydrateGroup)

            #  Initialize a row component to contain the printing result.
            build = _mathml.RowComponent()

            #  Print the prefix number part.
            pfx = work_node.get_prefix_number().simplify()
            if pfx != _math_constant.ONE:
                build.append_object(_print_operand(
                    pfx,
                    True,
                    mexp_parser,
                    mexp_protected_header_enabled=mexp_protected_header_enabled,
                    mexp_protected_header_prefix=mexp_protected_header_prefix
                ))
                build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
                surround = True
            else:
                surround = False

            #  Print children nodes.
            build.append_object(printed[id(work_node[0])])
            for child_id in range(1, len(work_node)):
                build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_DOT))
                build.append_object(printed[id(work_node[child_id])])

            #  Complete the surrounding parentheses if the flag was marked.
            if surround:
                build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))

            #  Save printing result.
            printed[id(work_node)] = build
        elif work_node.is_molecule():
            assert isinstance(work_node, _ml_ast_base.ASTNodeMolecule)

            #  Initialize a row component to contain the printing result.
            build = _mathml.RowComponent()

            #  Print the prefix number part.
            pfx = work_node.get_prefix_number().simplify()
            if pfx != _math_constant.ONE:
                build.append_object(_print_operand(
                    pfx,
                    True,
                    mexp_parser,
                    mexp_protected_header_enabled=mexp_protected_header_enabled,
                    mexp_protected_header_prefix=mexp_protected_header_prefix
                ))

            #  Print children nodes.
            for child_id in range(0, len(work_node)):
                build.append_object(printed[id(work_node[child_id])])

            el_charge = work_node.get_electronic_count().simplify()
            if not el_charge.is_zero:
                if len(work_node) == 0:
                    build.append_object(_mathml.SuperComponent(
                        _mathml.TextComponent("e"),
                        _print_super_electronic(
                            el_charge,
                            mexp_parser,
                            mexp_protected_header_enabled=mexp_protected_header_enabled,
                            mexp_protected_header_prefix=mexp_protected_header_prefix
                        )
                    ))
                else:
                    #  Find the innermost row component.
                    innermost = build
                    while innermost[-1].is_row():
                        innermost = innermost[-1]

                    #  Fetch the last item.
                    last_item = innermost[-1]

                    #  Add the electronic.
                    if last_item.is_sub():
                        assert isinstance(last_item, _mathml.SubComponent)
                        last_item = _mathml.SubAndSuperComponent(
                            last_item.get_main_object(),
                            last_item.get_sub_object(),
                            _print_super_electronic(
                                el_charge,
                                mexp_parser,
                                mexp_protected_header_enabled=mexp_protected_header_enabled,
                                mexp_protected_header_prefix=mexp_protected_header_prefix
                            )
                        )
                    else:
                        last_item = _mathml.SuperComponent(
                            last_item,
                            _print_super_electronic(
                                el_charge,
                                mexp_parser,
                                mexp_protected_header_enabled=mexp_protected_header_enabled,
                                mexp_protected_header_prefix=mexp_protected_header_prefix
                            )
                        )

                    #  Save the modified item.
                    innermost[-1] = last_item

            #  Save printing result.
            printed[id(work_node)] = build
        elif work_node.is_atom():
            assert isinstance(work_node, _ml_ast_base.ASTNodeAtom)

            #  Print and save the result.
            printed[id(work_node)] = _print_suffix(
                _mathml.TextComponent(work_node.get_atom_symbol()),
                work_node,
                mexp_parser,
                mexp_protected_header_enabled=mexp_protected_header_enabled,
                mexp_protected_header_prefix=mexp_protected_header_prefix
            )
        elif work_node.is_parenthesis():
            assert isinstance(work_node, _ml_ast_base.ASTNodeParenthesisWrapper)

            #  Initialize a row component to contain the printing result.
            build = _mathml.RowComponent()

            #  Print.
            build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
            build.append_object(printed[id(work_node.get_inner_node())])
            build.append_object(_print_suffix(
                _mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS),
                work_node,
                mexp_parser,
                mexp_protected_header_enabled=mexp_protected_header_enabled,
                mexp_protected_header_prefix=mexp_protected_header_prefix
            ))

            #  Save printing result.
            printed[id(work_node)] = build
        elif work_node.is_abbreviation():
            assert isinstance(work_node, _ml_ast_base.ASTNodeAbbreviation)

            #  Print and save the result.
            printed[id(work_node)] = _print_suffix(
                _mathml.TextComponent("[%s]" % work_node.get_abbreviation_symbol()),
                work_node,
                mexp_parser,
                mexp_protected_header_enabled=mexp_protected_header_enabled,
                mexp_protected_header_prefix=mexp_protected_header_prefix
            )
        else:
            raise RuntimeError("BUG: Unhandled AST node type.")

    #  Post process - add status.
    post_process = printed[id(root_node)]
    if root_node.get_status() is not None:
        if not post_process.is_row():
            tmp = _mathml.RowComponent()
            tmp.append_object(post_process)
            post_process = tmp
        post_process.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
        if root_node.get_status() == _ml_ast_base.STATUS_GAS:
            post_process.append_object(_mathml.TextComponent("g"))
        elif root_node.get_status() == _ml_ast_base.STATUS_LIQUID:
            post_process.append_object(_mathml.TextComponent("l"))
        elif root_node.get_status() == _ml_ast_base.STATUS_SOLID:
            post_process.append_object(_mathml.TextComponent("s"))
        elif root_node.get_status() == _ml_ast_base.STATUS_AQUEOUS:
            post_process.append_object(_mathml.TextComponent("aq"))
        else:
            raise RuntimeError("BUG: No such status.")
        post_process.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))

    return printed[id(root_node)]
Exemplo n.º 5
0
def print_cexp(cexp_object,
               molecule_parser,
               mexp_parser,
               mexp_protected_header_enabled=False,
               mexp_protected_header_prefix="X"):
    """Print the chemical equation.

    :type cexp_object: bce.parser.interface.cexp_parser.ChemicalEquation
    :type molecule_parser: bce.parser.interface.molecule_parser.MoleculeParserInterface
    :type mexp_parser: bce.parser.interface.mexp_parser.MathExpressionParserInterface
    :type mexp_protected_header_enabled: bool
    :type mexp_protected_header_prefix: str
    :param cexp_object: The chemical equation object.
    :param molecule_parser: The molecule parser.
    :param mexp_parser: The math expression parser.
    :param mexp_protected_header_enabled: Whether the MEXP protected headers are enabled.
    :param mexp_protected_header_prefix: The prefix of the MEXP protected headers.
    :rtype : bce.dom.mathml.all.Base
    :return: The printed MathML.
    """

    assert cexp_object.get_left_item_count(
    ) != 0 and cexp_object.get_right_item_count() != 0

    #  Initialize an empty CE expression.
    r = _mathml.RowComponent()

    #  Process items on left side.
    for idx in range(0, cexp_object.get_left_item_count()):
        #  Get the item.
        item = cexp_object.get_left_item(idx)

        #  Insert operator.
        if item.is_operator_plus():
            if len(r) != 0:
                r.append_object(
                    _mathml.OperatorComponent(_mathml.OPERATOR_PLUS))

        if item.is_operator_minus():
            r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_MINUS))

        #  Get the AST root node.
        ast_root = item.get_molecule_ast()

        #  Backup the prefix number.
        origin_coefficient = ast_root.get_prefix_number()

        #  Set the prefix to the balanced coefficient.
        ast_root.set_prefix_number(item.get_coefficient() * origin_coefficient)

        #  Print the molecule.
        r.append_object(
            molecule_parser.print_out(
                ast_root,
                mexp_parser,
                mexp_protected_header_enabled=mexp_protected_header_enabled,
                mexp_protected_header_prefix=mexp_protected_header_prefix,
                printer_type=_interface_printer.PRINTER_TYPE_MATHML))

        #  Restore the prefix number.
        ast_root.set_prefix_number(origin_coefficient)

    #  Insert '='.
    r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_EQUAL))

    #  Mark whether processing molecule is the first molecule on right side.
    r_is_first = True

    #  Process items on right side.
    for idx in range(0, cexp_object.get_right_item_count()):
        #  Get the item.
        item = cexp_object.get_right_item(idx)

        #  Insert operator.
        if item.is_operator_plus():
            if not r_is_first:
                r.append_object(
                    _mathml.OperatorComponent(_mathml.OPERATOR_PLUS))

        if item.is_operator_minus():
            r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_MINUS))

        #  Get the AST root node.
        ast_root = item.get_molecule_ast()

        #  Backup the prefix number.
        origin_coefficient = ast_root.get_prefix_number()

        #  Set the prefix to the balanced coefficient.
        ast_root.set_prefix_number(item.get_coefficient() * origin_coefficient)

        #  Print the molecule.
        r.append_object(
            molecule_parser.print_out(
                ast_root,
                mexp_parser,
                mexp_protected_header_enabled=mexp_protected_header_enabled,
                mexp_protected_header_prefix=mexp_protected_header_prefix,
                printer_type=_interface_printer.PRINTER_TYPE_MATHML))

        #  Restore the prefix number.
        ast_root.set_prefix_number(origin_coefficient)

        #  Switch off the mark.
        r_is_first = False

    return r
Exemplo n.º 6
0
    def _print_Mul(self, expr):
        """Print a Mul object.

        :param expr: The expression.
        :rtype : bce.dom.mathml.all.Base
        :return: The printed MathML object.
        """

        assert isinstance(expr, _sympy.Mul)

        # noinspection PyProtectedMember
        if _coeff_isneg(expr):
            x = _mathml.RowComponent()
            x.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_MINUS))
            x.append_object(self._print(-expr))
            return x

        PREC = _sympy_precedence.precedence(expr)

        from sympy.simplify import fraction
        numer, denom = fraction(expr)

        if denom is not _sympy.S.One:
            return _mathml.FractionComponent(self._print(numer),
                                             self._print(denom))

        coeff, terms = expr.as_coeff_mul()
        if coeff is _sympy.S.One and len(terms) == 1:
            #  Since the negative coefficient has been handled, I don't
            #  thing a coeff of 1 can remain
            if _sympy_precedence.precedence(terms[0]) < PREC:
                #  Return the argument with parentheses around.
                tmp_node = _mathml.RowComponent()
                tmp_node.append_object(
                    _mathml.OperatorComponent(
                        _mathml.OPERATOR_LEFT_PARENTHESIS))
                tmp_node.append_object(self._print(terms[0]))
                tmp_node.append_object(
                    _mathml.OperatorComponent(
                        _mathml.OPERATOR_RIGHT_PARENTHESIS))

                return tmp_node
            else:
                #  Return the argument only.
                return self._print(terms[0])

        if self.order != "old":
            # noinspection PyProtectedMember
            terms = _sympy.Mul._from_args(terms).as_ordered_factors()

        #  Build result row element(node).
        x = _mathml.RowComponent()

        if coeff != 1:
            if _sympy_precedence.precedence(coeff) < PREC:
                #  Insert the coefficient number with parentheses around.
                x.append_object(
                    _mathml.OperatorComponent(
                        _mathml.OPERATOR_LEFT_PARENTHESIS))
                x.append_object(self._print(coeff))
                x.append_object(
                    _mathml.OperatorComponent(
                        _mathml.OPERATOR_RIGHT_PARENTHESIS))
            else:
                #  Insert the coefficient number only.
                x.append_object(self._print(coeff))

            #  Insert a multiply operator.
            if not terms[0].is_Symbol:
                x.append_object(
                    _mathml.OperatorComponent(_mathml.OPERATOR_MULTIPLY))

        terms_len = len(terms)
        for term_id in range(0, terms_len):
            cur_term = terms[term_id]
            if _sympy_precedence.precedence(cur_term) < PREC:
                x.append_object(
                    _mathml.OperatorComponent(
                        _mathml.OPERATOR_LEFT_PARENTHESIS))
                x.append_object(self._print(cur_term))
                x.append_object(
                    _mathml.OperatorComponent(
                        _mathml.OPERATOR_RIGHT_PARENTHESIS))
            else:
                x.append_object(self._print(cur_term))
            if term_id + 1 != terms_len and not cur_term.is_Symbol:
                x.append_object(
                    _mathml.OperatorComponent(_mathml.OPERATOR_MULTIPLY))

        return x
Exemplo n.º 7
0
    def _print_Pow(self, e):
        """Print a Pow object.

        :param e: The expression.
        :rtype : bce.dom.mathml.all.Base
        :return: The printed MathML object.
        """

        assert isinstance(e, _sympy.Pow)
        PREC = _sympy_precedence.precedence(e)

        if e.exp.is_Rational and e.exp.p == 1:
            #  If the exponent is like {1/x}, do SQRT operation if x is 2, otherwise, do
            #  root operation.
            printed_base = self._print(e.base)

            if e.exp.q != 2:
                #  Do root operation.
                root = _mathml.RootComponent(
                    printed_base, _mathml.NumberComponent(str(e.exp.q)))
            else:
                #  Do SQRT operation.
                root = _mathml.SquareRootComponent(printed_base)

            return root

        if e.exp.is_negative:
            if e.exp.is_Integer and e.exp == _sympy.Integer(-1):
                final_node = _mathml.FractionComponent(
                    _mathml.NumberComponent("1"), self._print(e.base))
            else:
                #  frac{1, base ^ |exp|}
                neg_exp = -e.exp

                #  Get node for the base.
                if _sympy_precedence.precedence(e.base) < PREC:
                    base_node = _mathml.RowComponent()
                    base_node.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_LEFT_PARENTHESIS))
                    base_node.append_object(self._print(e.base))
                    base_node.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_RIGHT_PARENTHESIS))
                else:
                    base_node = self._print(e.base)

                #  Get node for the exponent.
                if _sympy_precedence.precedence(neg_exp) < PREC:
                    exp_node = _mathml.RowComponent()
                    exp_node.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_LEFT_PARENTHESIS))
                    exp_node.append_object(self._print(neg_exp))
                    exp_node.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_RIGHT_PARENTHESIS))
                else:
                    exp_node = neg_exp

                final_node = _mathml.FractionComponent(
                    _mathml.NumberComponent("1"),
                    _mathml.SuperComponent(base_node, exp_node))

            return final_node

        #  Get node for the base.
        if _sympy_precedence.precedence(e.base) < PREC:
            base_node = _mathml.RowComponent()
            base_node.append_object(
                _mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
            base_node.append_object(self._print(e.base))
            base_node.append_object(
                _mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))
        else:
            base_node = self._print(e.base)

        return _mathml.SuperComponent(base_node, self._print(e.exp))
Exemplo n.º 8
0
    def _print_Add(self, expr, order=None):
        """Print a Add object.

        :param expr: The expression.
        :rtype : bce.dom.mathml.all.Base
        :return: The printed MathML object.
        """

        assert isinstance(expr, _sympy.Add)

        args = self._as_ordered_terms(expr, order=order)
        PREC = _sympy_precedence.precedence(expr)
        dt = _mathml.RowComponent()
        args_len = len(args)

        #  Iterator each part.
        for arg_id in range(0, args_len):
            cur_arg = args[arg_id]
            if cur_arg.is_negative:
                #  Get the negative number.
                neg_arg = -cur_arg

                #  Get the precedence.
                CUR_PREC = _sympy_precedence.precedence(neg_arg)

                #  Add a '-' operator.
                dt.append_object(
                    _mathml.OperatorComponent(_mathml.OPERATOR_MINUS))

                # noinspection PyProtectedMember
                if CUR_PREC < PREC or (_coeff_isneg(neg_arg) and arg_id != 0):
                    #  Insert the argument with parentheses around.
                    dt.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_LEFT_PARENTHESIS))
                    dt.append_object(self._print(neg_arg))
                    dt.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_RIGHT_PARENTHESIS))
                else:
                    #  Insert the argument only.
                    dt.append_object(self._print(neg_arg))
            else:
                #  Add a '+' operator if the argument is not the first one.
                if arg_id != 0:
                    dt.append_object(
                        _mathml.OperatorComponent(_mathml.OPERATOR_PLUS))

                #  Get the precedence.
                CUR_PREC = _sympy_precedence.precedence(cur_arg)

                # noinspection PyProtectedMember
                if CUR_PREC < PREC or (_coeff_isneg(cur_arg) and arg_id != 0):
                    #  Insert the argument with parentheses around.
                    dt.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_LEFT_PARENTHESIS))
                    dt.append_object(self._print(cur_arg))
                    dt.append_object(
                        _mathml.OperatorComponent(
                            _mathml.OPERATOR_RIGHT_PARENTHESIS))
                else:
                    #  Insert the argument only.
                    dt.append_object(self._print(cur_arg))

        return dt