Beispiel #1
0
def print_steps(steps):
    for i, (narr, ani_narr, axiom, axiomIdx) in enumerate(steps):
        tex = expression.narr2tex(narr)
        value = state_value(narr)
        rich.print(f'[red]{i + 1}[/red] [blue]{value:.2f}[/]', end=" ")
        print(axiom.name())
        if ani_narr:
            ani_tex = expression.narr2tex(ani_narr)
            print('\t', ani_tex)
        print('\t', tex)
Beispiel #2
0
 def _uniq_append(result_narrs, new_narr, max_results):
     full = False
     if len(result_narrs) + 1 > max_results:
         return True, False
     applied_set = set([expression.narr2tex(narr) for narr in result_narrs])
     new_tex = expression.narr2tex(new_narr)
     append = False
     if new_tex not in applied_set:
         result_narrs.append(new_narr)
         append = True
     return full, append
def random_polynomial_term():
    err = False
    build_op = tr2narr.sup
    t1 = random_tok()

    if 'order2' == nonUniformChoice(
        ['order1', 'order2'],
        [0.5, 0.5]
    ):
        sign = nonUniformChoice(
            [+1, -1],
            [0.5, 0.5]
        )

        if sign < 0:
            t0 = tr2narr.null_reduce([])
            t1 = tr2narr.minus([t0, t1])

        t2 = random_tok(only_number=True, small_number=True)
        t1 = build_op([t1, t2])

    try:
        tex = expression.narr2tex(t1)
        expression.tex2narr(tex)
    except Exception as err_msg:
        err = True

    return tex, err
Beispiel #4
0
def alpha_prettyprint(alpha):
    print('rewrite rules:')
    if len(alpha) == 0:
        print('\t(empty)')
    else:
        for key in alpha:
            print(f'\t[{key}]:', end=' ')
            print(expression.narr2tex(alpha[key]))
Beispiel #5
0
def dfs(narr,
        axioms,
        debug=False,
        maxsteps=150,
        animation_mode=False,
        printTrim=False):
    any_err = None
    try:
        next_steps = [(narr, None, Axiom(name='原式'), -1)]
        return_steps = []
        cnt = 0
        while len(next_steps) > 0:
            narr, ani_narr, axiom, axiom_idx = next_steps[0]

            output_narr = deepcopy(narr)
            #print('[output narr]', narr)

            if animation_mode:
                if printTrim:
                    rich.print('[blue]before trim[/]')
                    expression.narr_prettyprint(narr)
                    print('[tex]', expression.narr2tex(narr))
                expression.trim_animations(narr)
                if printTrim:
                    rich.print('[blue]after trim[/]')
                    expression.narr_prettyprint(narr)
                    print('[tex]', expression.narr2tex(narr))

            return_steps.append((output_narr, ani_narr, axiom, axiom_idx))
            next_steps = possible_next_steps(narr,
                                             axioms,
                                             state.value_v1,
                                             animation_mode=animation_mode,
                                             fast_return=True,
                                             debug=debug)
            if cnt > maxsteps:
                any_err = "maximum steps reached."
                break
            cnt += 1
    except KeyboardInterrupt:
        pass

    return return_steps, any_err
Beispiel #6
0
def best_child_of(father, c_param=None, debug=False):
    """
    根据 UCT 选择最好的儿子节点
    """
    q, N, narr, _, _, _, children = father
    if c_param is None:
        weights = children_weights(father, debug=debug)
    else:
        weights = children_weights(father, c_param=c_param, debug=debug)
    argmax_idx = argmax(weights)

    if debug:
        print(f"\nfather", expression.narr2tex(narr))
        for i, ((q, n, narr, _, a, ai, _),
                UCT) in enumerate(zip(children, weights)):
            print()
            print(f"child [[{i}]] of axiom#{ai}", a.name())
            print(
                f"[UCT={UCT:.4f}, q/n={q:.2f}/{n}, N={N}, c_param={c_param}]",
                expression.narr2tex(narr))
        print('\n[choice index]', f"[[{argmax_idx}]]")
        print()
    return children[argmax_idx], weights[argmax_idx], argmax_idx
Beispiel #7
0
def print_UCT(father, detailed=False):
    q, n, f_narr, _, _, _, children = father
    children_visits = [c[1] for c in children]
    children_narrs = [c[2] for c in children]
    zip_arr = zip(children, children_weights(father, c_param=.0),
                  children_visits, children_narrs)

    if detailed:
        arr = [(c[4].name(), round(w, 3), f'{visits}/{n}', narr)
               for c, w, visits, narr in zip_arr]
    else:
        arr = [(c[4].name(), round(w, 3), f'{visits}/{n}')
               for c, w, visits, _ in zip_arr]

    arr.sort(key=lambda x: x[1], reverse=True)

    if detailed:
        print(expression.narr2tex(f_narr))
        for axiom_name, UCT, visits, narr in arr:
            rich.print('[green]UCT:[/]', end=" ")
            print(UCT, visits, axiom_name, expression.narr2tex(narr))
    else:
        print('[UCT]', arr)
Beispiel #8
0
def value_v1(narr, debug=False):
    """
    计算 表达式的价值(等于各个符号频率的自定义加权和)
    """
    if isinstance(narr, str):
        return value(expression.tex2narr(narr))

    narr = expression.trim_animations_copy(narr)

    value_dict = {
        'VAR': 10,
        'NUMBER_integer': 0.1,
        'NUMBER_decimal': 2,
        'NUMBER_pad_zeros': -0.25,
        'NUMBER_one': -0.1,
        'NUMBER_zero': 0.1,
        'NUMBER_in_sqrt': 0.5,
        'eq': 0,
        'neg': 0.5,
        'add': 2,
        'mul': 1,
        'div': 10,
        'frac': 8,
        'ifrac': 20,
        'sup': 4,
        'abs': 1,
        'sqrt': 1,
        'n_terms': 0.6,
        'n_terms_in_sqrt': 25,
        'n_deepest_var_level': 100,
        'right_side_of_eq': 200,
    }
    stats = token_stats(narr, {})

    if debug:
        print('[value_v1]', expression.narr2tex(narr))
        print(stats)

    accum = 0
    # symbol type values
    for key in stats:
        if key in value_dict:
            accum += stats[key] * value_dict[key]
    # number sum values
    if 'NUMBER_sum' in stats:
        accum += math.log(1 + stats['NUMBER_sum']) / 2
    if 'NUMBER_in_sqrt' in stats:
        accum += 1.5 * math.log(1 + stats['NUMBER_in_sqrt'])
    return -accum
Beispiel #9
0
    def _fraction_cancel(narr, debug=False):
        sign, Type = narr[0].get()
        if Type != 'frac':
            return narr

        # extract weights
        numerator_weights = Axiom()._extract_weights(narr[1])
        if any([x is None for x in numerator_weights]):
            return narr

        denominator_weights = Axiom()._extract_weights(narr[2])
        if any([x is None for x in denominator_weights]):
            return narr

        # cancel weights
        L = len(numerator_weights)
        weights = np.array(numerator_weights + denominator_weights, dtype=int)
        gcd = np.gcd.reduce(weights)
        weights = (weights // gcd).tolist()

        # restore weights
        numerator_weights = weights[:L]
        denominator_weights = weights[L:]

        if debug:
            rich.print('[yellow]cancel fraction:', expression.narr2tex(narr))
            print('numerator:', numerator_weights)
            print('denominator:', denominator_weights)

        Axiom()._restore_weights(numerator_weights, narr[1])
        Axiom()._restore_weights(denominator_weights, narr[2])

        if debug:
            rich.print('[yellow]after:', expression.narr2tex(narr))
            expression.narr_prettyprint(narr)
        return narr
def random_exp(complexity=2):
    """
    按照复杂度指示生成随机数学表达式
    """
    err = False
    tex = ''
    t1 = tr2narr.null_reduce([])
    for _ in range(complexity):
        # null-reduce must be commutative
        commutative = (len(t1) == 0)

        n_oprands, build_op = random_operator(commutative=commutative)

        if n_oprands == 2:
            always_t12 = False

            if tr2narr.sup == build_op:
                t2 = random_tok(only_number=True, small_number=True)
                always_t12 = True

            elif 'simple' == nonUniformChoice(
                ['complex', 'simple'],
                [0.2, 0.8]
            ):
                t2 = random_tok()
            else:
                random_complexity = bounded_guassian_sample(3, 5)
                tex, err = random_exp(complexity=random_complexity)
                if err: break
                t2 = expression.tex2narr(tex)

            if always_t12 or random.choice(['12', '21']) == '12':
                t1 = build_op([t1, t2])
            else:
                t1 = build_op([t2, t1])
        else:
            t1 = build_op([t1])

        try:
            tex = expression.narr2tex(t1)
            expression.tex2narr(tex)
        except Exception as err_msg:
            err = True
            #rich.print('[red]invalid random expression')
            break

    return tex, err
Beispiel #11
0
def render_steps(steps, output='./render-tex.html', show_index=False):
    display_str = '\\begin{align}'
    for i, step in enumerate(steps):
        if len(step) == 4:
            narr, _, axiom, axiom_idx = step
        else:
            narr, axiom, axiom_idx = step

        tex = expression.narr2tex(narr)
        if show_index: display_str += '' if i == 0 else ('\\text{step %d}' % i)
        display_str += '&' if i == 0 else '=&'
        display_str += tex
        if axiom_idx >= 0:
            text = axiom.name() + f' (规则 {axiom_idx})'
            display_str += ('\\qquad %s' % latex_text(text))
        display_str += '\\\\'

    display_str += '\\end{align}'
    output_html(output, display_str)
def random_equations():
    """
    生成等号两边由随机表达式组成的等式
    """
    build_op = tr2narr.eq
    tex1, err1 = random_terms()
    tex2, err2 = random_terms()

    if err1 or err2:
        return '', True

    try:
        t1 = expression.tex2narr(tex1)
        t2 = expression.tex2narr(tex2)
        t1 = build_op([t1, t2])
        tex = expression.narr2tex(t1)
        expression.tex2narr(tex)
    except Exception as err_msg:
        return '', True

    return tex, False
Beispiel #13
0
def value_v2(narr, level=0, debug=False):
    stats = {
        'right_side_of_eq': 0,
        'neg': 0,
        'NUMBER_level_cnt': 0,
        'NUMBER_sum': 0,
        'NUMBER_in_sqrt': 0,
        'NUMBER_one_zero': 0,
        'NUMBER_other_ints': 0,
        'NUMBER_pad_zeros': 0,
        'NUMBER_decimal': 0,
        'VAR_max_level': 0,
        'VAR_level_cnt': 0
    }

    narr = expression.trim_animations_copy(narr)

    collect_stats(narr, stats, 0, None, False)

    if debug:
        tex = expression.narr2tex(narr)
        print('[value_v2]', tex)

    complexity = [
        (2.0 * stats['right_side_of_eq'])**3,
        1.0 * math.log(1 + math.log(1 + stats['NUMBER_sum'])),
        5.0 * math.log(1 + stats['NUMBER_in_sqrt']),
        1.0 * (0 + 0.9 * stats['NUMBER_one_zero'] +
               1.0 * stats['NUMBER_other_ints'] + 0.1 * stats['neg'] + 3.0 +
               stats['NUMBER_decimal'] - 0.2 * stats['NUMBER_pad_zeros'] +
               3.0 * stats['VAR_level_cnt'] + 1.0 * stats['NUMBER_level_cnt']),
        (2.0 * stats['VAR_max_level'])**2
    ]

    if debug:
        print(stats)
        print(complexity)

    return -sum(complexity)
Beispiel #14
0
def back_off_step(steps, debug=False):
    """
    裁剪 MCTS 最后几步的探索步骤,确保得到的 value 比较小
    """
    max_val = max([state_value(narr) for narr, a, ai in steps])

    while len(steps) > 1:
        cur_step = steps[-1]
        narr, _, _ = cur_step
        val = state_value(narr)

        if val >= max_val:
            break
        else:
            if debug:
                expr = expression.narr2tex(narr)
                val = state_value(narr)
                rich.print(f'[magenta]back-off[/] [blue]val={val:.3f}[/]',
                           end=' ')
                print(expr)
            steps.pop()

    return steps
def random_terms():
    """
    将随机表达式按项组合,生成随机加和表达式
    """
    any_err = True
    build_op = tr2narr.add
    t1 = tr2narr.null_reduce([])

    # the number of terms is sampled from normal distribution
    n_terms = bounded_guassian_sample(3, 6)

    for _ in range(n_terms):
        if 'nested' == nonUniformChoice(
            ['nested', 'polynomial'],
            [0.2, 0.8]
        ):
            tex_t2, err = random_exp()
        else:
            tex_t2, err = random_polynomial_term()

        if err:
            continue
        else:
            any_err = False

        t2 = expression.tex2narr(tex_t2)
        if random.choice(['12', '21']) == '12':
            t1 = build_op([t1, t2])
        else:
            t1 = build_op([t2, t1])

    if len(t1) == 0:
        return '', True
    else:
        tex = expression.narr2tex(t1)
        return tex, any_err
Beispiel #16
0
    def _exact_apply(self, pattern, narr, debug=False):
        # refuse to apply when rule is not animation compatible in animation mode.
        if self.animation_mode and pattern not in self.animation:
            return narr, False

        # apply pattern transformation to nested array
        pattern_narr = self.narrs[pattern]
        is_match, rewrite_rules = test_alpha_equiv(pattern_narr,
                                                   narr,
                                                   debug=False)

        if debug:
            # Example:
            # Axiom: (a+b)(a-b) => (a)^{2} - (b)^{2}
            #          pattern   =>  destination
            # narr: (-xy - z)(-xy + z)
            # rewrite_rules:
            #    a -> -xy
            #    b -> -z
            print()
            if False:
                print('pattern:', pattern_narr)
                print('subject:', narr)
            else:
                print('pattern:', expression.narr2tex(pattern_narr))
                print('subject:', expression.narr2tex(narr))
            rich.print('match:', is_match)

        if is_match:
            if debug:
                alpha_prettyprint(rewrite_rules[0])

            dest = self.animation[
                pattern] if self.animation_mode else self.rules[pattern]
            dest_narr = [self.narrs[d] for d in dest] if isinstance(
                dest, list) else self.narrs[dest]

            if debug:
                print('dest:', dest)

            call = self.dp[pattern]
            if call is not None:  # dynamical axiom
                signs = self.signs[pattern]
                rewritten_narr, is_applied = call(pattern_narr, signs, narr,
                                                  rewrite_rules[0], dest_narr)
            else:
                rewritten_narr, is_applied = rewrite_by_alpha(
                    dest_narr, rewrite_rules[0]), True

            if debug:
                rich.print('applied:', is_applied, end=': ')
                if False:
                    print(rewritten_narr)
                else:
                    print(expression.narr2tex(rewritten_narr))

            # if a rule with higher priority get applied, later ones are ignored
            if is_applied:
                # post processes
                rewritten_narr = self._fraction_cancel(rewritten_narr)
                return rewritten_narr, True

        return narr, False
Beispiel #17
0
def policy_steps(narr,
                 all_axioms,
                 k=3,
                 debug=False,
                 nn_models=False,
                 lock=None):
    """
    结合 policy 网络预测的 prior 生成 steps 以及其每一种可能的概率
    """
    if nn_models:
        # get NN predictions
        expr = expression.narr2tex(narr)

        if lock: lock.acquire()
        j = nn_request({'req': 'rule', 'tex': expr})
        rules, probs, = j['rules'], j['probs']
        if lock: lock.release()

        if debug:
            rich.print('[[restrict apply]]', end=" ")
            rich.print([all_axioms[r].name() for r in rules])

        steps = possible_next_steps(narr,
                                    all_axioms,
                                    state_value,
                                    restrict_rules=rules)
        if len(steps) == 0:
            steps = possible_next_steps(narr,
                                        all_axioms,
                                        state_value,
                                        restrict_rules=None)

        steps = [(n, a, ai) for n, _, a, ai in steps]

        # combine NN priors
        base_prob = min(probs) / 2.0
        step_probs = [
            base_prob if ai not in rules else probs[rules.index(ai)]
            for s, a, ai in steps
        ]
        step_probs = np.array(step_probs)

        # normalize step probabilities
        sum_probs = step_probs.sum()
        if sum_probs != 0: step_probs = step_probs / sum_probs

        if debug:
            for prob, (s, a, ai) in zip(step_probs, steps):
                prob_percent = round(prob * 100, 2)
                rich.print(
                    f'NN Policy: axiom#[red]{ai}[/red] {a.name()} prob=[blue]{prob_percent}%[/blue]'
                )
                print(expression.narr2tex(s))
                print()

        return steps, step_probs
    else:
        # default steps without prior
        steps = possible_next_steps(narr, all_axioms, state_value)
        steps = [(n, a, ai) for n, _, a, ai in steps]
        return steps, [0 for _ in steps]
Beispiel #18
0
    def test(self,
             tex=None,
             debug=False,
             render=True,
             printNarr=False,
             printTrim=False,
             printJSON=False):
        # construct test pairs (TeX, expected TeX)
        tests = self.tests if tex is None else [(tex, None)]
        if len(tests) == 0: print('[no test case]')
        # test through each testcase for this axiom ...
        for test, expect in tests:
            expr = test if isinstance(test, str) else expression.narr2tex(test)
            narr = expression.tex2narr(expr) if isinstance(test, str) else test
            results = self.apply(narr, debug=debug)
            # render texs is for HTML preview
            render_texs = [expr]

            rich.print('[bold cyan][[test]][/]', end=" ")
            print(expr)
            #if printNarr:
            #    expression.narr_prettyprint(narr)

            for applied_narr, ani_narr in results:
                # print transition animations
                if ani_narr:
                    ani_tex = expression.narr2tex(ani_narr)
                    rich.print('[bold cyan][[transition]][/]', end=" ")
                    print(ani_tex)
                else:
                    rich.print('[bold cyan][[transition]][/]', None)

                # print result expression
                applied_tex = expression.narr2tex(applied_narr)
                rich.print('[bold cyan][[result]][/]', end=" ")
                print(applied_tex, end=" ")
                if expect is not None:
                    if applied_tex in expect:
                        rich.print('[bold green]pass[/]')
                    else:
                        rich.print('[bold red]failed[/]')
                else:
                    print()

                # render texs is for HTML preview
                render_texs.append(applied_tex)

                if printNarr:
                    rich.print("[red]narr[/]:")
                    expression.narr_prettyprint(applied_narr)

                if printTrim:
                    rich.print("[red]trim[/]:")
                    expression.trim_animations(applied_narr)
                    expression.narr_prettyprint(applied_narr)

                if printJSON:
                    rich.print('[red]JSON[/]:')
                    json = mathjs.tex2json(applied_tex, indent=4)
                    print(json)

            if render:
                import render_math
                render_math.render_equations(render_texs)
Beispiel #19
0
                steps = [(n, a, ai) for n, an, a, ai in steps]

            if err or always_use_MCTS:
                with open('fallback.log', 'a') as fh:
                    fh.write(f'#{i}: ' + expr + '\n')

                steps = mcts(narr, all_axioms, debug=False, n_sample_times=n_sample_times,
                    nn_models=None, force_single_thread=False)

            # make data pair
            data = []
            for j in range(1, len(steps)):
                last_narr, _, _ = steps[j - 1]
                narr, axiom, axiom_idx = steps[j]

                last_expr = expression.narr2tex(last_narr)
                expr = expression.narr2tex(narr)

                axiom_name = axiom.name()
                rich.print(f'step{j} axiom#{axiom_idx} {axiom_name}', expr)

                data.append((last_expr, axiom_idx + 1, expr))
            data.append((expr, 0, expr))

            # write data pair
            print(f'Test case: {i} / {len(testcases) - 1}')
            generate_corpus(i, data, steps, DIV=20)

            #input('pause')

        except KeyboardInterrupt:
Beispiel #20
0
def rollout(node,
            idx,
            all_axioms,
            n_times,
            visited,
            debug=False,
            nn_models=False,
            k=3,
            lock=None):
    """
    Monte-Carlo 树的 roll-out 操作
    """
    q, n, narr, father, axiom, axiom_idx, children = node

    cnt = 0

    values = [state_value(father[2])]
    choices = [idx + 1]

    root_tex = expression.narr2tex(father[2])

    if debug:
        print('[roll-out origin]', end=' ')
        rich.print(f'[blue]{values[0]:.2f}[/]', end=' ')
        print(root_tex)

    while True:
        q, n, narr, father, axiom, axiom_idx, children = node
        expr = expression.narr2tex(narr)

        if nn_models:
            # use NN to estimate the number of left-over steps
            if lock: lock.acquire()
            j = nn_request({'req': 'value', 'tex': expr})
            expr_val = j['value']
            if lock: lock.release()
        else:
            # use rule-based value function to indicate complexity
            expr_val = state_value(narr)

        values.append(expr_val)

        if debug:
            axiom_name = axiom.name()
            print(f'[roll-out depth={cnt}]', end=' ')
            rich.print(f'[blue]{expr_val:.2f}[/]', end=' ')
            print(axiom_name, expr)

        if expr in visited:
            if debug: rich.print(f'[[roll-out]] [red]visited![/]')
            reward, rewardless_len = 0, 0
            break

        steps, step_probs = policy_steps(narr,
                                         all_axioms,
                                         k=k,
                                         debug=False,
                                         nn_models=nn_models,
                                         lock=lock)

        if len(steps) == 0:
            if debug: print('[roll-out reach leaf]')

            reward, rewardless_len = reward_calc(
                values, relative_value=(nn_models is None))
            break

        elif cnt >= n_times:
            if debug: print(f'[roll-out stop early (max times reached)]')

            reward, rewardless_len = reward_calc(
                values, relative_value=(nn_models is None))
            break

        # randomly select index
        rollout_idx = random.randint(0, len(steps) - 1)

        choices.append(rollout_idx + 1)

        # dive to deeper node specified by index
        if lock: lock.acquire()
        fully_expand(node, steps, prior_arr=step_probs)
        _, _, _, _, _, _, children = node
        next_node = children[rollout_idx]
        if lock: lock.release()

        node = next_node
        cnt += 1

    # write to roll-out log
    if lock: lock.acquire()
    with open(rollout_logfile, 'a') as fh:
        fh.write(json.dumps(choices))
        fh.write(json.dumps([f'{reward:.3f}']))
        fh.write(' ' + root_tex)
        fh.write('\n')
    if lock: lock.release()

    return node, reward, rewardless_len
Beispiel #21
0
                                                 all_axioms,
                                                 state_value,
                                                 debug=True,
                                                 restrict_rules=rules)
            else:
                next_steps = possible_next_steps(narr,
                                                 all_axioms,
                                                 state_value,
                                                 debug=True)

            if len(next_steps) == 0:
                break

            # print choices
            rich.print(f'[bold red]current[/] [blue]{value:.2f}[/]:', end=" ")
            print(expression.narr2tex(narr))
            #expression.narr_prettyprint(narr)

            reward, _ = reward_calc(values)
            print('\033[91m', end='')
            print(
                f'origin value: {val0:.2f}, cur value: {value:.2f}, reward = {reward:.2f}'
            )
            print('\033[0m')

            while True:
                print_steps(next_steps)
                render_steps(steps[-1:] + next_steps,
                             show_index=True,
                             output='./debug.html')
                j = input('Enter choice (0 to print past steps): ')
Beispiel #22
0
def possible_next_steps(narr,
                        axioms,
                        state_value,
                        animation_mode=False,
                        debug=False,
                        restrict_rules=None,
                        fast_return=False):
    return_steps = []
    cur_value = state_value(narr)
    if debug:
        tex = expression.narr2tex(narr)
        rich.print(f'[light]{cur_value:.2f}', end=' ')
        print(tex)

    for axiom_idx, axiom in enumerate(axioms):
        if restrict_rules and axiom_idx not in restrict_rules:
            if debug:
                rich.print('[grey50][[N]]', end=' ')
                print(axiom.name(), end=' ')
                print(tex)
            continue

        axiom.animation_mode = animation_mode
        #print('restrict apply', [axioms[r].name() for r in restrict_rules if r >= 0])
        possible_applied_tuples = axiom.apply(narr)
        #print('done apply', axiom.name())

        value_constrain_narrs = []
        for applied_narr, ani_narr in possible_applied_tuples:
            value = state_value(applied_narr)
            if not axiom.allow_complication:
                if ((axiom.strict_simplify and value <= cur_value)
                        or value < cur_value):
                    if debug:
                        rich.print('[grey50][[x]]', end=' ')
                        tex = expression.narr2tex(applied_narr)
                        print(axiom.name(), end=' ')
                        rich.print(f'[light]{value:.2f}', end=' ')
                        print(tex)
                    continue

            value_constrain_narrs.append(
                (applied_narr, ani_narr, axiom, axiom_idx, value))

        return_steps += value_constrain_narrs

        if fast_return and len(value_constrain_narrs) > 0: break

    return_steps.sort(key=lambda x: (x[-2], -x[-1]))

    if debug:
        for i, (applied_narr, ani_narr, axiom, axiom_idx,
                value) in enumerate(return_steps):
            # print axiom name
            if i == 0:
                rich.print(f'[bright_green][[✓]]', end=' ')
            else:
                rich.print(f'[grey50][[ ]]', end=' ')
            print(axiom.name(), end=" ")
            # print value
            rich.print(f'[light]{value:.2f}', end=' ')
            # print tex
            tex = expression.narr2tex(applied_narr)
            print(tex)
        print()

    # trim value from tuples
    return [s[:-1] for s in return_steps]
Beispiel #23
0
        all_axioms = common_axioms()

    args = sys.argv[1:]
    if len(args) > 0:
        tex = args[0]
        narr = expression.tex2narr(tex)
        steps, err = dfs(narr, all_axioms, debug=False, animation_mode=True)

        if err:
            print(err, file=sys.stderr)
            quit()

        ret_arr = []
        for i, (narr, ani_narr, axiom, axiom_idx) in enumerate(steps):
            trim_narr = expression.trim_animations_copy(narr)
            trim_tex = expression.narr2tex(trim_narr)

            animate_tex = expression.narr2tex(narr)
            animate_json = mathjs.tex2json(animate_tex)

            if ani_narr:
                ani_tex = expression.narr2tex(ani_narr)
                ani_json = mathjs.tex2json(ani_tex)
                ret_arr.append({
                    'tex': '\\text{transition step ...}',
                    'animate_tex': ani_tex,
                    'animate_json': ani_json,
                    'axiom': '移项',
                    'axiom_idx': -2
                })
Beispiel #24
0
    #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')
Beispiel #25
0
def mcts(narr0,
         all_axioms,
         sample_depth=4,
         n_sample_times=200,
         n_maxsteps=100,
         k=3,
         debug=False,
         nn_models=False,
         training=False,
         force_single_thread=False):
    #       q  n   narr  father  axiom   axiomIdx  children
    root = [0, 1, narr0, None, None, -1, []]
    moves = [root]

    render_steps([(narr0, None, -1)])

    global manager
    if not force_single_thread:
        # prepare proxy structure for parallel processes
        root[6] = manager.list([])
        root = manager.list(root)
        moves = [root]
    else:
        manager = None

    node = root
    visited = set([expression.narr2tex(narr0)])
    final_steps = []

    while True:
        q, n, narr, father, axiom, axiom_idx, children = node

        # debug print
        if True:
            #if debug:
            print('\033[94m', end='')
            expr_val = state_value(narr)
            print(f'[current] step={len(moves)}, val={expr_val:.1f}:',
                  expression.narr2tex(narr),
                  end='')
            print('\033[0m', end='\n')
            expression.narr_prettyprint(narr)

        steps, step_probs = policy_steps(narr,
                                         all_axioms,
                                         k=k,
                                         debug=debug,
                                         nn_models=nn_models)

        if debug:
            rich.print(f'[magenta]Candidate steps: {len(steps)}[/]')
            for i, (n, a, ai) in enumerate(steps):
                val = state_value(n)
                rich.print(f'[red]#{i+1}[/]', a.name(), ':', end=' ')
                rich.print(f'val={val:.2f}', end=' ')
                print(expression.narr2tex(n), end='\n\n')

            if False:
                from axiom import Axiom
                render_steps([(narr, Axiom(), -1)] + steps, show_index=True)
                choices = input('Limit choices: ')
                choices = [
                    i for i in map(lambda x: int(x), choices.split(','))
                ]
                rich.print(choices)
                steps = [steps[i - 1] for i in choices]

        if len(steps) == 0:
            if debug: print('[no more candidate steps]')
            if nn_models and training:
                policy = 0
                #policy_fine_tuning(nn_models, expr, policy, debug=debug, all_axioms=all_axioms)
            break

        if manager and not force_single_thread:
            evaluate_parallel(node,
                              all_axioms,
                              steps,
                              n_sample_times,
                              sample_depth,
                              visited,
                              debug=debug,
                              nn_models=nn_models,
                              k=k,
                              step_probs=step_probs)
        else:
            evaluate(node,
                     all_axioms,
                     steps,
                     n_sample_times,
                     sample_depth,
                     visited,
                     debug=debug,
                     nn_models=nn_models,
                     k=k,
                     step_probs=step_probs)

        # selection
        move_choice, w, _ = best_child_of(node, c_param=.0, debug=debug)
        move_to_expr = expression.narr2tex(move_choice[2])
        if w == 0 or move_to_expr in visited:
            print(
                f'[abort] best w={w:.2f}, visited: {move_to_expr in visited}')
            break
        else:
            if nn_models and training:
                policy = move_choice[5] + 1
                #policy_fine_tuning(nn_models, expr, policy, debug=debug, all_axioms=all_axioms)

            moves.append(move_choice)
            node = move_choice

            # construct steps to be returned
            final_steps = [(e, a, ai) for q, n, e, f, a, ai, c in moves]
            render_steps(final_steps)

            visited.add(move_to_expr)
            #if debug: print('[visited]', visited)

            if len(moves) >= n_maxsteps:
                if debug: print('[exceed max steps]')
                break

    if len(final_steps) > 0:
        final_steps = back_off_step(final_steps, debug=True)

    if nn_models and training:
        # fine-tune value network
        for i, (e, _, _) in enumerate(final_steps):
            value = -(len(final_steps) - i - 1)
            #value_fine_tuning(nn_models, e, value, debug=debug)
    return final_steps
Beispiel #26
0
def test():
    from test_cases import test_cases_x3_rational, test_cases_wiki131278697, test_case_from_log

    from common_axioms import common_axioms
    axioms = common_axioms(full=True)

    testcases = []

    tmp, _ = test_cases_x3_rational()
    testcases += tmp

    #testcases += [
    #    '\\frac{12a}{3a + a + 20a} - \\frac{1}{4}',
    #    '1 + \\frac{7}{3}',
    #    '4 -3 \\frac{1}{2}',
    #    '\\frac{(-3)^{3}}{2 \cdot \\frac{1}{4} \cdot (-\\frac{2}{3})^{2}} + 4 -4 \cdot \\frac{1}{3}',
    #    '\\frac{11}{2} (- \\frac{1}{6}) \\frac{3}{11} \\frac{4}{3}',
    #    '(-3\\frac{1}{3})\div2\\frac{1}{3}\\times\\frac{7}{10}',
    #    'a - x^{2} + x^{2} \\times 0.609 + 1 = 0',
    #    '1.609 \\times x^{2} + x^{2} + x^{2} \\times 2 \\times x = 0',
    #    '-x \\times 0.391 - 629 - x^{2} \\times 2 + y^{2} + x \\times \\frac{50}{x + y} = 0',

    #    # some tests for extracting common factors
    #    "25 \cdot 48 + 103 \cdot 25 - 25 \cdot 51",
    #    "-13 \\times \\frac{2}{3} - 0.34 \\frac{2}{7} + \\frac{1}{3}(-13) - \\frac{5}{7} 0.34",

    #    "-x 0.391 - 629 - 2 x^{2} + y^{2} + \\frac{50x}{x+y} = 0",
    #    "- (3\\frac{4}{17}) (2\\frac{2}{15}) - (7\\frac{4}{17}) (14 \\frac{13}{15}) - 4 (-14 \\frac{13}{15})",
    #    "(-3 - \\frac{4}{17}) \\times (14 + \\frac{13}{15}) - (3 + \\frac{4}{17}) \\times (2 + \\frac{2}{15})",
    #    #"-200.9 + 28 + 0.9 + (-8)",
    #    #"3+5\\times6-6\div3",
    #    #"\\frac{(-3)^{3}}{2 \\times \\frac{1}{4} (-\\frac{2}{3})^{2}} +4 -4 \\times\\frac{1}{3}",
    #    #"6 \div 3"
    #]

    nn_models = True
    debug = True
    force_single_thread = False

    n_steps = 0
    timer = Timer()
    open(rollout_logfile, 'w')
    #for i, expr in enumerate(testcases[-1:]):
    for i, expr in enumerate(testcases[:]):
        narr = expression.tex2narr(expr)

        n_sample_times = 22 if nn_models or force_single_thread else 440

        with timer:
            steps = mcts(narr,
                         axioms,
                         debug=debug,
                         n_sample_times=n_sample_times,
                         nn_models=nn_models,
                         force_single_thread=force_single_thread)

        for j, (narr, axiom, axiom_idx) in enumerate(steps):
            val = state_value(narr)
            expr = expression.narr2tex(narr)
            axiom_name = axiom.name() if axiom is not None else '原式'
            rich.print(f'step{j} {axiom_name} [blue]val={val:.2f}[/]', expr)

        render_steps(steps)
        n_steps += len(steps)
        print(f'steps: {len(steps)}')
        print(f'Test case: {i} / {len(testcases) - 1}')

        #print('Enter to continue')
        #input()

    timer.show_stats(n_steps=n_steps)
Beispiel #27
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
Beispiel #28
0
def test(all_axioms):
    from render_math import render_steps
    from test_cases import test_cases_x3_rational, test_cases_wiki131278697

    testcases = []

    tmp, _ = test_cases_x3_rational()
    testcases += tmp

    tmp, _ = test_cases_wiki131278697()
    testcases += tmp

    testcases += [
        '\\frac{12a}{3a + a + 20a} - \\frac{1}{4}',
        '1 + \\frac{7}{3}',
        '4 -3 \\frac{1}{2}',
        '\\frac{(-3)^{3}}{2 \cdot \\frac{1}{4} \cdot (-\\frac{2}{3})^{2}} + 4 -4 \cdot \\frac{1}{3}',
        '\\frac{11}{2} (- \\frac{1}{6}) \\frac{3}{11} \\frac{4}{3}',
        'a - x^{2} + x^{2} \\times 0.609 + 1 = 0',
        "25 \cdot 48 + 103 \cdot 25 - 25 \cdot 51",
        "-13 \\times \\frac{2}{3} - 0.34 \\frac{2}{7} + \\frac{1}{3}(-13) - \\frac{5}{7} 0.34",
        '(-3\\frac{1}{3})\div2\\frac{1}{3}\\times\\frac{7}{10}',
        "(-18) \div ((2\\frac{1}{4}) \\times (1 - \\frac{3}{4}))",

        #"(-3 - \\frac{4}{17}) (14\\frac{13}{15}) - (3\\frac{4}{17}) (2 + \\frac{2}{15})",
        "b + 3x^{2} +2b + 3b + x^{2}= 0",
        "(3 + \\frac{4}{17}) (-14\\frac{13}{15} - \\frac{2}{15}) - 2 \times 3 - 2 \\times \\frac{4}{17}",
        "-(3 + \\frac{4}{17}) \\times (14\\frac{13}{15}) - (3 + \\frac{4}{17}) \\times (2\\frac{2}{15})",
        "\\frac{-1}{\\frac{2}{3} \cdot \\frac{7}{10}}",
        "\\frac{ 60 (1 - \\frac{2}{5}) + 3}{2}"

        ## some animation testcases
        #"1 + 0 + 0 + 0 + 0",
        #'-3 \\frac{-2}{4}',
        #'\\frac{2}{3} \div \\frac{4}{5}',
        #'(\sqrt{2})^{2}',
        #'0+1+2',
        #'-\\frac{1}{-2} \div \\frac{-3}{4}',
        #'\\frac{x}{3xy}',
        #'-x x',
        #'-\\frac{8}{-2}',
        #"a + b = 3 - c",
        #"x + b = 12",
        #'\\frac{2}{x} + y = a + b',
        #'\\frac{1}{y} \\frac{x}{1}',
        #'-7(a-b)',
        #'-(-2-3)^{2}',
        #"\left| -(5+\\frac{1}{2})\\right| (\\frac{1}{3} - \\frac{1}{2}) \\frac{3}{11} \\div (1 - \\frac{1}{4})",
        #"2 + 7 + 8",
        #"3x + 3 = 2x - 1",
        #'2(a + b) + 3',
        #'2(a + b)',
        #'(-7) + 10 + (-3) + 6 + (-6)',
        #'-(3 - 2)x',
        #"(-3 - \\frac{4}{17}) \\times (14\\frac{13}{15}) - (3\\frac{4}{17}) \\times (2\\frac{2}{15})",
        #"\\frac{1}{2} \\times 10.2 - (\\frac{5}{4} + 1 - 9 \\frac{1}{7})^{2}"
    ]

    begin_from = 0

    n_steps = 0
    timer = Timer()

    #for i, test in enumerate(testcases):
    for i, test in enumerate(testcases[-1:]):
        if i < begin_from: continue

        test_narr = expression.tex2narr(test)

        with timer:
            steps, err = dfs(test_narr,
                             all_axioms,
                             debug=True,
                             animation_mode=True,
                             printTrim=False)
            if err:
                print('DFS error:', err)

        for narr, ani_narr, axiom, axiom_idx in steps:
            rich.print(f'[red]{axiom.name()}')

            narr = expression.trim_animations_copy(narr)

            tex = expression.narr2tex(narr)
            if ani_narr:
                ani_tex = expression.narr2tex(ani_narr)
                print('\t', ani_tex)
            print('\t', tex)

            #animation_json = mathjs.tex2json(tex)
            #print('\t', animation_json)

        render_steps(steps)

        n_steps += len(steps)
        print(f'steps: {len(steps)}')
        print(f'test case: {i} / {len(testcases)}')

        #input('Enter to continue...')

    timer.show_stats(n_steps=n_steps)
Beispiel #29
0
 def _print_results_in_tex(narrs):
     for n in narrs:
         print(expression.narr2tex(n))
     print()
Beispiel #30
0
def nn_value(narr):
    tex = expression.narr2tex(narr)
    expr_val, _ = nn.predict_value(tex, nn_models)
    return expr_val