蒼い夏の空のライブラリー

ブログ名は適当に考えました  このブログの記事のすべてはCC0、パブリックドメインです

書くことがなさすぎるので、自作ライブラリの紹介をします

初めに

このブログは作ってみたものの、特に書くこともなく放置していました() なので、いつか書こうと思っていた自作ユーティリティーのドキュメントなどを書こうと思います。

nyaruga::util::diff

今回は、関数を微分する関数を紹介します。nyaruga::util::diff です。

nyaruga_util/diff.hpp at master · alphya/nyaruga_util · GitHub

using num_t =
   boost::multiprecision::number<boost::multiprecision::cpp_dec_float<1000>>;

// 微分します
// 7 点近似です
template <typename Number = num_t, typename F>
constexpr auto diff(F && f) noexcept
{
   return [f](auto && x) noexcept(noexcept(f(x))) -> Number {
      auto h = 1e-7;
      if constexpr (std::is_same_v<Number, num_t>)
         h = DBL_EPSILON;

      auto&& y1 = f(static_cast<Number>(x + h));
      auto&& y2 = f(static_cast<Number>(x - h));
      auto&& y3 = f(static_cast<Number>(x + 2 * h));
      auto&& y4 = f(static_cast<Number>(x - 2 * h));
      auto&& y5 = f(static_cast<Number>(x + 3 * h));
      auto&& y6 = f(static_cast<Number>(x - 3 * h));

      return (y5 - 9 * y3 + 45 * y1 - 45 * y2 + 9 * y4 - y6) /
                           (60 * h);
   };
}

上記の関数は、一引数の関数を引数にとって、「点xでの微分係数を返すような関数」を返す高階関数です。7 点近似らしいです。導出などは、検索すればおそらく見つけられると思われます() (自分でも、これでよいのかわかってないです。もっと良いやり方をご存じの方は教えてください...orz)

ちなみに、h の値も雰囲気で決定しました☆orz

使い方

int main()
{
   auto fn = [](double x){ return std::pow(x, 2); };

   // テンプレート引数は、関数の引数の型などに合わせてください
   auto d_fn_d_x = diff<double>(fn);
   
   std::cout << d_fn_d_x(3); // 6
}

nyaruga::util::partial_diff

せっかくなので、偏微分する関数も紹介します。

nyaruga_util/partial_diff.hpp at master · alphya/nyaruga_util · GitHub

namespace hana = boost::hana;

// Partial differentiation
template <std::size_t count, typename NumType = num_t, typename F>
constexpr auto partial_diff(F && f) noexcept
{
   return [f](auto&& ... args) noexcept -> NumType
   {
      return diff<NumType>(bind_select_arg_replace<count>(forward(f), args...))
         (hana::arg<count>(forward(args)...));
   };
}

テンプレート引数 count で、( 1 からスタートして)何番目の引数に関して偏微分するかを指定します。 bind_select_arg_replace<count>は、count で指定した引数をプレースホルダーにするように、与えられた引数を引数の関数に束縛するような高階関数です。こうして一引数関数を作り、diff関数でその引数に関して微分しています。

使い方

int main()
{
   auto lambda = [](auto ... a) { return static_cast<nyaruga::util::num_t>((a * ... )); };
   std::cout << std::setprecision(18) 
      << nyaruga::util::partial_diff<1>(lambda)(nyaruga::util::num_t(2), 5., 6.); // 30
}

おわりに

すごく手抜き気味になってしまいましたが、たぶんこの記事は誰も見ないと思って公開しようと思います...