エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

半群の右単位元と左単位元(4)

ChatGPTで単純に日本語で指摘すると、ChatGPTは単に日本語を生成するだけなのでうまくいかない、というようなことが何かの本に書かれていたような気がします。そこで、何かChatGPTが知っていることをやると良いのかと思われるのでやってみたいと思います。しかしそれが何なのかはわかりません。

ここではプログラムの仕様を書いてもらいます。以下のように入力しました。

半群の等式を構文解析できるようにします。半群演算子は「*」、等号は「=」とします。半群の基本的要素は文字列とします。文字列の先頭の文字が大文字のとき変数、それ以外は定数であるとします。二つの等式を入力します。(等式Aと等式Bとします)等式Aと等式Bに同じ名前の変数が含まれていても、それらの変数は別の変数であるとします。等式Aの左辺または右辺のどちらかの式と、等式Bの左辺または右辺のどちらかの式が一致するかどうかを調べます。例として、「e_l * X = X」(等式A)と「X * e_r = X」(等式B)という二つの等式が入力されたとします。等式Aの左辺と等式Bの左辺、等式Aの左辺と等式Bの右辺、等式Aの右辺と等式Bの左辺、等式Aの右辺と等式Bの右辺、について、二つの式が一致するかどうかを調べます。もしどれも一致しなかったときはそのように答えを返します。この例では等式Aの左辺と等式Bの左辺の場合だけを書きます。「e_l * X = X」(等式A)と「X * e_r = X」(等式B)の変数Xは別の変数なので、等式Bは「Y * e_r = Y」と書き直します。変数Xをe_rで置き換えて(X:=e_rと書きます)変数Yをe_lで置き換ると(Y:=e_lと書きます)両方の式は「e_l * e_r」となって一致します。この方法は単一化(unification)のアルゴリズムで、最小の置き換えを求めます。等式Aの逆側の式(右辺)はXですが、X:=e_rで置き換えるとe_rとなります。等式Bの逆側の式(右辺)はXですが、これはYに変更されていて、Y:=e_lで置き換えるとe_lとなります。よって逆側の式同士を組み合わせた等式はe_l=e_rとなります。どれかの二つの式が一致したときはこの式を返します。このようなプログラムを C# で書こうとしています。このプログラムの仕様を書いてください

以下は引用です。

プログラムの仕様を以下にまとめます。

仕様:
  1. 入力:
    • ユーザーには二つの等式が入力されます。
    • 等式は文字列として表現されます。
    • 演算子半群演算子である「*」を使用します。
    • 等号は「=」とします。
  2. 等式の構文:
    • 等式は左辺と右辺に分かれます。
    • 左辺または右辺のどちらかが変数であれば、もう一方は定数です。
    • 変数は文字列の先頭の文字が大文字です。
    • 定数はそれ以外の文字列です。
  3. 等式の一致のチェック:
    • 与えられた二つの等式に同じ名前の変数が含まれていても、それらの変数は別の変数として扱います。
    • 二つの等式の左辺と右辺の組み合わせについて、一致するものがあるかどうかを調べます。
    • 一致する場合、その組み合わせを返します。一致しない場合は空の結果を返します。
  4. 単一化(unification):
    • 一致した組み合わせが見つかった場合、それを元に等式の逆側の式同士を組み合わせて新しい等式を生成します。
    • このとき、変数同士の対応関係を記録し、最小の置換を求めます。
  5. 出力:
    • 一致した組み合わせが見つかった場合、逆側の式同士を組み合わせた新しい等式を出力します。
    • 一致する組み合わせが見つからなかった場合は、空の結果を出力します。

これらの仕様に従って、二つの等式を構文解析し、一致する組み合わせがあれば逆側の式同士を組み合わせて新しい等式を生成するC#プログラムを作成します。

次に以下のように入力しました。

このプログラムを C# で書いてください

以下は引用です。

理解しました。以下に、指定された仕様に従って、等式を構文解析し、一致する組み合わせがあれば新しい等式を生成するC#プログラムを示します。

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        // 二つの等式を入力
        string equation1 = "e_l * X = X";
        string equation2 = "X * e_r = X";

        // 等式の一致を調べ、新しい等式を生成
        string result = UnifyEquations(equation1, equation2);

        // 結果を出力
        Console.WriteLine("Result: " + result);
    }

    // 等式の一致を調べ、新しい等式を生成するメソッド
    static string UnifyEquations(string equation1, string equation2)
    {
        // トークンに分割
        string[] tokens1 = equation1.Split();
        string[] tokens2 = equation2.Split();

        // 等式の一致をチェックし、一致した場合に新しい等式を生成
        foreach (var side1 in new[] { GetLeftSide(tokens1), GetRightSide(tokens1) })
        {
            foreach (var side2 in new[] { GetLeftSide(tokens2), GetRightSide(tokens2) })
            {
                var substitutions = UnifySides(side1, side2);
                if (substitutions != null)
                {
                    // 一致した変数の置換を適用して新しい等式を生成
                    var newEquation = ApplySubstitutions(equation1, equation2, substitutions);
                    return newEquation;
                }
            }
        }

        // 一致する組み合わせがない場合は空の結果を返す
        return "";
    }

    // 等式の片側の式を取得するメソッド
    static string GetLeftSide(string[] tokens)
    {
        return tokens[2]; // "="の左側が3番目の要素
    }

    static string GetRightSide(string[] tokens)
    {
        return tokens[0]; // "="の右側が1番目の要素
    }

    // 等式の一致をチェックし、変数の置換を求めるメソッド
    static Dictionary<string, string> UnifySides(string side1, string side2)
    {
        // 変数が一致するかどうかをチェックし、一致した場合は変数の置換を求める
        if (char.IsUpper(side1[0]) && char.IsUpper(side2[0]) && side1 != side2)
        {
            // 変数同士の置換を記録して返す
            var substitutions = new Dictionary<string, string>();
            substitutions[side1] = side2;
            return substitutions;
        }

        // 一致しない場合はnullを返す
        return null;
    }

    // 等式に変数の置換を適用して新しい等式を生成するメソッド
    static string ApplySubstitutions(string equation1, string equation2, Dictionary<string, string> substitutions)
    {
        // 等式を置換して新しい等式を生成
        string newEquation1 = ApplySubstitutionsToEquation(equation1, substitutions);
        string newEquation2 = ApplySubstitutionsToEquation(equation2, substitutions);

        // 置換した等式同士を組み合わせて新しい等式を生成
        string newEquation = $"{newEquation1} = {newEquation2}";
        return newEquation;
    }

    // 等式に変数の置換を適用するメソッド
    static string ApplySubstitutionsToEquation(string equation, Dictionary<string, string> substitutions)
    {
        // 置換を適用して新しい等式を生成
        foreach (var substitution in substitutions)
        {
            equation = equation.Replace(substitution.Key, substitution.Value);
        }
        return equation;
    }
}

このプログラムは、与えられた二つの等式を構文解析し、一致する組み合わせがあれば新しい等式を生成します。等式の一致をチェックするために、単一化(unification)アルゴリズムを使用しています。そして、一致した組み合わせが見つかった場合は、等式の逆側の式同士を組み合わせて新しい等式を生成します。

できていません。しかしこうしておくと、仕様について指摘することができるようになったかもしれません。どう指摘するか検討してみたいと思います。