admin commited on
Commit
30e9073
·
0 Parent(s):

Initial commit

Browse files
Files changed (12) hide show
  1. .gitattributes +35 -0
  2. .gitignore +10 -0
  3. README.md +12 -0
  4. app.py +221 -0
  5. output_util.py +14 -0
  6. requirements.txt +3 -0
  7. sgntools.py +34 -0
  8. solution.py +132 -0
  9. solutions/e.py +68 -0
  10. solutions/eq.py +179 -0
  11. solutions/pi.py +136 -0
  12. solutions/pin.py +188 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ .idea/
2
+ .vscode/
3
+ workdir/mathjax-full/
4
+ workdir/res.html
5
+ workdir/pre/mma2sympy_input.txt
6
+ workdir/pre/mma2sympy_output.py
7
+ pre.nb
8
+ *__pycache__*
9
+ test.*
10
+ rename.sh
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Note that * QED
3
+ emoji: 🤓
4
+ colorFrom: indigo
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 5.22.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ short_description: Compare sizes by 'Note that' proof
12
+ ---
app.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from solution import solutions
4
+ from sympy.core.numbers import Rational
5
+
6
+ EN_US = os.getenv("LANG") != "zh_CN.UTF-8"
7
+ ZH2EN = {
8
+ "# “注意到”证明法比较大小": "# Compare sizes by 'Note that' proof",
9
+ "比较 e^(m/n) 与 u/v 大小": "Compare e^(m/n) and u/v",
10
+ "分母不能为 0": "The denominator cannot be 0",
11
+ "比较 π^n 与 p/q 大小": "Compare π^n and p/q",
12
+ "比较 e 与 p/q 大小": "Compare e and p/q",
13
+ "比较 π 与 p/q 大小": "Compare π and p/q",
14
+ "#### 证明结果": "#### Proof result",
15
+ "注意到": "Note that",
16
+ "状态栏": "Status",
17
+ "证毕!": "QED",
18
+ }
19
+
20
+
21
+ def _L(zh_txt: str):
22
+ return ZH2EN[zh_txt] if EN_US else zh_txt
23
+
24
+
25
+ def generate_md(args_dict, name):
26
+ ans_latex = solutions[name](**args_dict).get_latex_ans()
27
+ return f"{_L('注意到')} $${ans_latex}$$ {_L('证毕!')}"
28
+
29
+
30
+ def float_to_fraction(x):
31
+ x_str = "{0:.10f}".format(x).rstrip("0").rstrip(".") # 移除小数点后的无效零
32
+
33
+ # 检查是否为整数
34
+ if "." not in x_str:
35
+ return Rational(x_str), Rational(1)
36
+
37
+ # 分割整数部分和小数部分
38
+ integer_part, decimal_part = x_str.split(".")
39
+ decimal_digits = len(decimal_part)
40
+
41
+ # 构造分子和分母
42
+ numerator = int(integer_part + decimal_part)
43
+ denominator = 10**decimal_digits
44
+
45
+ # 简化分数
46
+ gcd_value = 1
47
+ a = numerator
48
+ b = denominator
49
+ while b != 0:
50
+ a, b = b, a % b
51
+ gcd_value = a
52
+
53
+ p = Rational(numerator // gcd_value)
54
+ q = Rational(denominator // gcd_value)
55
+ return p, q
56
+
57
+
58
+ def infer_pi(p, q):
59
+ status = "Success"
60
+ proof = None
61
+ try:
62
+ if q == 0:
63
+ raise ValueError(_L("分母不能为 0"))
64
+
65
+ p, q = float_to_fraction(p / q)
66
+ args_dict = {"p": p, "q": q}
67
+ proof = generate_md(args_dict, "π")
68
+
69
+ except Exception as e:
70
+ status = f"{e}"
71
+
72
+ return status, proof
73
+
74
+
75
+ def infer_e(p, q):
76
+ status = "Success"
77
+ proof = None
78
+ try:
79
+ if q == 0:
80
+ raise ValueError(_L("分母不能为 0"))
81
+
82
+ p, q = float_to_fraction(p / q)
83
+ args_dict = {"p": p, "q": q}
84
+ proof = generate_md(args_dict, "e")
85
+
86
+ except Exception as e:
87
+ status = f"{e}"
88
+
89
+ return status, proof
90
+
91
+
92
+ def infer_eq(q1, q2, u, v):
93
+ status = "Success"
94
+ proof = None
95
+ try:
96
+ if q2 == 0 or v == 0:
97
+ raise ValueError(_L("分母不能为 0"))
98
+
99
+ q1, q2 = float_to_fraction(q1 / q2)
100
+ u, v = float_to_fraction(u / v)
101
+ args_dict = {"q1": q1, "q2": q2, "u": u, "v": v}
102
+ proof = generate_md(args_dict, "e^q")
103
+
104
+ except Exception as e:
105
+ status = f"{e}"
106
+
107
+ return status, proof
108
+
109
+
110
+ def infer_pin(n: int, p, q):
111
+ status = "Success"
112
+ proof = None
113
+ try:
114
+ if q == 0:
115
+ raise ValueError(_L("分母不能为 0"))
116
+
117
+ p, q = float_to_fraction(p / q)
118
+ args_dict = {"n": n, "p": p, "q": q}
119
+ proof = generate_md(args_dict, "π^n")
120
+
121
+ except Exception as e:
122
+ status = f"{e}"
123
+
124
+ return status, proof
125
+
126
+
127
+ if __name__ == "__main__":
128
+ os.chdir(os.path.dirname(__file__))
129
+ for file_name in os.listdir("solutions"):
130
+ if not file_name.endswith(".py"):
131
+ continue
132
+
133
+ __import__(f"solutions.{file_name[:-3]}")
134
+
135
+ with gr.Blocks() as demo:
136
+ gr.Markdown(_L("# “注意到”证明法比较大小"))
137
+ with gr.Tabs():
138
+ with gr.TabItem("π"):
139
+ gr.Interface(
140
+ fn=infer_pi,
141
+ inputs=[
142
+ gr.Number(label="p", value=314),
143
+ gr.Number(label="q", value=100),
144
+ ],
145
+ outputs=[
146
+ gr.Textbox(label=_L("状态栏"), show_copy_button=True),
147
+ gr.Markdown(
148
+ value=_L("#### 证明结果"),
149
+ show_copy_button=True,
150
+ container=True,
151
+ min_height=122,
152
+ ),
153
+ ],
154
+ title=_L("比较 π 与 p/q 大小"),
155
+ flagging_mode="never",
156
+ )
157
+
158
+ with gr.TabItem("e"):
159
+ gr.Interface(
160
+ fn=infer_e,
161
+ inputs=[
162
+ gr.Number(label="p", value=2718),
163
+ gr.Number(label="q", value=1000),
164
+ ],
165
+ outputs=[
166
+ gr.Textbox(label=_L("状态栏"), show_copy_button=True),
167
+ gr.Markdown(
168
+ value=_L("#### 证明结果"),
169
+ show_copy_button=True,
170
+ container=True,
171
+ min_height=122,
172
+ ),
173
+ ],
174
+ title=_L("比较 e 与 p/q 大小"),
175
+ flagging_mode="never",
176
+ )
177
+
178
+ with gr.TabItem("e^q"):
179
+ gr.Interface(
180
+ fn=infer_eq,
181
+ inputs=[
182
+ gr.Number(label="m", value=3),
183
+ gr.Number(label="n", value=4),
184
+ gr.Number(label="u", value=2117),
185
+ gr.Number(label="v", value=1000),
186
+ ],
187
+ outputs=[
188
+ gr.Textbox(label=_L("状态栏"), show_copy_button=True),
189
+ gr.Markdown(
190
+ value=_L("#### 证明结果"),
191
+ show_copy_button=True,
192
+ container=True,
193
+ min_height=122,
194
+ ),
195
+ ],
196
+ title=_L("比较 e^(m/n) 与 u/v 大小"),
197
+ flagging_mode="never",
198
+ )
199
+
200
+ with gr.TabItem("π^n"):
201
+ gr.Interface(
202
+ fn=infer_pin,
203
+ inputs=[
204
+ gr.Number(label="n", value=3, step=1),
205
+ gr.Number(label="p", value=31),
206
+ gr.Number(label="q", value=1),
207
+ ],
208
+ outputs=[
209
+ gr.Textbox(label=_L("状态栏"), show_copy_button=True),
210
+ gr.Markdown(
211
+ value=_L("#### 证明结果"),
212
+ show_copy_button=True,
213
+ container=True,
214
+ min_height=122,
215
+ ),
216
+ ],
217
+ title=_L("比较 π^n 与 p/q 大小"),
218
+ flagging_mode="never",
219
+ )
220
+
221
+ demo.launch()
output_util.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy import latex
2
+
3
+
4
+ def to_latex(expr, is_coeff=False):
5
+ return "" if is_coeff and expr == 1 else f"{{{latex(expr)}}}"
6
+
7
+
8
+ def to_latexes(*args, is_coeff=False):
9
+ return [to_latex(i, is_coeff=is_coeff) for i in args]
10
+
11
+
12
+ sign2cmp = {1: ">", -1: "<"}
13
+
14
+ sign2cmp_inv = {1: "<", -1: ">"}
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ sympy~=1.12
2
+ pywebview~=5.3.2
3
+ ttkbootstrap~=1.10.1
sgntools.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def sgns(*args):
2
+ for i in args:
3
+ if i < 0:
4
+ break
5
+ else:
6
+ return 1
7
+
8
+ for i in args:
9
+ if i > 0:
10
+ break
11
+ else:
12
+ return -1
13
+
14
+ return 0
15
+
16
+
17
+ def sq_func_sgn(a, b, c):
18
+ r"""
19
+ let f(x) = a+bx+cx^2, x \in [0, 1]
20
+ :return: f(x)>=0? 1; f(x)<=0? -1; 0
21
+ """
22
+ f0 = a
23
+ f1 = a + b + c
24
+ fm = 0
25
+ if c != 0:
26
+ x_m = -b / (2 * c)
27
+ if 0 <= x_m <= 1:
28
+ fm = a + b * x_m + c * x_m**2
29
+
30
+ return sgns(f0, f1, fm)
31
+
32
+
33
+ def lin_func_sgn(a, b):
34
+ return sgns(a, a + b)
solution.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Iterable, Callable
2
+ from sympy import Eq, Expr, Symbol, linsolve, simplify, latex
3
+
4
+
5
+ class CannotCalculate(Exception):
6
+ pass
7
+
8
+
9
+ class BadInput(Exception):
10
+ pass
11
+
12
+
13
+ CONSTANT_TERM_KEY = "constant_term"
14
+
15
+
16
+ class GetIntegrate:
17
+ integrate_result_classes: dict[str, Expr | None]
18
+
19
+ def integrate_and_separate(
20
+ self, integrate_formula: Expr, integrate_args: tuple
21
+ ) -> dict[str, Expr]:
22
+ """
23
+ 解积分,分离各项
24
+ """
25
+ raise NotImplementedError(
26
+ "该函数已弃用,请使用 GetIntegrateFromData 类。如果想要使用它预处理,见 pre/old_solution.py"
27
+ )
28
+
29
+ def get_integrate_args(self, try_arg):
30
+ """
31
+ :return: integrand_function, (independent_variable, lower_limit, upper_limit)
32
+ 被积函数, (自变量, 下限, 上限)
33
+ """
34
+ raise NotImplementedError()
35
+
36
+ def tries(self, try_arg):
37
+ """
38
+ :return: {term_name: coefficient_of_the_term}
39
+ {该项的名称: 该项系数}
40
+ """
41
+ return self.integrate_and_separate(*self.get_integrate_args(try_arg))
42
+
43
+ def get_latex(self, try_arg, subs):
44
+ expr, args = self.get_integrate_args(try_arg)
45
+ expr = simplify(expr).subs(subs)
46
+ sym, low, high = args
47
+ return r"\int_{%s}^{%s} {%s} \mathrm{d} {%s}" % (
48
+ low,
49
+ high,
50
+ latex(simplify(expr)),
51
+ sym,
52
+ )
53
+
54
+
55
+ class GetIntegrateFromData(GetIntegrate):
56
+ data: dict[object, dict[str, Expr]]
57
+
58
+ def tries(self, try_arg):
59
+ return self.data[try_arg]
60
+
61
+
62
+ class Solution:
63
+ get_integrate: GetIntegrate
64
+ # gui: Pattern
65
+
66
+ get_tries_args: Callable[[], Iterable[Expr]]
67
+ """
68
+ Generate try_arg for each trial
69
+ 生成每一次尝试的 try_arg
70
+ """
71
+
72
+ symbols: tuple[Symbol, ...]
73
+ """
74
+ The undetermined variable to solve.
75
+ 要求的待定系数
76
+ """
77
+
78
+ integrate_result_classes_eq: dict[str, Expr]
79
+ """
80
+ {term_name: coefficient}
81
+ The value to which each term's coefficient is equal.
82
+ 每个项系数分别要等于的值
83
+ """
84
+
85
+ check_sgn: Callable
86
+ """
87
+ Input: unpacked solution of undetermined variables;
88
+ Output: 0 (cannot determine), 1 or -1 (can determine; 1 and -1 are interchangeable for greater or less than).
89
+ Module sgntools provides lin_func_sgn and sq_func_sgn. Call help() for further details.
90
+
91
+ 输入:解包的待定系数的值列表;
92
+ 输出: 0(无法确定), 1或-1(可以确定, 1和-1哪个代表大于、哪个代表小于, 是可以互换的)
93
+ sgntools 模块提供了 lin_func_sgn 和 sq_func_sgn 函数,详见 help()
94
+ """
95
+ # check_sgn: Callable[?, 1 | 0 | -1]
96
+
97
+ def get_symbols(self, separate_result):
98
+ """凑积分结果系数"""
99
+ system = [
100
+ Eq(int_term, self.integrate_result_classes_eq[key])
101
+ for key, int_term in separate_result.items()
102
+ ]
103
+ print(f"{system=}")
104
+ return linsolve(system, *self.symbols)
105
+
106
+ def try_times(self) -> tuple[Expr, dict, int] | tuple[None, None, None]:
107
+ for try_arg in self.get_tries_args():
108
+ separate = self.get_integrate.tries(try_arg)
109
+ for symbol_solution in self.get_symbols(separate):
110
+ if sgn := self.check_sgn(*symbol_solution):
111
+ return try_arg, dict(zip(self.symbols, symbol_solution)), sgn
112
+
113
+ return None, None, None
114
+
115
+ def get_latex_ans(self):
116
+ """
117
+ :return: None if it can't be solved; Otherwise, LaTeX (without "$$")
118
+ """
119
+ raise NotImplementedError()
120
+
121
+
122
+ # 插件注册(历史遗留问题)
123
+ solutions = {}
124
+ solution_sort = []
125
+
126
+
127
+ def register(name, solution, top=False):
128
+ solutions[name] = solution
129
+ if top:
130
+ solution_sort.insert(0, name)
131
+ else:
132
+ solution_sort.append(name)
solutions/e.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy import *
2
+ from sympy.abc import a, b, x
3
+ from output_util import to_latex, sign2cmp
4
+ from sgntools import lin_func_sgn
5
+ from solution import *
6
+
7
+ _data = {
8
+ 1: {"constant_term": 3 * a - 8 * b, "e_term": -a + 3 * b},
9
+ 2: {"constant_term": -38 * a + 174 * b, "e_term": 14 * a - 64 * b},
10
+ 3: {"constant_term": 1158 * a - 7584 * b, "e_term": -426 * a + 2790 * b},
11
+ 4: {"constant_term": -65304 * a + 557400 * b, "e_term": 24024 * a - 205056 * b},
12
+ 5: {
13
+ "constant_term": 5900520 * a - 62118720 * b,
14
+ "e_term": -2170680 * a + 22852200 * b,
15
+ },
16
+ 6: {
17
+ "constant_term": -780827760 * a + 9778048560 * b,
18
+ "e_term": 287250480 * a - 3597143040 * b,
19
+ },
20
+ }
21
+
22
+
23
+ class EIntegrate(GetIntegrateFromData):
24
+ # sympy 算力不够,以下由 MMA 算出
25
+ data = _data
26
+
27
+ def get_integrate_args(self, n):
28
+ return x**n * (1 - x) ** n * (a + b * x) * exp(x), (x, 0, 1)
29
+
30
+
31
+ class ESolution(Solution):
32
+ def __init__(self, p, q):
33
+ self.p = p
34
+ self.q = q
35
+ if self.q == 0:
36
+ raise BadInput()
37
+
38
+ self.get_integrate = EIntegrate()
39
+ self.symbols = (a, b)
40
+
41
+ self.integrate_result_classes_eq = {
42
+ "e_term": q,
43
+ CONSTANT_TERM_KEY: -p,
44
+ }
45
+ # check
46
+ self.check_sgn = lin_func_sgn
47
+
48
+ @staticmethod
49
+ def get_tries_args():
50
+ return EIntegrate.data.keys()
51
+
52
+ def get_latex_ans(self):
53
+ try_arg, symbol_val, sgn = self.try_times()
54
+ print(f"{(try_arg, symbol_val, sgn)=}")
55
+ if try_arg is None:
56
+ return None
57
+
58
+ p = to_latex(self.p)
59
+ q = to_latex(self.q, is_coeff=True)
60
+ I = self.get_integrate.get_latex(try_arg, symbol_val)
61
+ return rf"{q}e-{p} = {I} {sign2cmp[sgn]} 0"
62
+
63
+
64
+ register("e", ESolution)
65
+
66
+
67
+ if __name__ == "__main__":
68
+ print(ESolution(25, 9))
solutions/eq.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy import *
2
+ from sympy.abc import *
3
+ from output_util import to_latex, sign2cmp, to_latexes
4
+ from sgntools import lin_func_sgn
5
+ from solution import *
6
+
7
+ _data = {
8
+ (1,): {
9
+ "constant_term": a / q**2 + 2 * a / q**3 - 2 * b / q**3 - 6 * b / q**4,
10
+ "eq_term": a / q**2 - 2 * a / q**3 + b / q**2 - 4 * b / q**3 + 6 * b / q**4,
11
+ },
12
+ (2,): {
13
+ "constant_term": -2 * a / q**3
14
+ - 12 * a / q**4
15
+ - 24 * a / q**5
16
+ + 6 * b / q**4
17
+ + 48 * b / q**5
18
+ + 120 * b / q**6,
19
+ "eq_term": 2 * a / q**3
20
+ - 12 * a / q**4
21
+ + 24 * a / q**5
22
+ + 2 * b / q**3
23
+ - 18 * b / q**4
24
+ + 72 * b / q**5
25
+ - 120 * b / q**6,
26
+ },
27
+ (3,): {
28
+ "constant_term": 6 * a / q**4
29
+ + 72 * a / q**5
30
+ + 360 * a / q**6
31
+ + 720 * a / q**7
32
+ - 24 * b / q**5
33
+ - 360 * b / q**6
34
+ - 2160 * b / q**7
35
+ - 5040 * b / q**8,
36
+ "eq_term": 6 * a / q**4
37
+ - 72 * a / q**5
38
+ + 360 * a / q**6
39
+ - 720 * a / q**7
40
+ + 6 * b / q**4
41
+ - 96 * b / q**5
42
+ + 720 * b / q**6
43
+ - 2880 * b / q**7
44
+ + 5040 * b / q**8,
45
+ },
46
+ (4,): {
47
+ "constant_term": -24 * a / q**5
48
+ - 480 * a / q**6
49
+ - 4320 * a / q**7
50
+ - 20160 * a / q**8
51
+ - 40320 * a / q**9
52
+ + 120 * b / q**6
53
+ + 2880 * b / q**7
54
+ + 30240 * b / q**8
55
+ + 161280 * b / q**9
56
+ + 362880 * b / q**10,
57
+ "eq_term": 24 * a / q**5
58
+ - 480 * a / q**6
59
+ + 4320 * a / q**7
60
+ - 20160 * a / q**8
61
+ + 40320 * a / q**9
62
+ + 24 * b / q**5
63
+ - 600 * b / q**6
64
+ + 7200 * b / q**7
65
+ - 50400 * b / q**8
66
+ + 201600 * b / q**9
67
+ - 362880 * b / q**10,
68
+ },
69
+ (5,): {
70
+ "constant_term": 120 * a / q**6
71
+ + 3600 * a / q**7
72
+ + 50400 * a / q**8
73
+ + 403200 * a / q**9
74
+ + 1814400 * a / q**10
75
+ + 3628800 * a / q**11
76
+ - 720 * b / q**7
77
+ - 25200 * b / q**8
78
+ - 403200 * b / q**9
79
+ - 3628800 * b / q**10
80
+ - 18144000 * b / q**11
81
+ - 39916800 * b / q**12,
82
+ "eq_term": 120 * a / q**6
83
+ - 3600 * a / q**7
84
+ + 50400 * a / q**8
85
+ - 403200 * a / q**9
86
+ + 1814400 * a / q**10
87
+ - 3628800 * a / q**11
88
+ + 120 * b / q**6
89
+ - 4320 * b / q**7
90
+ + 75600 * b / q**8
91
+ - 806400 * b / q**9
92
+ + 5443200 * b / q**10
93
+ - 21772800 * b / q**11
94
+ + 39916800 * b / q**12,
95
+ },
96
+ (6,): {
97
+ "constant_term": -720 * a / q**7
98
+ - 30240 * a / q**8
99
+ - 604800 * a / q**9
100
+ - 7257600 * a / q**10
101
+ - 54432000 * a / q**11
102
+ - 239500800 * a / q**12
103
+ - 479001600 * a / q**13
104
+ + 5040 * b / q**8
105
+ + 241920 * b / q**9
106
+ + 5443200 * b / q**10
107
+ + 72576000 * b / q**11
108
+ + 598752000 * b / q**12
109
+ + 2874009600 * b / q**13
110
+ + 6227020800 * b / q**14,
111
+ "eq_term": 720 * a / q**7
112
+ - 30240 * a / q**8
113
+ + 604800 * a / q**9
114
+ - 7257600 * a / q**10
115
+ + 54432000 * a / q**11
116
+ - 239500800 * a / q**12
117
+ + 479001600 * a / q**13
118
+ + 720 * b / q**7
119
+ - 35280 * b / q**8
120
+ + 846720 * b / q**9
121
+ - 12700800 * b / q**10
122
+ + 127008000 * b / q**11
123
+ - 838252800 * b / q**12
124
+ + 3353011200 * b / q**13
125
+ - 6227020800 * b / q**14,
126
+ },
127
+ }
128
+
129
+
130
+ class EQIntegrate(GetIntegrateFromData):
131
+ data = _data
132
+
133
+ def get_integrate_args(self, try_arg):
134
+ n, q = try_arg
135
+ return x**n * (1 - x) ** n * (a + b * x) * e ** (q * x), (x, 0, 1)
136
+
137
+ def tries(self, try_arg):
138
+ n, q_value = try_arg
139
+ return {key: expr.subs(q, q_value) for key, expr in self.data[(n,)].items()}
140
+
141
+
142
+ class EQSolution(Solution):
143
+ def __init__(self, q1, q2, u, v):
144
+ if q2 == 0 or v == 0:
145
+ raise BadInput()
146
+
147
+ self.q = q1 / q2 # 输入都是 Rational 类型的,可以不损失精度相除
148
+ self.u = u
149
+ self.v = v
150
+ self.get_integrate = EQIntegrate()
151
+ self.symbols = (a, b)
152
+ self.integrate_result_classes_eq = {
153
+ "eq_term": v,
154
+ CONSTANT_TERM_KEY: -u,
155
+ }
156
+ # check
157
+ self.check_sgn = lin_func_sgn
158
+
159
+ def get_tries_args(self):
160
+ for (n,) in EQIntegrate.data.keys():
161
+ yield n, self.q
162
+
163
+ def get_latex_ans(self):
164
+ try_arg, symbol_val, sgn = self.try_times()
165
+ print(f"{(try_arg, symbol_val, sgn)=}")
166
+ if try_arg is None:
167
+ return None
168
+
169
+ u, q = to_latexes(self.u, self.q)
170
+ v = to_latex(self.v, is_coeff=True)
171
+ I = self.get_integrate.get_latex(try_arg, symbol_val)
172
+ return rf"{v}e^{q}-{u} = {I} {sign2cmp[sgn]} 0"
173
+
174
+
175
+ register("e^q", EQSolution)
176
+
177
+
178
+ if __name__ == "__main__":
179
+ print(EQSolution(Rational(2), 1, 7, 1).get_latex_ans())
solutions/pi.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.abc import a, b, c, x
2
+ from output_util import to_latex, sign2cmp
3
+ from sgntools import sq_func_sgn
4
+ from solution import *
5
+
6
+
7
+ class PiIntegrate(GetIntegrateFromData):
8
+ # sympy 算力不够,以下由 MMA 算出
9
+ # PiIF[n_] :=
10
+ # Collect[ Collect[
11
+ # PowerExpand[ Expand[
12
+ # Integrate[x^n*(1 - x)^n*(a + b x + c x^2)/(x^2 + 1),
13
+ # {x, 0, 1}]
14
+ # ]],
15
+ # Log[2]], Pi]
16
+ data = {
17
+ 1: {
18
+ "pi_term": (a - b - c) / 4,
19
+ "log2_term": (a + b - c) / 2,
20
+ CONSTANT_TERM_KEY: -a + b / 2 + 7 * c / 6,
21
+ },
22
+ 2: {
23
+ "pi_term": -b / 2,
24
+ "log2_term": a - c,
25
+ CONSTANT_TERM_KEY: (-2 * a / 3 + 19 * b / 12 + 7 * c / 10),
26
+ },
27
+ 3: {
28
+ "pi_term": (-a - b + c) / 2,
29
+ "log2_term": a - b - c,
30
+ CONSTANT_TERM_KEY: 53 * a / 60 + 34 * b / 15 - 92 * c / 105,
31
+ },
32
+ 4: {
33
+ "pi_term": -a + c,
34
+ "log2_term": 2 * b,
35
+ CONSTANT_TERM_KEY: 22 * a / 7 + 233 * b / 168 - 1979 * c / 630,
36
+ },
37
+ 5: {
38
+ "pi_term": -a + b + c,
39
+ "log2_term": 2 * (-a - b + c),
40
+ CONSTANT_TERM_KEY: 11411 * a / 2520 - 4423 * b / 2520 - 41837 * c / 9240,
41
+ },
42
+ 6: {
43
+ "pi_term": 2 * b,
44
+ "log2_term": -4 * a + 4 * c,
45
+ CONSTANT_TERM_KEY: (38429 * a) / 13860
46
+ - (174169 * b) / 27720
47
+ - (35683 * c) / 12870,
48
+ },
49
+ 7: {
50
+ "pi_term": 2 * (a + b - c),
51
+ "log2_term": 4 * (-a + b + c),
52
+ CONSTANT_TERM_KEY: -((421691 * a) / 120120)
53
+ - (407917 * b) / 45045
54
+ + (31627 * c) / 9009,
55
+ },
56
+ 8: {
57
+ "pi_term": 4 * (a - c),
58
+ "log2_term": 8 * b,
59
+ CONSTANT_TERM_KEY: -(188684 * a) / 15015
60
+ - (1332173 * b) / 240240
61
+ + (3849155 * c) / 306306,
62
+ },
63
+ 9: {
64
+ "pi_term": 4 * (a - b - c),
65
+ "log2_term": 8 * (-c + a + b),
66
+ CONSTANT_TERM_KEY: -((17069771 * a) / 942480)
67
+ + (86025349 * b) / 12252240
68
+ + (4216233689 * c) / 232792560,
69
+ },
70
+ 10: {
71
+ "pi_term": -8 * b,
72
+ "log2_term": 16 * (a - c),
73
+ CONSTANT_TERM_KEY: -((1290876029 * a) / 116396280)
74
+ + (325039733 * b) / 12932920
75
+ + (117352369 * c) / 10581480,
76
+ },
77
+ 11: {
78
+ "pi_term": 8 * (-a - b + c),
79
+ "log2_term": 16 * (a - b - c),
80
+ CONSTANT_TERM_KEY: (817240769 * a) / 58198140
81
+ + (4216233641 * b) / 116396280
82
+ - (37593075209 * c) / 2677114440,
83
+ },
84
+ 12: {
85
+ "pi_term": -16 * a + 16 * c,
86
+ "log2_term": -32 * b,
87
+ CONSTANT_TERM_KEY: (431302721 * a) / 8580495
88
+ + (9135430531 * b) / 411863760
89
+ - (5902037233 * c) / 117417300,
90
+ },
91
+ }
92
+
93
+ def get_integrate_args(self, n):
94
+ return x**n * (1 - x) ** n * (a + b * x + c * x**2) / (1 + x**2), (x, 0, 1)
95
+
96
+
97
+ class PiSolution(Solution):
98
+ def __init__(self, p, q):
99
+ self.p = p
100
+ self.q = q
101
+ if self.q == 0:
102
+ raise BadInput()
103
+
104
+ self.get_integrate = PiIntegrate()
105
+ self.symbols = (a, b, c)
106
+ self.integrate_result_classes_eq = {
107
+ "pi_term": q,
108
+ "log2_term": 0,
109
+ CONSTANT_TERM_KEY: -p,
110
+ }
111
+ # check
112
+ self.check_sgn = sq_func_sgn
113
+
114
+ @staticmethod
115
+ def get_tries_args():
116
+ return PiIntegrate.data.keys()
117
+
118
+ def get_latex_ans(self):
119
+ try_arg, symbol_val, sgn = self.try_times()
120
+ print(f"{(try_arg, symbol_val, sgn)=}")
121
+ if try_arg is None:
122
+ return None
123
+
124
+ p = to_latex(self.p)
125
+ q = to_latex(self.q, is_coeff=True)
126
+ I = self.get_integrate.get_latex(try_arg, symbol_val)
127
+ return rf"{q}\pi-{p} = {I} {sign2cmp[sgn]} 0"
128
+
129
+
130
+ register("π", PiSolution, top=True)
131
+
132
+ if __name__ == "__main__":
133
+ while True:
134
+ p = int(input(">>> "))
135
+ q = int(input(" / "))
136
+ print(PiSolution(p, q).get_latex_ans())
solutions/pin.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy import *
2
+ from sympy.abc import a, b, x
3
+ from output_util import to_latex, sign2cmp, to_latexes
4
+ from sgntools import lin_func_sgn
5
+ from solution import *
6
+
7
+ _data = {
8
+ (1, 2): {"constant_term": a - 2 * b / 3, "pin_term": -a / 4 + b / 4},
9
+ (1, 4): {"constant_term": -2 * a / 3 + 13 * b / 15, "pin_term": a / 4 - b / 4},
10
+ (1, 6): {"constant_term": 13 * a / 15 - 76 * b / 105, "pin_term": -a / 4 + b / 4},
11
+ (1, 8): {"constant_term": -76 * a / 105 + 263 * b / 315, "pin_term": a / 4 - b / 4},
12
+ (1, 10): {
13
+ "constant_term": 263 * a / 315 - 2578 * b / 3465,
14
+ "pin_term": -a / 4 + b / 4,
15
+ },
16
+ (1, 12): {
17
+ "constant_term": -2578 * a / 3465 + 36979 * b / 45045,
18
+ "pin_term": a / 4 - b / 4,
19
+ },
20
+ (2, 3): {"constant_term": a / 4 - 3 * b / 16, "pin_term": -a / 48 + b / 48},
21
+ (2, 5): {"constant_term": -3 * a / 16 + 31 * b / 144, "pin_term": a / 48 - b / 48},
22
+ (2, 7): {
23
+ "constant_term": 31 * a / 144 - 115 * b / 576,
24
+ "pin_term": -a / 48 + b / 48,
25
+ },
26
+ (2, 9): {
27
+ "constant_term": -115 * a / 576 + 3019 * b / 14400,
28
+ "pin_term": a / 48 - b / 48,
29
+ },
30
+ (2, 11): {
31
+ "constant_term": 3019 * a / 14400 - 973 * b / 4800,
32
+ "pin_term": -a / 48 + b / 48,
33
+ },
34
+ (2, 13): {
35
+ "constant_term": -973 * a / 4800 + 48877 * b / 235200,
36
+ "pin_term": a / 48 - b / 48,
37
+ },
38
+ (3, 2): {"constant_term": 2 * a - 52 * b / 27, "pin_term": -a / 16 + b / 16},
39
+ (3, 4): {
40
+ "constant_term": -52 * a / 27 + 6554 * b / 3375,
41
+ "pin_term": a / 16 - b / 16,
42
+ },
43
+ (3, 6): {
44
+ "constant_term": 6554 * a / 3375 - 2241272 * b / 1157625,
45
+ "pin_term": -a / 16 + b / 16,
46
+ },
47
+ (3, 8): {
48
+ "constant_term": -2241272 * a / 1157625 + 60600094 * b / 31255875,
49
+ "pin_term": a / 16 - b / 16,
50
+ },
51
+ (3, 10): {
52
+ "constant_term": 60600094 * a / 31255875 - 80596213364 * b / 41601569625,
53
+ "pin_term": -a / 16 + b / 16,
54
+ },
55
+ (3, 12): {
56
+ "constant_term": -80596213364 * a / 41601569625
57
+ + 177153083899958 * b / 91398648466125,
58
+ "pin_term": a / 16 - b / 16,
59
+ },
60
+ (4, 3): {
61
+ "constant_term": 3 * a / 8 - 45 * b / 128,
62
+ "pin_term": -7 * a / 1920 + 7 * b / 1920,
63
+ },
64
+ (4, 5): {
65
+ "constant_term": -45 * a / 128 + 1231 * b / 3456,
66
+ "pin_term": 7 * a / 1920 - 7 * b / 1920,
67
+ },
68
+ (4, 7): {
69
+ "constant_term": 1231 * a / 3456 - 19615 * b / 55296,
70
+ "pin_term": -7 * a / 1920 + 7 * b / 1920,
71
+ },
72
+ (4, 9): {
73
+ "constant_term": -19615 * a / 55296 + 12280111 * b / 34560000,
74
+ "pin_term": 7 * a / 1920 - 7 * b / 1920,
75
+ },
76
+ (4, 11): {
77
+ "constant_term": 12280111 * a / 34560000 - 4090037 * b / 11520000,
78
+ "pin_term": -7 * a / 1920 + 7 * b / 1920,
79
+ },
80
+ (4, 13): {
81
+ "constant_term": -4090037 * a / 11520000 + 9824498837 * b / 27659520000,
82
+ "pin_term": 7 * a / 1920 - 7 * b / 1920,
83
+ },
84
+ (5, 2): {
85
+ "constant_term": 24 * a - 1936 * b / 81,
86
+ "pin_term": -5 * a / 64 + 5 * b / 64,
87
+ },
88
+ (5, 4): {
89
+ "constant_term": -1936 * a / 81 + 6051944 * b / 253125,
90
+ "pin_term": 5 * a / 64 - 5 * b / 64,
91
+ },
92
+ (5, 6): {
93
+ "constant_term": 6051944 * a / 253125 - 101708947808 * b / 4254271875,
94
+ "pin_term": -5 * a / 64 + 5 * b / 64,
95
+ },
96
+ (5, 8): {
97
+ "constant_term": -101708947808 * a / 4254271875
98
+ + 24715694492344 * b / 1033788065625,
99
+ "pin_term": 5 * a / 64 - 5 * b / 64,
100
+ },
101
+ (5, 10): {
102
+ "constant_term": 24715694492344 * a / 1033788065625
103
+ - 3980462502772918544 * b / 166492601756971875,
104
+ "pin_term": -5 * a / 64 + 5 * b / 64,
105
+ },
106
+ (5, 12): {
107
+ "constant_term": -3980462502772918544 * a / 166492601756971875
108
+ + 1477921859864507412282392 * b / 61817537584151358384375,
109
+ "pin_term": 5 * a / 64 - 5 * b / 64,
110
+ },
111
+ (6, 3): {
112
+ "constant_term": 15 * a / 8 - 945 * b / 512,
113
+ "pin_term": -31 * a / 16128 + 31 * b / 16128,
114
+ },
115
+ (6, 5): {
116
+ "constant_term": -945 * a / 512 + 229955 * b / 124416,
117
+ "pin_term": 31 * a / 16128 - 31 * b / 16128,
118
+ },
119
+ (6, 7): {
120
+ "constant_term": 229955 * a / 124416 - 14713475 * b / 7962624,
121
+ "pin_term": -31 * a / 16128 + 31 * b / 16128,
122
+ },
123
+ (6, 9): {
124
+ "constant_term": -14713475 * a / 7962624 + 45982595359 * b / 24883200000,
125
+ "pin_term": 31 * a / 16128 - 31 * b / 16128,
126
+ },
127
+ (6, 11): {
128
+ "constant_term": 45982595359 * a / 24883200000 - 5109066151 * b / 2764800000,
129
+ "pin_term": -31 * a / 16128 + 31 * b / 16128,
130
+ },
131
+ (6, 13): {
132
+ "constant_term": -5109066151 * a / 2764800000
133
+ + 601081707598999 * b / 325275955200000,
134
+ "pin_term": 31 * a / 16128 - 31 * b / 16128,
135
+ },
136
+ }
137
+
138
+
139
+ class PiNIntegrate(GetIntegrateFromData):
140
+ data = _data
141
+
142
+ def get_integrate_args(self, args):
143
+ n, m = args
144
+ return x**m * (a + b * x**2) * (log(1 / x)) ** (n - 1) / (1 + x**2), (x, 0, 1)
145
+
146
+
147
+ class PiNSolution(Solution):
148
+ def __init__(self, n, p, q):
149
+ if n < 0:
150
+ n = -n
151
+ p, q = q, p
152
+ self.n = n
153
+ self.p = p
154
+ self.q = q
155
+ if self.q == 0:
156
+ raise BadInput()
157
+
158
+ self.get_integrate = PiNIntegrate()
159
+ self.symbols = (a, b)
160
+ self.integrate_result_classes_eq = {
161
+ "pin_term": q,
162
+ CONSTANT_TERM_KEY: -p,
163
+ }
164
+ # check
165
+ self.check_sgn = lin_func_sgn
166
+
167
+ def get_tries_args(self):
168
+ for n, m in PiNIntegrate.data.keys():
169
+ if n == self.n:
170
+ yield n, m
171
+
172
+ def get_latex_ans(self):
173
+ try_arg, symbol_val, sgn = self.try_times()
174
+ print(f"{(try_arg, symbol_val, sgn)=}")
175
+ if try_arg is None:
176
+ return None
177
+
178
+ p, n = to_latexes(self.p, self.n)
179
+ q = to_latex(self.q, is_coeff=True)
180
+ I = self.get_integrate.get_latex(try_arg, symbol_val)
181
+ return rf"{q}\pi^{n}-{p} = {I} {sign2cmp[sgn]} 0"
182
+
183
+
184
+ register("π^n", PiNSolution)
185
+
186
+
187
+ if __name__ == "__main__":
188
+ print(PiNSolution(3, 31, 1).get_latex_ans())