Ejemplo n.º 1
0
def _decompile_super_electronic(charge, options):
    """Decompile electronic charge value.

    :type options: _opt.Option
    :param charge: The charge number (must be simplified).
    :param options: The BCE options.
    :return: The decompiled DOM node.
    """

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

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

        #  Decompile the charge part.
        r.append_object(_decompile_operand(charge, True, options))

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

        return r
Ejemplo n.º 2
0
    def _print_Add(self, expr, order=None):
        args = self._as_ordered_terms(expr, order=order)
        PREC = precedence(expr)
        dt = _mathml_comp.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 = precedence(neg_arg)

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

                if CUR_PREC < PREC or (_coeff_isneg(neg_arg) and arg_id != 0):
                    #  Insert the argument with parentheses around.
                    dt.append_object(
                        _mathml_comp.OperatorComponent(
                            _mathml_comp.OPERATOR_LEFT_PARENTHESIS))
                    dt.append_object(self._print(neg_arg))
                    dt.append_object(
                        _mathml_comp.OperatorComponent(
                            _mathml_comp.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_comp.OperatorComponent(
                            _mathml_comp.OPERATOR_PLUS))

                #  Get the precedence.
                CUR_PREC = precedence(cur_arg)

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

        return dt
Ejemplo n.º 3
0
def _decompile_operand(value, need_wrapping, options):
    """Decompile an operand.

    :type need_wrapping: bool
    :type options: _opt.Option
    :param value: The operand value (must be simplified).
    :param need_wrapping: Set to True if you need to wrap the expression when it is neither an integer nor a symbol.
                          Otherwise, set to False.
    :param options: The BCE options.
    :return: The decompiled DOM node.
    """

    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 decompiled expression.
            r = _mathml.RowComponent()
            r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
            r.append_object(_mexp_decompiler.decompile_mexp(value, options.get_protected_math_symbol_header()))
            r.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))
            return r
        else:
            return _mexp_decompiler.decompile_mexp(value, options.get_protected_math_symbol_header())
Ejemplo n.º 4
0
def decompile_ce(ce, options):
    """Decompile the combined balanced result to a human-readable form (string).

    :type ce: _ce_base.ChemicalEquation
    :type options: _opt.Option
    :param ce: The chemical equation (represented by ChemicalEquation class).
    :param options: The BCE options.
    :return: The decompiling result.
    """

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

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

    #  Process items on left side.
    for idx in range(0, ce.get_left_item_count()):
        #  Get the item.
        item = ce.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)

        #  Decompile the molecule.
        r.append_object(_ml_decompiler.decompile_ast(ast_root, options))

        #  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, ce.get_right_item_count()):
        #  Get the item.
        item = ce.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)

        #  Decompile the molecule.
        r.append_object(_ml_decompiler.decompile_ast(ast_root, options))

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

        #  Switch off the mark.
        r_is_first = False

    return r
Ejemplo n.º 5
0
def decompile_ast(root_node, options):
    """Decompile an AST to BCE expression.

    :type root_node: _ml_ast_base.ASTNodeHydrateGroup | _ml_ast_base.ASTNodeMolecule
    :type options: _opt.Option
    :param root_node: The root node of the AST.
    :param options: The BCE options.
    :return: The decompiled expression.
    """

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

    #  Initialize the decompiling result container.
    decompiled = {}

    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 decompiling result.
            build = _mathml.RowComponent()

            #  Decompile the prefix number part.
            pfx = work_node.get_prefix_number().simplify()
            if pfx != _math_cst.ONE:
                build.append_object(_decompile_operand(pfx, True, options))
                build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
                surround = True
            else:
                surround = False

            #  Decompile children nodes.
            build.append_object(decompiled[id(work_node[0])])
            for child_id in range(1, len(work_node)):
                build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_DOT))
                build.append_object(decompiled[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 decompiling result.
            decompiled[id(work_node)] = build
        elif work_node.is_molecule():
            assert isinstance(work_node, _ml_ast_base.ASTNodeMolecule)

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

            #  Decompile the prefix number part.
            pfx = work_node.get_prefix_number().simplify()
            if pfx != _math_cst.ONE:
                build.append_object(_decompile_operand(pfx, True, options))

            #  Decompile children nodes.
            for child_id in range(0, len(work_node)):
                build.append_object(decompiled[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"),
                                                               _decompile_super_electronic(
                                                                   el_charge,
                                                                   options)))
                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(),
                                                                 _decompile_super_electronic(el_charge, options))
                    else:
                        last_item = _mathml.SuperComponent(last_item,
                                                           _decompile_super_electronic(el_charge, options))

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

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

            #  Decompile and save the result.
            decompiled[id(work_node)] = _decompile_suffix(_mathml.TextComponent(work_node.get_atom_symbol()),
                                                          work_node,
                                                          options)
        elif work_node.is_parenthesis():
            assert isinstance(work_node, _ml_ast_base.ASTNodeParenthesisWrapper)

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

            #  Decompile.
            build.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_LEFT_PARENTHESIS))
            build.append_object(decompiled[id(work_node.get_inner_node())])
            build.append_object(_decompile_suffix(_mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS),
                                                  work_node,
                                                  options))

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

            #  Decompile and save the result.
            decompiled[id(work_node)] = _decompile_suffix(
                _mathml.TextComponent("[%s]" % work_node.get_abbreviation_symbol()),
                work_node,
                options)
        else:
            raise RuntimeError("Never reach this condition.")

    post_process = decompiled[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_status.STATUS_GAS:
            post_process.append_object(_mathml.TextComponent("g"))
        elif root_node.get_status() == _ml_status.STATUS_LIQUID:
            post_process.append_object(_mathml.TextComponent("l"))
        elif root_node.get_status() == _ml_status.STATUS_SOLID:
            post_process.append_object(_mathml.TextComponent("s"))
        elif root_node.get_status() == _ml_status.STATUS_AQUEOUS:
            post_process.append_object(_mathml.TextComponent("aq"))
        else:
            raise RuntimeError("BUG: No such molecule status.")
        post_process.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_RIGHT_PARENTHESIS))

    return decompiled[id(root_node)]
Ejemplo n.º 6
0
    def _print_Mul(self, expr):
        if _coeff_isneg(expr):
            x = _mathml_comp.RowComponent()
            x.append_object(
                _mathml_comp.OperatorComponent(_mathml_comp.OPERATOR_MINUS))
            x.append_object(self._print_Mul(-expr))
            return x

        PREC = precedence(expr)

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

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

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

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

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

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

        if coeff != 1:
            if precedence(coeff) < PREC:
                #  Insert the coefficient number with parentheses around.
                x.append_object(
                    _mathml_comp.OperatorComponent(
                        _mathml_comp.OPERATOR_LEFT_PARENTHESIS))
                x.append_object(self._print(coeff))
                x.append_object(
                    _mathml_comp.OperatorComponent(
                        _mathml_comp.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_comp.OperatorComponent(
                        _mathml_comp.OPERATOR_MULTIPLY))

        terms_len = len(terms)
        for term_id in range(0, terms_len):
            cur_term = terms[term_id]
            if precedence(cur_term) < PREC:
                x.append_object(
                    _mathml_comp.OperatorComponent(
                        _mathml_comp.OPERATOR_LEFT_PARENTHESIS))
                x.append_object(self._print(cur_term))
                x.append_object(
                    _mathml_comp.OperatorComponent(
                        _mathml_comp.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_comp.OperatorComponent(
                        _mathml_comp.OPERATOR_MULTIPLY))
        return x
Ejemplo n.º 7
0
    def _print_Pow(self, e):
        PREC = 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_comp.RootComponent(
                    printed_base, _mathml_comp.NumberComponent(str(e.exp.q)))
            else:
                #  Do SQRT operation.
                root = _mathml_comp.SquareRootComponent(printed_base)

            return root

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

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

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

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

            return final_node

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

        return _mathml_comp.SuperComponent(base_node, self._print(e.exp))