交換子の計算(2)
「マグマの左単位元と右単位元」の問題の構文解析を ChatGPT でやってみようと入力したところ、「Lark ライブラリ」を使ったプログラムが返ってきました。そこでいったんこのプログラムを自分で改造して交換子の計算の構文解析をやってみることにしました。
class GroupExp: def __init__(self, exp, struct_exp = None): if exp == "e": self.exp = "" else: self.exp = exp if struct_exp is not None: self.struct_exp = struct_exp else: if exp == "": self.struct_exp = ("const", "e") else: self.struct_exp = ("const", exp) def __add__(self, other): # 積 if isinstance(other, GroupExp): result_str = self.remove_opposite_case_pairs(self.exp + other.exp) return GroupExp(result_str, self.prod_struct(other)) raise TypeError("Operand must be a GroupExp") def __sub__(self, other): # 逆元との積 if isinstance(other, GroupExp): return self + - other raise TypeError("Operand must be a GroupExp") def __neg__(self): # 逆元 result_str = self.reverse_and_swapcase(self.exp) return GroupExp(result_str, self.inv_struct()) def __mul__(self, other): # 交換子 if isinstance(other, GroupExp): return (- self - other + self + other).replace_struct(self.com_struct(other)) raise TypeError("Operand must be a GroupExp") def __pow__(self, other): # 共役 if isinstance(other, GroupExp): return (- other + self + other).replace_struct(self.conj_struct(other)) raise TypeError("Operand must be a GroupExp") def prod_struct(self, other): # 積の構造 return ("prod", self.struct_exp, other.struct_exp) def inv_struct(self): # 逆元の構造 return ("inv", self.struct_exp) def com_struct(self, other): # 交換子の構造 return ("com", self.struct_exp, other.struct_exp) def conj_struct(self, other): # 共役の構造 return ("conj", self.struct_exp, other.struct_exp) def replace_struct(self, struct_exp): # 構造を置き換える return GroupExp(self.exp, struct_exp) def __str__(self): return self.exp def __repr__(self): return f"GroupExp({self.exp})" def reverse_and_swapcase(self, text): # 文字列を逆順にする reversed_text = text[::-1] # 大文字と小文字を入れ替える swapped_text = reversed_text.swapcase() return swapped_text def remove_opposite_case_pairs(self, text): # 文字列の中で大文字とその文字の小文字、または小文字とその文字の大文字が # 連続しているペアを削除します。 i = 0 while i < len(text) - 1: # 現在の文字と次の文字を比較 current = text[i] next_char = text[i + 1] # 大文字と小文字の組み合わせ、またはその逆を検出 if (current.lower() == next_char.lower() and current.islower() != next_char.islower()): # このペアを削除するために、前と次を繋げてスライス text = text[:i] + text[i + 2:] # 削除されたので、再度この位置からチェック i = max(0, i - 1) else: # 削除がない場合は、次に進む i += 1 return text class GroupEquation: def __init__(self, left, right): self.left = left self.right = right def __str__(self): return str(self.left) + " = " + str(self.right) def __repr__(self): return f"GroupEquation({self.left} = {self.right})" def equal(self): return str(self.left) == str(self.right) def tex_print(s): if len(s) == 2: struct_type, x = s if struct_type == "const": return x elif struct_type == "inv": return tex_print(x) + "^{-1}" if len(s) == 3: struct_type, x, y = s if struct_type == "prod": return tex_print(x) + tex_print(y) elif struct_type == "com": return "[" + tex_print(x) + ", " + tex_print(y) + "]" elif struct_type == "conj": return tex_print(x) + "^{" + tex_print(y) + "}" def etex_print(eq): return tex_print(eq.left.struct_exp) + " = " + tex_print(eq.right.struct_exp) def equation_print(src): print("src: ", src) tree = parser.parse(src) eq = custom_transformer.transform(tree) print(eq) if (eq.equal()): print("一致しました") print(etex_print(eq)) else: print("違います") from lark import Transformer, v_args @v_args(inline=True) # 引数をリストではなく個別の要素として受け取る class CustomTransformer(Transformer): def equation(self, left, right): return GroupEquation(left, right) # 等式 def multiplication(self, left, right): return left + right # 積 def conjugate_trans(self, left, right): return left ** right # 共役 def commutator(self, left, right): return left * right # 交換子 def inverse_trans(self, exp): return - exp # 逆元 def expression(self, item): return item def conjugate(self, item): return item def inverse(self, item): return item def term(self, item): return item def atom(self, item): return item def VARIABLE(self, name): return GroupExp(str(name)) # Variable オブジェクトとして返す def CONSTANT(self, name): return GroupExp(str(name)) # Constant オブジェクトとして返す # グラマー定義 grammar = """ ?start: equation equation: expression "=" expression expression: conjugate | expression "*" conjugate -> multiplication # 積 conjugate: inverse | inverse "^" inverse -> conjugate_trans # 共役 inverse: term | inverse "~" -> inverse_trans # 逆元 term: atom | "(" expression ")" # 括弧を使った演算 | "[" expression "," expression "]" -> commutator # 交換子 atom: VARIABLE | CONSTANT # 変数と定数 VARIABLE: /[A-Z][a-zA-Z_]*/ # 大文字で始まる変数 CONSTANT: /[a-z][a-zA-Z_]*/ # 小文字で始まる定数 %ignore " " # 空白を無視 """ # 構文解析 from lark import Lark parser = Lark(grammar, parser="lalr") custom_transformer = CustomTransformer() # x^y = x[x, y] equation_print("x^y = x*[x, y]") # [y, x] = [x, y]^-1 equation_print("[y, x] = [x, y]~") # [xy,z] = [x,z]^y[y,z] equation_print("[x*y,z] = [x,z]^y*[y,z]") # [x,yz] = [x,z][x,y]^z equation_print("[x,y*z] = [x,z]*[x,y]^z") # [x,y^−1] = [y,x]^y^−1 equation_print("[x,y~] = [y,x]^y~") # [x^−1,y] = [y,x]^x^−1 equation_print("[x~,y] = [y,x]^x~") # [[x,y^−1],z]^y[[y,z^−1],x]^z[[z,x^−1],y]^x = e equation_print("[[x,y~],z]^y*[[y,z~],x]^z*[[z,x~],y]^x = e") # [[x,y],z^x][[z,x],y^z][[y,z],x^y] = e equation_print("[[x,y],z^x]*[[z,x],y^z]*[[y,z],x^y] = e") # [x,y]^z = [x^z, y^z] equation_print("[x,y]^z = [x^z, y^z]")
結果
src: x^y = x*[x, y]
Yxy = Yxy
一致しました
src: [y, x] = [x, y]~
YXyx = YXyx
一致しました
src: [x*y,z] = [x,z]^y*[y,z]
YXZxyz = YXZxyz
一致しました
src: [x,y*z] = [x,z]*[x,y]^z
XZYxyz = XZYxyz
一致しました
src: [x,y~] = [y,x]^y~
XyxY = XyxY
一致しました
src: [x~,y] = [y,x]^x~
xYXy = xYXy
一致しました
src: [[x,y~],z]^y*[[y,z~],x]^z*[[z,x~],y]^x = e
=
一致しました
src: [[x,y],z^x]*[[z,x],y^z]*[[y,z],x^y] = e
=
一致しました
src: [x,y]^z = [x^z, y^z]
ZXYxyz = ZXYxyz
一致しました