数式微分器の作成 (2) 式木の最適化

前回の記事の続きです。

数式微分器の作成 と D言語での木走査 - 茅の下

前回の内容

前回の記事で数式微分器を作成したが、出力が繁雑になった。

結論

今回はそれを解消するために式木に対してより強力な最適化を掛けるようにした結果、出力がこましになった。

前回の反省

前回、出力が繁雑になった原因は主に次の2つです。

  1. 割り算ノードを用意しなかった。

    前回は必要な式木の型数を小さくするために、割り算に相当するノード型を用意しませんでした。

    そのため、{ f / g } f \times g^{-1} のように表現する必要があり、これが出力の式木のノード数が増える原因になっていました。

    今回は割り算ノードを用意しました。

  2. 式木に対する最適化が甘かった。

    前回式木に対して施していた最適化は以下の3項目のみでした。

    1. 加算両辺の 0 の削除。

       0 + b → b

       a + 0 → a

    2. 乗算両辺の 1 の削除。

       1 \times b → b

       a \times 1 → a

    3. 0 を含む乗算の削除。

       0 \times b → 0

       a \times 0 → 0

    今回はこれらに加えて式木に対して様々な最適化を行いました。

GitHub - Ryooooooga/Calculator

結果

では前回と同様、 1 / tan(x) (= cos(x) \times sin(x)^{-1})微分してみます。

以下が前回の出力結果です。

((((-1)*sin(x))*sin(x)^{(-1)})+(cos(x)*(sin(x)^{(-1)}*((cos(x)*(-1))*sin(x)^{(-1)}))))

以下が今回の最適化を施したあとの出力です。

(-1-((cos(x)^2)/(sin(x)^2)))

依然として括弧だらけですが、全体的にこざっぱりしました。

なお、二階微分すると爆発します。

-(-(((((((cos(x)^2)*(2*sin(x)))*(sin(x)^2))/cos(x))+(((cos(x)^2)*((sin(x)^2)*(2*cos(x))))/sin(x)))/((sin(x)^2)^2))))