该项目已转移到增强(数学/差异/自动式),并且该存储库不再更新。
分支 | 特拉维斯 | 应用程序 | codecov.io |
---|---|---|---|
master | |||
develop |
AutoDiff是一个仅标题的C ++库,可促进单个和多个变量的数学函数的自动分化(正向模式)。
该实现是基于在X₀点上的分析函数F的Taylor系列扩展:
Autodiff的基本思想是在评估F(X₀)中用多项式替代数字。通过将数字X替换为一阶多项式X₀+ε ,并使用相同的算法来计算F(x₀+ε) , ε中的结果多项式包含该函数的衍生物f'(x₀) , f'(x₀),f''(x₀) , f'''(x₀) ,...在系数内。每个系数等于其各自秩序的导数,除以该顺序的阶乘。
更详细地,假设一个人有兴趣计算X f处F的第一个N衍生物。如果不损失计算衍生物的精确度,则可以丢弃包括大于n的功率的所有项O( εn+1 ) 。 (这是由于以下事实:多项式中的每个项仅取决于算术操作下的相等和低阶项。)在这些截断规则下, F提供了多项式到多项式转换:
C ++的超载运算符和功能的能力允许创建代表ε中多项式的类fvar
。因此,在写入并返回通用(模板)类型的变量时,计算y₀= f(x₀)的数值的相同算法f也用于计算多项式ʃn y n y n his ε) 。然后从各个阶乘n的乘积中找到衍生物F (n) (x₀) !和系数y n :
#include <boost/math/difection/autodiff.hpp> #include <iostream> template <typename t> t fourth_power(t const&x){ t x4 = x * x; //操作员*()中的retval通过NRVO使用X4的内存。 x4 *= x4; //即使在平方时,也没有在操作员内制作X4的副本。 返回x4; // x4通过nrvo。} int main()在main()中使用y的内存{使用名称空间boost :: math ::差异化; constexpr unsigned顺序= 5; //要计算的最高阶导数。 自动const x = make_fvar <double,order>(2.0); //在x = 2处找到衍生物。 auto const y = fourth_power(x); for(无符号i = 0; i <=顺序; ++ i) std :: cout <<“ y。 返回0; }/*输出:y。衍生(0)= 16y。衍生物(1)= 32y.Derivive(2)= 48y.Derivive(3)= 48y.Derivive(4)= 24y。衍生物(5)= 0*/
上述计算
#include <boost/Math/distriation.hpp> #include <boost/upertRecision/cpp_bin_float.hpp> #include <IoStream>使用namesspace boost :: Mathiation :: Mathiation :: Intelliation; typename z> 促进<w,x,y,z> f(const w&w,const x&x,const y&y,const z&z){使用命名空间std; 返回exp(w * sin(x * log(y) / z) + sqrt(w * z /(x * y))) + w * w / tan(z); } int main(){使用float50 = boost :: multipRecision :: cpp_bin_float_50; constexpr unsigned nw = 3; //最大派生级顺序以计算W constexpr unsigned nx = 2; //衍生物的最大顺序以计算x constexpr unsigned ny = 4; //最大派生阶以计算y constexpr unsigned nz = 3; //衍生物的最大顺序以计算z //将4个自变量一起声明为std ::元组。 auto const变量= make_ftuple <float50,nw,nx,ny,nz>(11,12,13,14); 自动const&w = std :: get <0>(变量); //在W = 11处最多最多NW衍生物 自动const&x = std :: get <1>(变量); // x = 12时最多可NX衍生物 自动const&y = std :: get <2>(变量); // y = 13的最多最多纽约导数 自动const&z = std :: get <3>(变量); //在z = 14时最多可NZ衍生物 自动const v = f(w,x,y,z); //根据Mathematica符号分化计算。 float50 const答案(“ 1976.31960074777777777779881875290418720908121189218755”); std :: cout << std :: setprecision(std :: numeric_limits <float50> :: digits10) <<“ Mathematica:” <<答案<<'n'<<“ autodiff:” << v.derivative(nw,nx,ny,ny,nz)<<'n'n'<< std :: setPrecision(3) <<“相对错误:” <<(V.Derivative(NW,NX,NY,NZ) /答案-1)<<'n'; 返回0; }/*输出:Mathematica:1976.3196007777777777777777777779818752904187209081211892188AUTODIFF:1976.3196600777777777777777777777777777777777777777777718721121121121121121121121121121121121121121121121121121121121199999999999太体
#include <boost/Math/districiation/autodiff.hpp> #include <Iostream>使用namespace boost :: Math :: Math :: Constants;使用名称空间BOOST :: MATH :: DINCATION; https://en.wikipedia.org/wiki/greeks_(finance)#formulas_for_european_option_greeks///标准标准累积累积分配函数<typename x> x phi(x const&x){返回0.5 * erfc(-One_div_root_two <x>() * x); }枚举类CP {呼叫,put}; //假定零年股息收益率(q = 0).template <typeName价格,TypeName Sigma,typename tau,typename rate> 促销<Price,Sigma,Tau,Rate> Black_Scholes_option_price(CP CP,Double K, 价格const&s, Sigma Const&Sigma, tau const&tau, 速率const&r){使用命名空间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 ::呼叫:返回s * phi(d1) - exp(-r * tau) * k * phi(d2); case cp :: put:return exp(-r * tau) * k * phi(-d2)-s * phi(-d1); } } int main(){double const k = 100.0; //罢工价格。 auto const s = make_fvar <double,2>(105); //股票价格。 双const sigma = 5; //波动。 双const tau = 30.0 / 365; //多年到期的时间。 (30天)。 double const r = 1.25 / 100; // 利率。 auto const call_price = black_scholes_option_price(cp :: call,k,s,s,sigma,tau,r); auto const put_price = black_scholes_option_price(cp :: put,k,s,s,sigma,tau,r); std :: cout <<“ black-scholes call price =” << call_price.derivative(0)<<'n'<<“ black-scholes price price =” << put_price.derivative(0)<<'n' <<“ call delta =” << call_price.derivative(1)<<'n'<<“ put delta =” << put_price.derivative(1)<<'n'n'n <<“ call gama =” << call_price 。衍生(2)<<'n'<<“ put gamma =” << put_price.derivative(2)<<'n'; 返回0; }/*输出:黑色 - choles呼叫价格= 56.5136Black-scholes put Price = 51.4109CALL delta = 0.773818 put delta = -0.226182CALL gamma = 0.001999852 put Gamma = 0.001999852*/0.00199852*/
有关自动计算的选项希腊人的较大列表,请参见示例/black_scholes.cpp。
以上示例说明了使用AutoDiff的一些优点:
消除代码冗余。 n个单独的功能以计算衍生物是代码冗余的一种形式,随之而来的所有负债:
一个功能的更改需要对其他功能进行n个其他更改。在上面的第三个示例中,考虑上述代码基库的大和相互依赖的数量是为每个希腊值编写单独的函数。
当对原始函数进行更改时,对不同目的的衍生功能的依赖性将破裂。不需要的不需要破裂。
代码膨胀,降低概念完整性。当代码库较小并且能够直观地掌握代码库时,对代码的演变的控制更加容易/更安全。
衍生物比有限差异方法的精度。单迭代有限差异方法始终包含一个无ΔX变量,必须仔细为每个应用程序选择。如果ΔX太小,则数值误差会大大。如果ΔX太大,则数学误差会大大。 使用AutoDiff,没有可以设置的自由变量,即使是最佳选择ΔX ,答案的准确性也比有限的差异方法优于有限的差异方法。
其他详细信息在自动手册中。
根据Boost软件许可证(版本1.0)分发。
仅标头。
针对C ++ 17进行了优化。还使用C ++ 11,C ++ 14和建议的C ++ 20标准进行编译并进行了测试。
所有内存都分配在堆栈上。
姓名 | 目的 |
---|---|
doc | 文档 |
example | 例子 |
include | 标题 |
test | 单位测试 |
报告错误:请务必提及您正在使用的Boost版本,平台和编译器。重现问题的小型编译代码样本也总是很好。
提交您的补丁程序作为对开发分支机构的拉请求。请注意,通过提交补丁,您同意根据Boost软件许可证版本1.0许可您的修改。