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)]
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])
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
def gen_num(n): return [NarrRoot(+1 if n >= 0 else -1, 'NUMBER'), float(abs(n))]
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
#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')
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]