質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.02%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

LaTeX

LaTeXは、レスリー・ランポートが開発したテキストベースの文書整形システムです。 電子製版ソフトウェアである「TeX」にマクロパッケージを組み込む形で構成されており、 通常のTeXより扱いやすくなっているのが特徴です。

Q&A

解決済

数式の文字列をLATEXの数式コマンドに変換するプログラム

AI_engineer
AI_engineer

総合スコア14

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

LaTeX

LaTeXは、レスリー・ランポートが開発したテキストベースの文書整形システムです。 電子製版ソフトウェアである「TeX」にマクロパッケージを組み込む形で構成されており、 通常のTeXより扱いやすくなっているのが特徴です。

1回答

0グッド

1クリップ

627閲覧

投稿2022/10/17 03:24

編集2022/10/17 04:45

前提

数式の文字列をLATEXの数式モードで表示したいです。(こちらのページを参考)
プログラム自体はエラーなく通るものの、LATEXで数式を表示しようとするとエラーが出るので、正しく動作していないと思います。

実現したいこと

数式の文字列をLATEXの数式モードで出力するよう変換するプログラムの修正をしたい。

発生している問題・エラーメッセージ

以下、LATEXによるエラーメッセージです。

Missing } inserted. ...{e}}}{log(x)}}{+(-1)}\frac0.1\frac\frac{e} Ambiguous; you need another { and }. ...{e}}}{log(x)}}{+(-1)}\frac0.1\frac\frac{e} Extra }, or forgotten $. ...{e}}}{log(x)}}{+(-1)}\frac0.1\frac\frac{e} etc...

この3行のエラーが立て続けに出ています。

該当のソースコード

Python

1各リストの要素がもつ引数の値を返す関数.例えばaddならadd(1,x)=1+xを表し,引数は1とxの2つとなる. 2def getArity(name): 3 if name in ["x","-1","0","1","0.5","0.1","pi","e"]: 4 return 0 5 elif name in ["sin","cos","tan","log","exp","sqrt"]: 6 return 1 7 elif name in ["add","sub","mul","div"]: # 四則演算記号 8 return 2 9 else: 10 print("bug : not define ",name) 11 exit() 12 13# 演算記号とそれがもつ引数の数をタプルで返す。(例)('div', 2)、('sqrt', 1) 14def addArityInfo(array): 15 new_array = [(name,getArity(name)) for name in array] 16 return new_array 17 18# TeXの数式記述形式に変換する関数 19def transformTexForm(array): 20 def getEnd(start,array): 21 _sum = 1 22 for i in range(start,len(array)): 23 arity = array[i][1] 24 _sum += arity -1 25 if _sum == 0: 26 return i+1 27 mid_end_indexs = [] 28 loopflg = True 29 while loopflg: 30 loopflg = False 31 for i in range(len(array)): 32 name,arity = array[i] 33 if arity == 2: 34 loopflg = True 35 end = getEnd(i,array) 36 mid = getEnd(i+1,array) 37 if name == "add": 38 array.insert(mid,("+",1)) 39 del array[i] 40 if name == "sub": 41 array.insert(mid,("-",1)) 42 del array[i] 43 if name == "mul": 44 array.insert(mid,(" ",1)) 45 del array[i] 46 if name == "div": 47 array[i] = ("frac",1) 48 break 49 for i in range(len(array)): 50 if array[i][0] == "frac": 51 array[i] = ("\\frac",2) 52 if array[i][0] == "pi": 53 array[i] = ("\\pi",0) 54 str_arr = [""] 55 for node in array: 56 name,arity = node 57 for i in range(len(str_arr)): 58 if str_arr[i] == "": 59 if arity == 0: 60 str_arr = str_arr[:i] + [name] + str_arr[i+1:] 61 if arity == 1: 62 if name == "sqrt": 63 name = "\\"+name 64 str_arr = str_arr[:i] + [name,"{","","}"]+ str_arr[i+1:] 65 else: 66 str_arr = str_arr[:i] + [name,"(","",")"]+ str_arr[i+1:] 67 if arity == 2: 68 temp = [name,"{","","}{","","}"] 69 str_arr = str_arr[:i] + temp+ str_arr[i+1:] 70 break 71 if "" not in str_arr: 72 str_arr.append(name) 73 str_arr.append("") 74 return "".join(str_arr) 75 76# string: 変換する数式 77string = "div(cos(mul(0.5,0.1)),cos(add(cos(add(sin(e),div(div(div(div(e,x),div(0.1,e)),log(add(x,-1))),div(0.1,div(div(e,x),div(0.1,e)))))),mul(div(div(div(0.1,div(div(e,x),div(0.1,e))),div(div(e,add(x,-1)),div(0.1,e))),div(div(div(div(e,x),div(0.1,e)),x),div(0.1,div(div(e,x),div(0.1,e))))),div(div(0.1,div(div(e,x),div(0.1,e))),div(div(div(div(e,x),div(0.1,e)),log(add(x,-1))),div(0.1,div(div(e,x),div(0.1,e)))))))))" 78array = [] 79s = "" 80for c in string: 81 if c in "(),": 82 if s != "": 83 array.append(s) 84 s = "" 85 else: 86 s+=c 87array = addArityInfo(array) 88print(transformTexForm(array))

ソースコードの出力

\frac{cos(0.5)}{ (0.1)}coscos(sin(e))+\frac{\frac{\frac{\frac{e}{x}}{\frac{0.1}{e}}}{log(x)}}{+(-1)}\frac0.1\frac\frac{e}{x}\frac0.1e+(\frac{\frac{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}{\frac{\frac{e}{x}}{+(-1)}}}{\frac{0.1}{e}})\frac\frac{\frac{\frac{e}{x}}{\frac{0.1}{e}}}{x}\frac0.1\frac\frac{e}{x}\frac0.1e (\frac{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}{\frac{\frac{\frac{\frac{e}{x}}{\frac{0.1}{e}}}{log(x)}}{+(-1)}})\frac0.1\frac\frac{e}{x}\frac0.1e

試したこと

LATEXのエラーより、LATEXの数式コードに変換する際、{}が正しく出力されていない気がしています。
またソースコードの出力を見ると、cosのあとに()がなかったり、mulの書き換えがうまくできていないように思います。
LATEXでの掛け算記号は\timesとあったので、array.insert(mid,("times", 1))、if array[i][0] == 'times';

python

1array.insert(mid,("times", 1)) 2 3if array[i][0] == 'times'; 4array[i] = ('\\times)

とdivと同様に処理を書き換えたがうまくいかなかった。

簡単な数式で試した場合、
(例)cos(0.5*0.1) / cos(1+x)をLATEXで表示できるように変換したい。

string = "div(cos(mul(0.5,0.1)),cos(add(1,x)))"

として、変換を行うと、

\frac{cos(0.5)}{ (0.1)}cos1+x

と出力されます。\frac{cos(0.5*0.1)}{cos(1+x)}が正しい出力だと思います。
三角関数、根号、指数・対数関数の()内の処理が誤っているようです。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

can110

2022/10/17 04:17

提示されたコードのデバッグ(おかしなところを見つけて修正)をしてほしいという類の質問でしょうか? - 変換元の数式文字列についての文法、変換ルール、コードの説明 - 単純な数式について、うまくいく例といかない例 などを記載すると回答得られやすくなると思います。
AI_engineer

2022/10/17 04:47

ご回答ありがとうございます。 コードのデバッグをしていただきたいです。 頂いたアドバイス通り今の自分が可能な限りの情報を追加いたしました。 コードの説明についてもう少し詳しく書いた方がよいと思いますが、コードの理解がうまく進みませんでした。申し訳ありません。
bsdfan

2022/10/17 11:24

arrayに対してループしながら、arrayにinsertしているのが、問題起こしそうです。

回答1

0

ベストアンサー

パッと見た感じ,array.insert()周りがおかしいと感じますが,私には難解なのでデバッグの回答は他の人に譲ります.

とりあえず再帰で書き直してみました.

基本方針は,文字列がoperator(expression)という形式であることを利用して,演算子operatorと括弧の中身expressionを抜き出して,関数再帰によりexpressionをまたoperator(expression)の形式として評価する.といった具合です.括弧がなかった場合,値のみなので再帰終了になります.

具体的には,演算子operatorと括弧の中身expressionの抜き出しをsplit_op_ex(x)で行い,arityによってコンマ区切りの有無の判定を利用した再帰になっています.arity = 2であればコンマ区切りされているoperator(expression1,expression2)状態なので,コンマの位置を関数split_comma(x)にて特定&分割,それぞれのexpressionを再帰により評価します.

再帰関数自体8行しかなく,そんなに変なことをしているつもりはないのですが,わからないことあれば教えてください.

Python

1def split_op_ex(x): # operator(expression)の形式のときoperatorとexpressionを返す 2 start, cnt = x.find('('), 1 3 assert start != -1, f"not found '(', maybe '{x}' is single value" 4 for i, ch in enumerate(x[start + 1:]): 5 if ch == '(': 6 cnt += 1 7 elif ch == ')': 8 cnt -= 1 9 if not cnt: 10 return x[:start], x[start + 1: start + i + 1] # operator, expression 11 assert False, f"not found ')', incorrect bracket error on '{x}'" 12 13def split_comma(x): # expressionを分割しているコンマを探索&分割 14 cnt = 0 15 for i, ch in enumerate(x): 16 if ch == '(': 17 cnt += 1 18 elif ch == ')': 19 cnt -= 1 20 if ch == ',' and not cnt: 21 return x[:i], x[i + 1:] # expression1, expression2 22 assert False, f"not found outer comma, incorrect bracket or comma style on '{x}'" 23 24def getArity(op): 25 if op in ["sin","cos","tan","log","exp","sqrt"]: 26 return 1 27 if op in ["add","sub","mul","div"]: # 四則演算記号 28 return 2 29 assert False, f"not defined operator '{op}'" 30 31def latexify(op, ex, parent_op): 32 if op == None: 33 if ex == "pi": 34 return "\\pi" 35 return ex 36 if op == "sqrt": 37 return "\\sqrt{" + ex + "}" 38 if getArity(op) == 1: 39 return f"\\{op}\\left({ex}\\right)" 40 pm = {"add": "+", "sub": "-"} 41 if op in pm.keys(): 42 if parent_op == "mul" or parent_op == "sub": # requirement priority bracket 43 return f"\\left({ex[0]} {pm[op]} {ex[1]}\\right)" 44 else: 45 return f"{ex[0]} {pm[op]} {ex[1]}" 46 if op == "mul": 47 return f"{ex[0]} \\times {ex[1]}" 48 if op == "div": 49 return "\\frac{" + ex[0] + "}{" + ex[1] + "}" 50 51 assert False, f"not defined latexify operator '{op}'" 52 53def dfs(S, parent_op = None): # recursion function 54 if not S.count('('): # only value 55 return latexify(None, S, parent_op) 56 op, ex = split_op_ex(S) # operator(expression) -> operator, expression 57 arity = getArity(op) 58 if arity == 1: 59 return latexify(op, dfs(ex, op), parent_op) 60 if arity == 2: 61 return latexify(op, list(map(lambda x: dfs(x, op), split_comma(ex))), parent_op) 62 63def translate(S): 64 return dfs(S).replace("+ -", "- ").replace("- -", "+ ") 65 66string = "div(cos(mul(0.5,0.1)),cos(add(cos(add(sin(e),div(div(div(div(e,x),div(0.1,e)),log(add(x,-1))),div(0.1,div(div(e,x),div(0.1,e)))))),mul(div(div(div(0.1,div(div(e,x),div(0.1,e))),div(div(e,add(x,-1)),div(0.1,e))),div(div(div(div(e,x),div(0.1,e)),x),div(0.1,div(div(e,x),div(0.1,e))))),div(div(0.1,div(div(e,x),div(0.1,e))),div(div(div(div(e,x),div(0.1,e)),log(add(x,-1))),div(0.1,div(div(e,x),div(0.1,e)))))))))" 67print(translate(string)) 68print(translate("div(cos(mul(0.5,0.1)),cos(add(1,x)))"))

add(x,-1)のときにx + -1になるので,.replace("+ -", "- ")しています.今回入力にsub(x,-1)は無いですが今後のため.replace("- -", "+ ")を付加しています.

shell:標準出力

1\frac{\cos\left(0.5 \times 0.1\right)}{\cos\left(\cos\left(\sin\left(e\right) + \frac{\frac{\frac{\frac{e}{x}}{\frac{0.1}{e}}}{\log\left(x - 1\right)}}{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}\right) + \frac{\frac{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}{\frac{\frac{e}{x - 1}}{\frac{0.1}{e}}}}{\frac{\frac{\frac{\frac{e}{x}}{\frac{0.1}{e}}}{x}}{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}} \times \frac{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}{\frac{\frac{\frac{\frac{e}{x}}{\frac{0.1}{e}}}{\log\left(x - 1\right)}}{\frac{0.1}{\frac{\frac{e}{x}}{\frac{0.1}{e}}}}}\right)} 2\frac{\cos\left(0.5 \times 0.1\right)}{\cos\left(1 + x\right)}

また,latexify時に括弧に付けた\left\rightですが,これは式のサイズに括弧のサイズを合わせるようなオプションです.付けなくても動きますが見づらいと思い,追加しておきました.さらに,関数表記において三角関数や対数関数,指数関数などは斜体ではなく立体で書く必要があるので\sinのようにしました.TeXに用意されている初等関数は大抵\をつけるだけで立体になります(そのぐらい立体にするのが当たり前です).

また,掛け算は\timesでなく\cdotでも良いと思います.ベクトルの場合に外積と内積で意味が異なりますので覚えておくと良いでしょう.さらに掛け算に,積より優先順位の低い演算である和と差が並んだ場合やsub(x,sub(y,z))を考慮して,parent_opmulorsubであった場合の和と差には括弧を付与するようにしています(今回は存在しませんが念の為).

もうちょっとparent_opに対する制御を書けばadd(x,-1)のようなケースもsub(x,1)であるかのように対応できますが,わかりづらくなると思うのでreplace()で対応しています.

latexit

投稿2022/10/17 10:18

編集2022/10/18 04:12
PondVillege

総合スコア1043

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

AI_engineer

2022/10/18 04:21

非常に詳しいご回答ありがとうございます。 コードを読むことに不慣れなため少し時間がかかるかもしれませんが、確認してみます。 わからない箇所が出てきましたら再度コメントにて補足させていただきます。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.02%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

LaTeX

LaTeXは、レスリー・ランポートが開発したテキストベースの文書整形システムです。 電子製版ソフトウェアである「TeX」にマクロパッケージを組み込む形で構成されており、 通常のTeXより扱いやすくなっているのが特徴です。