Proyek ini telah pindah ke Boost (matematika/diferensiasi/autodiff) dan repositori ini tidak lagi diperbarui.
Cabang | Travis | Appveyor | codecov.io |
---|---|---|---|
master | |||
develop |
AutoDiff adalah perpustakaan C ++ hanya header yang memfasilitasi diferensiasi otomatis (mode maju) dari fungsi matematika dari variabel tunggal dan berganda.
Implementasi ini didasarkan pada ekspansi seri Taylor dari fungsi analitik F pada titik x₀ :
Gagasan penting Autodiff adalah substitusi angka dengan polinomial dalam evaluasi f (x₀) . Dengan mengganti angka x₀ dengan polinomial pertama x₀+ε , dan menggunakan algoritma yang sama untuk menghitung f (x₀+ε) , polinomial yang dihasilkan dalam ε berisi turunan fungsi f '(x₀) , f' '(x₀) , f '' '(x₀) , ... di dalam koefisien. Setiap koefisien sama dengan turunan dari perintah masing -masing, dibagi dengan faktorial ordo.
Secara lebih rinci, asumsikan seseorang tertarik untuk menghitung t turunan pertama F pada x₀ . Tanpa kehilangan ketepatan pada perhitungan turunan, semua istilah o (ε n+1 ) yang mencakup kekuatan ε lebih besar dari n dapat dibuang. (Ini disebabkan oleh fakta bahwa setiap istilah dalam polinomial hanya tergantung pada istilah yang sama dan lebih rendah di bawah operasi aritmatika.) Di bawah aturan pemotongan ini, F memberikan transformasi polinomial-ke-polinomial:
Kemampuan C ++ untuk kelebihan beban operator dan fungsi memungkinkan untuk pembuatan kelas fvar
yang mewakili polinomial dalam ε . Dengan demikian algoritma yang sama f yang menghitung nilai numerik y₀ = f (x₀) , ketika ditulis untuk menerima dan mengembalikan variabel tipe generik (template), juga digunakan untuk menghitung polinomial ʃ N y n εⁿ = F (x₀+ ε) . Derivatif f (n) (x₀) kemudian ditemukan dari produk dari masing -masing faktorial n! dan koefisien y n :
#include <boost/matematika/diferensiasi/autodiff.hpp> #include <iostream> template <typename t> T fourth_power (t const & x) { T x4 = x * x; // retval di operator*() menggunakan memori X4 melalui NRVO. x4 *= x4; // Tidak ada salinan x4 yang dibuat di dalam operator*= () bahkan saat mengkuadratkan. mengembalikan x4; // x4 menggunakan memori y di main () melalui nrvo.} int main () {menggunakan namespace boost :: math :: diferensiasi; Constexpr Unsigned Order = 5; // turunan orde tertinggi untuk dihitung. Auto const x = make_fvar <double, order> (2.0); // Temukan turunan pada x = 2. Auto const y = fourth_power (x); untuk (unsigned i = 0; i <= order; ++ i) std :: cout << "y.derivative (" << i << ") =" << y.derivative (i) << std :: endl; kembali 0; }/*Output: y.derivative (0) = 16y.derivative (1) = 32y.derivative (2) = 48y.derivative (3) = 48y.derivative (4) = 24y.derivative (5) = 0*//
Yang di atas menghitung
#include <boost/matematika/diferensiasi/autodiff.hpp> #include <boost/multipresision/cpp_bin_float.hpp> #include <iostream> Menggunakan namespace boost :: math :: diferensiasi; template <typename w, typename x, ketik Y, math: Typename Z> Promosikan <w, x, y, z> f (const w & w, const x & x, const y & y, const z & z) {menggunakan namespace std; return exp (w * sin (x * log (y) / z) + sqrt (w * z / (x * y))) + w * w / tan (z); } int main () {menggunakan float50 = boost :: multipresision :: cpp_bin_float_50; Constexpr Unsigned NW = 3; // Urutan turunan maks untuk menghitung untuk w constexpr unsigned nx = 2; // Urutan turunan maks untuk menghitung x Constexpr Unsigned NY = 4; // Urutan turunan maks untuk menghitung untuk y Constexpr Unsigned NZ = 3; // Urutan turunan maks untuk menghitung z // Nyatakan 4 variabel independen bersama menjadi std :: tuple. variabel konstan otomatis = make_ftuple <float50, nw, nx, ny, nz> (11, 12, 13, 14); Auto const & w = std :: get <0> (variabel); // hingga turunan NW di W = 11 Auto Const & x = std :: Get <1> (variabel); // hingga turunan NX di x = 12 Auto const & y = std :: get <2> (variabel); // hingga turunan NY pada y = 13 Auto Const & Z = std :: Get <3> (variabel); // Hingga NZ Derivatif di Z = 14 Auto const v = f (w, x, y, z); // Dihitung dari diferensiasi simbolik Mathematica. float50 const jawaban ("1976.319600747797717779881875290418720908121189218755"); std :: cout << std :: setprecision (std :: numeric_limits <float50> :: digits10) << "Mathematica:" << Jawab << 'n' << "Autodiff:" << v.derivative (NW, NX, NY, NZ) << 'n' << std :: setprecision (3) << "Kesalahan relatif:" << (v.derivative (NW, NX, NY, NZ) / Jawaban - 1) << 'n'; kembali 0; }/*Output: Mathematica: 1976.3196007477777177798818752904187209081218921888Autodiff: 1976.319600777777777988881887529041877777777788881818752904041818818
#include <boost/matematika/diferensiasi/autodiff.hpp> #include <iostream> Menggunakan namespace boost :: math :: konstanta; menggunakan namespace boost :: math :: diferensiasi; // persamaan dan fungsi/variabel nama dari // https://en.wikipedia.org/wiki/greeks_(finance)#formulas_for_european_option_greeks// standar fungsi distribusi kumulatif normal. X phi (x const & x) {return 0,5 * erfc (-one_div_root_two <x> () * x); } enum class cp {call, put}; // Asumsikan nol dividen tahunan hasil (q = 0) .template <harga typename, typename sigma, typename tau, typename rate> Promosikan <harga, sigma, tau, rate> black_scholes_option_price (CP CP, Kouble K, Harga konstanta, Sigma Const & Sigma, Tau Const & Tau, Rate const & r) {Menggunakan namespace std; auto const d1 = (log (s / k) + (r + sigma * sigma / 2) * tau) / (sigma * sqrt (tau)); auto const d2 = (log (s / k) + (r - sigma * sigma / 2) * tau) / (sigma * sqrt (tau)); switch (cp) {case cp :: call: return s * phi (d1)-exp (-r * tau) * k * phi (d2); case cp :: put: return exp (-r * tau) * k * Phi (-d2)-s * phi (-d1); } } int main () {ganda const k = 100.0; // Harga pemogokan. auto const S = make_fvar <double, 2> (105); // Harga saham. Double Const Sigma = 5; // Volatilitas. ganda const tau = 30.0 / 365; // waktu untuk kedaluwarsa selama bertahun -tahun. (30 hari). Double Const R = 1.25 / 100; // Suku bunga. auto const call_price = black_scholes_option_price (cp :: call, k, s, sigma, tau, r); Auto const put_price = black_scholes_option_price (cp :: put, k, s, sigma, tau, r); std :: cout << "Black-Scholes Call Price =" << call_price.derivative (0) << 'n' << "Black-Scholes Price =" << put_price.derivative (0) << 'n' << "call delta =" << call_price.derivative (1) << 'n' << "put delta =" << put_price.derivative (1) << 'n' << "Call gamma =" << call_price .derivative (2) << 'n' << "taruh gamma =" << put_price.derivative (2) << 'n'; kembali 0; }/*Output: Black-Scholes Price Call = 56.5136Black-Scholes Put HARGA = 51.4109call Delta = 0.773818put delta = -0.226182call gamma = 0.00199852put gamma = 0.0019852*/
Lihat contoh/black_scholes.cpp untuk daftar yang lebih besar dari opsi orang Yunani yang dihitung secara otomatis.
Contoh -contoh di atas menggambarkan beberapa keuntungan menggunakan Autodiff:
Penghapusan redundansi kode. Keberadaan fungsi terpisah untuk menghitung turunan adalah bentuk redundansi kode, dengan semua kewajiban yang menyertainya:
Perubahan pada satu fungsi membutuhkan n perubahan tambahan untuk fungsi lain. Dalam contoh ke-3 di atas, pertimbangkan seberapa besar dan saling bergantung pada basis kode di atas jika fungsi terpisah ditulis untuk setiap nilai Yunani.
Ketergantungan pada fungsi turunan untuk tujuan yang berbeda akan pecah ketika perubahan dilakukan pada fungsi asli. Apa yang tidak perlu ada tidak bisa rusak.
Kode bloat, mengurangi integritas konseptual. Kontrol atas evolusi kode lebih mudah/lebih aman ketika basis kode lebih kecil dan dapat dipahami secara intuitif.
Keakuratan Derivatif atas Metode Perbedaan Hingga. Metode Perbedaan Hingga Single-Biterasi selalu mencakup variabel bebas Δx yang harus dipilih dengan cermat untuk setiap aplikasi. Jika Δx terlalu kecil, maka kesalahan numerik menjadi besar. Jika Δx terlalu besar, maka kesalahan matematika menjadi besar. Dengan Autodiff, tidak ada variabel gratis untuk ditetapkan dan keakuratan jawabannya umumnya lebih unggul daripada metode perbedaan hingga bahkan dengan pilihan terbaik ΔX .
Rincian tambahan ada di manual Autodiff.
Didistribusikan di bawah lisensi perangkat lunak Boost, versi 1.0.
Hanya header.
Dioptimalkan untuk C ++ 17. Juga mengkompilasi dan diuji dengan standar C ++ 11, C ++ 14 dan diusulkan C ++ 20.
Semua memori dialokasikan pada tumpukan.
Nama | Tujuan |
---|---|
doc | dokumentasi |
example | contoh |
include | header |
test | tes unit |
Laporkan bug: Pastikan untuk menyebutkan versi Boost, platform, dan kompiler yang Anda gunakan. Sampel kode kecil yang dapat dikompilasi untuk mereproduksi masalah selalu baik juga.
Kirim tambalan Anda sebagai permintaan tarik terhadap cabang yang dikembangkan. Perhatikan bahwa dengan mengirimkan tambalan, Anda setuju untuk melisensikan modifikasi Anda di bawah lisensi Boost Software, versi 1.0.