Esempio n. 1
0
def gen_atom_number(num):
    """
    生成一个常量表达式,输入是数字。小数点后至多保留 3 位。
    """
    num = float(num)
    if not num.is_integer():
        num = round(num, 3) # avoid infinity decimals

    if num >= .0:
        return [NarrRoot(+1, 'NUMBER'), abs(num)]
    else:
        return [NarrRoot(-1, 'NUMBER'), abs(num)]
Esempio n. 2
0
def _apply_sign(narr, apply_product):
    """
    apply sign to `narr', distribute sign in addition case.
    """
    if apply_product > 0:
        return

    root = narr[0]
    old_sign, Type = root.get()
    narr[0].apply_sign(apply_product)

    if Type == 'add':
        # Distribute signs (i.e., make addition root positive)
        narr[:], _ = expression.passchildren(NarrRoot(+1, Type), [narr])
Esempio n. 3
0
    def _level_apply(self, narr, debug=False):
        ret_narrs = []  # store possible results
        ani_narrs = []  # store transition animations
        root_sign, root_type = narr[0].get()

        # ignore terminal tokens (no rule has a single terminal token as pattern)
        if root_type in expression.terminal_tokens():
            return [], []

        for pattern in self.rules:
            wildcards_idx = self.wildcards_idx[pattern]
            no_permute = (wildcards_idx !=
                          None) or root_type in expression.no_permute_tokens()

            if debug:
                rich.print(
                    f'\n[red]level apply[/] {pattern} wildcards_idx={wildcards_idx},'
                    + f' no_permute={no_permute} [red]to[/]',
                    expression.narr2tex(narr))

            # extract and try partial one or two operands to match against pattern
            for construct_tree, brothers, ani_tree in self._children_permutation(
                    narr, no_permute=no_permute):
                rewritten_narr, is_applied = self._exact_apply(pattern,
                                                               construct_tree,
                                                               debug=debug)
                if is_applied:
                    new_narr = []  # construct a new father
                    if len(brothers) > 0:
                        if self.root_sign_reduce:
                            # always positive new father, in case the negative
                            # sign of father is also reduced, e.g. -abc => (ab)c
                            new_root = NarrRoot(+1, root_type)
                        else:
                            # in addition case, we will need to keep father sign,
                            # e.g. -(1+2+3) => -(3+3)
                            new_root = NarrRoot(root_sign, root_type)

                        new_narr = [new_root, None, *brothers]
                        expression.replace_or_pass_children(
                            new_narr, 0, rewritten_narr)
                    else:
                        # the entire expression in this level gets reduced
                        new_narr = rewritten_narr
                        if not self.root_sign_reduce and root_sign < 0:
                            new_narr[0].apply_sign(-1)

                    #print('[animat]', expression.narr2tex(ani_tree))
                    #print('[result]', expression.narr2tex(new_narr))
                    #print()
                    if False:
                        rich.print('[red]level apply[/]:')
                        print('[origin]', expression.narr2tex(narr))
                        print('[pattern]', pattern)
                        print('[result]', expression.narr2tex(new_narr))
                        print()

                    _, append = Axiom()._uniq_append(ret_narrs, new_narr,
                                                     self.max_results)
                    if append: ani_narrs.append(ani_tree)
        return ret_narrs, ani_narrs
Esempio n. 4
0
 def gen_num(n):
     return [NarrRoot(+1 if n >= 0 else -1, 'NUMBER'), float(abs(n))]
Esempio n. 5
0
def test_alpha_equiv(narr1, narr2, alpha_universe=[{}], debug=False):
    root1, root2 = narr1[0], narr2[0]
    sign1, sign2 = root1[0], root2[0]
    type1, type2 = root1[1], root2[1]

    if debug:
        print('test_alpha_equiv')
        #for alpha in alpha_universe:
        #    alpha_prettyprint(alpha)
        rich.print('[bold green]1[/]', end=" ")
        expression.narr_prettyprint(narr1)
        rich.print('[bold red]2[/]', end=" ")
        expression.narr_prettyprint(narr2)

    if type1 == 'NUMBER':
        return type1 == type2 and sign1 == sign2 and narr1[1] == narr2[
            1], alpha_universe

    elif type1 in ['VAR', 'WILDCARDS']:

        name1 = narr1[1] if type1 == 'VAR' else '*' + narr1[1]
        narr2 = deepcopy(narr2)

        # handle sign
        _apply_sign(narr2, sign1)

        #print(name1, end=' --> ')
        #print(narr2)
        #print()

        # uppercase pattern such as X, Y only match variables / polynomials
        if name1.isupper() and type2 not in ['VAR', 'sup']:
            return False, []
        # same variables must match same structures
        else:
            return alpha_universe_add_constraint(alpha_universe, name1, narr2)

    # quick test of identicalness for non-wildcards pattern
    wildcards_index = expression.get_wildcards_index(narr1)
    if root1 != root2:
        return False, []
    elif len(narr1[1:]) != len(narr2[1:]) and wildcards_index is None:
        return False, []

    alpha_universe_new = []
    # use exact order for concrete match or permuted order for wildcards match.
    # (the latter will possibly generate multiple universes/possibilities)
    permutations = [
        narr2[1:]
    ] if wildcards_index == None else children_wildcards_permutation(narr2)
    for perm_children in permutations:
        match_perm = True  # require all children get matched.
        alpha_universe_copy = deepcopy(alpha_universe)
        for i, c1 in enumerate(narr1[1:]):
            # safe-guard for long wildcards, e.g., 'abc*' matching 'ab'
            if i >= len(perm_children):
                match_perm = False
                break

            if c1[0][1] == 'WILDCARDS':
                # wildcards match (no sign reduce here)
                c2 = [NarrRoot(+1, type2)] + perm_children[i:]
                # unwrap matched group if necessary
                if len(c2[1:]) == 1:
                    c2 = c2[1]
            else:
                # concrete child match
                c2 = perm_children[i]

            # test subtree
            match_any, alpha_universe_copy = test_alpha_equiv(
                c1, c2, alpha_universe=alpha_universe_copy, debug=debug)

            if match_any:
                # stop early for wildcards match
                if c1[0][1] == 'WILDCARDS':
                    break
            else:
                match_perm = False
                break

        if match_perm:
            alpha_universe_new += alpha_universe_copy

    return len(alpha_universe_new) > 0, alpha_universe_new
Esempio n. 6
0
    #narr2 = expression.tex2narr('-(\\sqrt{x})^{2}')

    #narr1 = expression.tex2narr('0 (-n)')
    #narr2 = expression.tex2narr('- 0 n')

    #narr1 = expression.tex2narr('-x \\times *{1} + x \\times *{2}')
    #narr2 = expression.tex2narr('-25 \\times 51 + 25 \\times 48')

    #narr1 = expression.tex2narr('+(-X)(-X)')
    #narr2 = expression.tex2narr('-yy')

    #narr1 = expression.tex2narr('a + *{1}')
    #narr1 = expression.tex2narr('- a - *{1}')
    narr1 = expression.tex2narr('-a')
    narr2 = [
        NarrRoot(1, 'add'), [NarrRoot(1, 'NUMBER'), 30.0],
        [
            NarrRoot(1, 'add'), [NarrRoot(1, 'NUMBER'), 1.0],
            [NarrRoot(1, 'NUMBER'), 3.0]
        ]
    ]

    is_equiv, rewrite_rules = test_alpha_equiv(narr1, narr2, debug=True)
    if is_equiv:
        rich.print('[bold green]Is alpha-equivalent')
        alpha = rewrite_rules[0]
        alpha_prettyprint(alpha)
        rewritten_narr = rewrite_by_alpha(narr1, alpha)
        rich.print('[[rewritten]]', expression.narr2tex(rewritten_narr))
    else:
        rich.print('[bold red]Not alpha-equivalent')
Esempio n. 7
0
        if is_applied:
            rewrite_rules['X'] = new_narr
            return rewrite_by_alpha(output_tempalate, rewrite_rules), True
        else:
            return new_narr, False
    return narr, False

canonicalize = (
    Axiom(name='去括号')
    .add_rule('# a *{1}', 'X', animation='`#1 a *{1}`[replace]{X}', dynamic_procedure=_canonicalize)
    .add_rule('# a # *{1}', 'X', animation='`#1 a #2 *{1}`[replace]{X}', dynamic_procedure=_canonicalize)
    .add_rule('a', 'X', animation='`a`[replace]{X}', dynamic_procedure=_canonicalize)

    .add_test(
         [NarrRoot(1, "eq"),
             [NarrRoot(1, "add"),
                 [NarrRoot(1, "mul"),
                     [NarrRoot(1, "NUMBER"), 3.0],
                     [NarrRoot(1, "VAR"), 'x']
                 ],
                 [NarrRoot(1, "NUMBER"), 3.0],
                 [NarrRoot(1, "add"),
                    [NarrRoot(-1, "mul"),
                        [NarrRoot(1, "NUMBER"), 2.0],
                        [NarrRoot(1, "VAR"), 'x']
                    ],
                    [NarrRoot(1, "NUMBER"), 1.0]
                 ]
             ],
             [NarrRoot(1, "NUMBER"), 0.0]