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
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
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())
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
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)]
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
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))