├── .gitattributes ├── .gitignore ├── AAD and Parallel Simulations examples ├── toyCodeChp15section2 ├── toyCodeChp9section5 └── toyCodeChp9sections2to4 ├── AAD.cpp ├── AAD.h ├── AADExpr.h ├── AADNode.h ├── AADNumber.h ├── AADTape.h ├── AutocallPricer.xlsx ├── ConcurrentQueue.h ├── Intro2AADinMachineLearningAndFinance.pdf ├── README.md ├── ThreadPool.cpp ├── VC_redist.x64.exe ├── VC_redist.x86.exe ├── Workshop ├── dlBlackScholes.ipynb ├── net1.png ├── reval.xlsx └── testWithToyCode.xlsx ├── analytics.h ├── back.jpg ├── blocklist.h ├── choldc.h ├── gaussians.h ├── interp.h ├── ivs.h ├── main.h ├── matrix.h ├── mcBase.cpp ├── mcBase.h ├── mcMdl.h ├── mcMdlBS.h ├── mcMdlDupire.h ├── mcMdlMultiDisplaced.h ├── mcPrd.h ├── mcPrdMulti.h ├── mrg32k3a.h ├── sobol.cpp ├── sobol.h ├── store.h ├── testDLM.xlsx ├── threadPool.h ├── toyCode.h ├── utility.h ├── xlComp.sln ├── xlComp.vcxproj ├── xlComp.vcxproj.filters ├── xlComp.xll ├── xlCpp ├── ExportingCpp2xl.pdf └── cppFiles │ ├── MemoryManager.cpp │ ├── MemoryPool.cpp │ ├── MemoryPool.h │ ├── framework.h │ ├── gaussians.h │ ├── memorymanager.h │ ├── xlExport.cpp │ ├── xlOper.h │ ├── xlcall.cpp │ └── xlcall.h ├── xlExport.cpp ├── xlMemoryManager.cpp ├── xlMemoryPool.cpp ├── xlMemoryPool.h ├── xlOper.h ├── xlTest.xlsx ├── xlcall.cpp ├── xlcall.h ├── xlframework.h └── xlmemorymanager.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | # ========================= 255 | # Operating System Files 256 | # ========================= 257 | 258 | # OSX 259 | # ========================= 260 | 261 | .DS_Store 262 | .AppleDouble 263 | .LSOverride 264 | 265 | # Thumbnails 266 | ._* 267 | 268 | # Files that might appear in the root of a volume 269 | .DocumentRevisions-V100 270 | .fseventsd 271 | .Spotlight-V100 272 | .TemporaryItems 273 | .Trashes 274 | .VolumeIcon.icns 275 | 276 | # Directories potentially created on remote AFP share 277 | .AppleDB 278 | .AppleDesktop 279 | Network Trash Folder 280 | Temporary Items 281 | .apdisk 282 | 283 | # Windows 284 | # ========================= 285 | 286 | # Windows image file caches 287 | Thumbs.db 288 | ehthumbs.db 289 | 290 | # Folder config file 291 | Desktop.ini 292 | 293 | # Recycle Bin used on file shares 294 | $RECYCLE.BIN/ 295 | 296 | # Windows Installer files 297 | *.cab 298 | *.msi 299 | *.msm 300 | *.msp 301 | 302 | # Windows shortcuts 303 | *.lnk 304 | *.dat 305 | *.dat 306 | /*.dat 307 | /*.dat 308 | *.bak 309 | *.*.bak 310 | *.*.*.bak 311 | *.*.*.*.bak 312 | *.*.*.*.*.bak 313 | *.txt 314 | *.db 315 | *.opendb 316 | *.*.opendb 317 | *.*.*.opendb 318 | *.*.*.*.opendb 319 | 320 | -------------------------------------------------------------------------------- /AAD and Parallel Simulations examples/toyCodeChp15section2: -------------------------------------------------------------------------------- 1 | /* 2 | Toy code contained in chapter 15, section 2 (pages 512 to 520). 3 | 4 | The code is modified slightly to hold the adjoint in the class Number within a shared pointer to ensure that 5 | all copies of Number hold the same adjoint (thereby allowing the adjoints to be updated within x1 and x2). 6 | */ 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | /************************************************************************************************************************************************************/ 12 | template 13 | class Expression 14 | {}; 15 | 16 | /************************************************************************************************************************************************************/ 17 | // CRTP (Curiously Recurring Template Pattern) 18 | template 19 | class ExprTimes : public Expression> 20 | { 21 | LHS lhs; 22 | RHS rhs; 23 | 24 | public: 25 | 26 | // Constructor 27 | explicit ExprTimes 28 | (const Expression& l, const Expression& r) 29 | : lhs(static_cast(l)), 30 | rhs(static_cast(r)) {} 31 | 32 | double value() const 33 | { 34 | return lhs.value() * rhs.value(); 35 | } 36 | 37 | enum { numNumbers = LHS::numNumbers + RHS::numNumbers }; 38 | 39 | string writeProgram( 40 | // On input, the number of nodes processed so far 41 | // On return the total number of nodes processed on exit 42 | size_t& processed) 43 | { 44 | // Process the left sub-DAG 45 | const string ls = lhs.writeProgram(processed); 46 | const size_t ln = processed - 1; 47 | 48 | // Process the right sub-DAG 49 | const string rs = rhs.writeProgram(processed); 50 | const size_t rn = processed - 1; 51 | 52 | // Process this node 53 | const string thisString = ls + rs + 54 | "y" + to_string(processed) 55 | + " = y" + to_string(ln) + " * y" + to_string(rn) + "\n"; 56 | 57 | ++processed; 58 | 59 | return thisString; 60 | } 61 | 62 | // Input: accumulated adjoint for this node or 1 if top node 63 | void pushAdjoint(const double adjoint) 64 | { 65 | lhs.pushAdjoint(adjoint * rhs.value()); 66 | rhs.pushAdjoint(adjoint * lhs.value()); 67 | } 68 | }; 69 | 70 | // Operator overload for expressions 71 | template 72 | inline ExprTimes operator*( 73 | const Expression& lhs, const Expression& rhs) 74 | { 75 | return ExprTimes(lhs, rhs); 76 | } 77 | 78 | /************************************************************************************************************************************************************/ 79 | template 80 | class ExprLog : public Expression> 81 | { 82 | ARG arg; 83 | 84 | public: 85 | 86 | // Constructor 87 | explicit ExprLog(const Expression& a) 88 | : arg(static_cast(a)) {} 89 | 90 | double value() const 91 | { 92 | return log(arg.value()); 93 | } 94 | 95 | enum { numNumbers = ARG::numNumbers }; 96 | 97 | string writeProgram( 98 | // On input, the number of nodes processed so far 99 | // On return the total number of nodes processed on exit 100 | size_t& processed) 101 | { 102 | // Process the arg sub-DAG 103 | const string s = arg.writeProgram(processed); 104 | const size_t n = processed - 1; 105 | 106 | // Process this node 107 | const string thisString = s + 108 | "y" + to_string(processed) 109 | + " = log(y" + to_string(n) + ")\n"; 110 | 111 | ++processed; 112 | 113 | return thisString; 114 | } 115 | 116 | // Input: accumulated adjoint for this node or 1 if top node 117 | void pushAdjoint(const double adjoint) 118 | { 119 | arg.pushAdjoint(adjoint / arg.value()); 120 | } 121 | }; 122 | 123 | // Operator overload for expressions 124 | template 125 | inline ExprLog log(const Expression& arg) 126 | { 127 | return ExprLog(arg); 128 | } 129 | 130 | /************************************************************************************************************************************************************/ 131 | // Number type, also an expression 132 | class Number : public Expression 133 | { 134 | double val; 135 | shared_ptr adj; // Use a shared pointer so that copies of Number hold the same adjoint value (required to make lines 199 and 200 work) 136 | 137 | public: 138 | 139 | // Constructor 140 | explicit Number(const double v) : val(v), adj(make_shared(0.0)) {} // code modified from text to work with shared pointer 141 | 142 | double value() const 143 | { 144 | return val; 145 | } 146 | 147 | double adjoint() const 148 | { 149 | return *adj; // code modified from text to work with shared pointer 150 | } 151 | 152 | enum { numNumbers = 1 }; 153 | 154 | string writeProgram( 155 | // On input, the number of nodes processed so far 156 | // On return the total number of nodes processed on exit 157 | size_t& processed) 158 | { 159 | const string thisString = "y" + to_string(processed) + " = " + to_string(val) + "\n"; 160 | 161 | ++processed; 162 | 163 | return thisString; 164 | } 165 | 166 | void pushAdjoint(const double adjoint) 167 | { 168 | *adj = adjoint; // code modified from text to work with shared pointer 169 | } 170 | }; 171 | 172 | /************************************************************************************************************************************************************/ 173 | auto calculate(Number t1, Number t2) 174 | { 175 | return t1 * log(t2); 176 | } 177 | 178 | /************************************************************************************************************************************************************/ 179 | template 180 | constexpr auto countNumbersIn(const Expression&) 181 | { 182 | return E::numNumbers; 183 | } 184 | 185 | int main() 186 | { 187 | Number x1(2.0), x2(3.0); 188 | 189 | auto e = calculate(x1, x2); 190 | 191 | std::cout << e.value() << std::endl; // 2.19722 = 2 * log(3) 192 | 193 | std::cout << countNumbersIn(e) << std::endl; // 2 - note this fixes a typo in the text that used numNumbersIn 194 | 195 | size_t processed = 0; 196 | cout << e.writeProgram(processed); 197 | 198 | e.pushAdjoint(1.0); 199 | cout << "x1 adjoint = " << x1.adjoint() << endl; // 1.09861 = log(3) 200 | cout << "x2 adjoint = " << x2.adjoint() << endl; // 0.666667 = 2/3 201 | } 202 | -------------------------------------------------------------------------------- /AAD and Parallel Simulations examples/toyCodeChp9section5: -------------------------------------------------------------------------------- 1 | /* 2 | Toy code contained in chapter 9, sections 5 (pages 349 to 355). 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | class Node 13 | { 14 | protected: 15 | 16 | vector myArguments; 17 | 18 | double myResult; 19 | double myAdjoint = 0.0; 20 | 21 | public: 22 | 23 | // Access result 24 | double result() 25 | { 26 | return myResult; 27 | } 28 | 29 | // Access adjoint 30 | double& adjoint() 31 | { 32 | return myAdjoint; 33 | } 34 | 35 | void resetAdjoints() 36 | { 37 | for (auto argument : myArguments) argument->resetAdjoints(); 38 | myAdjoint = 0.0; 39 | } 40 | 41 | virtual void propagateAdjoint() = 0; 42 | }; 43 | 44 | class PlusNode : public Node 45 | { 46 | public: 47 | 48 | PlusNode(Node* lhs, Node* rhs) 49 | { 50 | myArguments.resize(2); 51 | myArguments[0] = lhs; 52 | myArguments[1] = rhs; 53 | 54 | // Eager evaluation 55 | myResult = lhs->result() + rhs->result(); 56 | } 57 | 58 | void propagateAdjoint() override 59 | { 60 | myArguments[0]->adjoint() += myAdjoint; 61 | myArguments[1]->adjoint() += myAdjoint; 62 | } 63 | }; 64 | 65 | class TimesNode : public Node 66 | { 67 | public: 68 | 69 | TimesNode(Node* lhs, Node* rhs) 70 | { 71 | myArguments.resize(2); 72 | myArguments[0] = lhs; 73 | myArguments[1] = rhs; 74 | 75 | // Eager evaluation 76 | myResult = lhs->result() * rhs->result(); 77 | } 78 | 79 | void propagateAdjoint() override 80 | { 81 | myArguments[0]->adjoint() += myAdjoint * myArguments[1]->result(); 82 | myArguments[1]->adjoint() += myAdjoint * myArguments[0]->result(); 83 | } 84 | }; 85 | 86 | class LogNode : public Node 87 | { 88 | public: 89 | 90 | LogNode(Node* arg) 91 | { 92 | myArguments.resize(1); 93 | myArguments[0] = arg; 94 | 95 | // Eager evaluation 96 | myResult = log(arg->result()); 97 | } 98 | 99 | void propagateAdjoint() override 100 | { 101 | myArguments[0]->adjoint() += myAdjoint / myArguments[0]->result(); 102 | } 103 | }; 104 | 105 | class Leaf : public Node 106 | { 107 | public: 108 | 109 | Leaf(double val) 110 | { 111 | myResult = val; 112 | } 113 | 114 | double getVal() 115 | { 116 | return myResult; 117 | } 118 | 119 | void setVal(double val) 120 | { 121 | myResult = val; 122 | } 123 | 124 | void propagateAdjoint() override {} 125 | }; 126 | 127 | class Number 128 | { 129 | Node* myNode; 130 | 131 | public: 132 | 133 | // The tape, as a public static member 134 | static vector> tape; 135 | 136 | // Create node and put it on the tape 137 | Number(double val) 138 | : myNode(new Leaf(val)) 139 | { 140 | tape.push_back(unique_ptr(myNode)); 141 | } 142 | 143 | Number(Node* node) 144 | : myNode(node) {} 145 | 146 | Node* node() 147 | { 148 | return myNode; 149 | } 150 | 151 | void setVal(double val) 152 | { 153 | // Cast to Leaf, only leaves can be changed 154 | dynamic_cast(myNode)->setVal(val); 155 | } 156 | 157 | double getVal() 158 | { 159 | // Only leaves can be read 160 | return dynamic_cast(myNode)->getVal(); 161 | } 162 | 163 | // Accessor/setter, from the inputs 164 | double& adjoint() 165 | { 166 | return myNode->adjoint(); 167 | } 168 | 169 | // Propagator 170 | void propagateAdjoints() 171 | { 172 | myNode->resetAdjoints(); 173 | myNode->adjoint() = 1.0; 174 | 175 | // Find my node on the tape, searching from the last 176 | auto it = tape.rbegin(); // last node on the tape 177 | while (it->get() != myNode) 178 | ++it; // reverse iter: ++ means go back 179 | 180 | // Now it is on my node 181 | // Conduct propogation in reverse order 182 | while (it != tape.rend()) 183 | { 184 | (*it)->propagateAdjoint(); 185 | ++it; // really means -- 186 | } 187 | } 188 | }; 189 | 190 | vector> Number::tape; 191 | 192 | Number operator+(Number lhs, Number rhs) 193 | { 194 | // Create node: note eagerly computes result 195 | Node* n = new PlusNode(lhs.node(), rhs.node()); 196 | // Put on tape 197 | Number::tape.push_back(unique_ptr(n)); 198 | // Return result 199 | return n; 200 | } 201 | 202 | Number operator*(Number lhs, Number rhs) 203 | { 204 | // Create node: note eagerly computes result 205 | Node* n = new TimesNode(lhs.node(), rhs.node()); 206 | // Put on tape 207 | Number::tape.push_back(unique_ptr(n)); 208 | // Return result 209 | return n; 210 | } 211 | 212 | Number log(Number arg) 213 | { 214 | // Create node: note eagerly computes result 215 | Node* n = new LogNode(arg.node()); 216 | // Put on tape 217 | Number::tape.push_back(unique_ptr(n)); 218 | // Return result 219 | return n; 220 | } 221 | 222 | template 223 | T f(T x[5]) 224 | { 225 | auto y1 = x[2] * (5.0 * x[0] + x[1]); 226 | auto y2 = log(y1); 227 | auto y = (y1 + x[3] * y2) * (y1 + y2); 228 | return y; 229 | } 230 | 231 | int main() 232 | { 233 | Number x[5] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; 234 | 235 | // Evaluate and build the tape 236 | Number y = f(x); 237 | 238 | // Propagate adjoints through the tape in reverse order 239 | y.propagateAdjoints(); 240 | 241 | // Get derivatives 242 | for (size_t i = 0; i < 5; ++i) 243 | { 244 | cout << "a" << i << " = " << x[i].adjoint() << endl; 245 | } 246 | 247 | // 950.736, 190.147, 443.677, 73.2041, 0 248 | } 249 | -------------------------------------------------------------------------------- /AAD and Parallel Simulations examples/toyCodeChp9sections2to4: -------------------------------------------------------------------------------- 1 | /* 2 | Toy code contained in chapter 9, sections 2, 3 and 4 (pages 328 to 349). 3 | 4 | For VS15, the code in the book compiles and reproduces the results described. 5 | VS17 has issues with not accepting directly created lambdas into non const refs, so the code below is modified slightly 6 | to work in both VS15 and VS17. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | /******************************************************************************************************************/ 16 | class Node 17 | { 18 | protected: 19 | vector> myArguments; 20 | 21 | bool myProcessed = false; 22 | unsigned myOrder = 0; 23 | double myResult; 24 | double myAdjoint = 0.0; 25 | 26 | public: 27 | virtual ~Node() {}; 28 | 29 | // visitFunc: 30 | // a function of Node& that conducts a particular form of visit 31 | // templated so we can pass a lambda 32 | template 33 | void postOrder(V& visitFunc) 34 | { 35 | // Already processed -> do nothing 36 | if (myProcessed == false) 37 | { 38 | // Process children first 39 | for (auto argument : myArguments) 40 | argument->postOrder(visitFunc); 41 | 42 | // Visit the node 43 | visitFunc(*this); 44 | 45 | // Mark as processed 46 | myProcessed = true; 47 | } 48 | } 49 | 50 | template 51 | void preOrder(V& visitFunc) 52 | { 53 | // Visit the node first 54 | visitFunc(*this); 55 | 56 | // Process children 57 | for (auto argument : myArguments) 58 | argument->preOrder(visitFunc); 59 | } 60 | 61 | // Additional function required to handle VS17 compatibility 62 | template 63 | void breadthFirst(V& visitFunc) 64 | { 65 | queue> q; 66 | breadthFirst(visitFunc, q); 67 | } 68 | 69 | // The signature of this function has changed to work in both VS15 and VS17. 70 | template 71 | void breadthFirst( 72 | V& visitFunc, 73 | queue>& q) 74 | { 75 | // Send kids to queue 76 | for (auto argument : myArguments) q.push(argument); 77 | 78 | // Visit the node first 79 | visitFunc(*this); 80 | 81 | // Process nodes in the queue until empty 82 | while (!q.empty()) 83 | { 84 | // Access the front node 85 | auto n = q.front(); 86 | 87 | // Remove from queue 88 | q.pop(); 89 | 90 | // Process it 91 | n->breadthFirst(visitFunc, q); 92 | } // Finished processing the queue: exit 93 | } 94 | 95 | // Access result 96 | double result() 97 | { 98 | return myResult; 99 | } 100 | 101 | // Reset processsed flags 102 | void resetProcessed() 103 | { 104 | for (auto argument : myArguments) argument->resetProcessed(); 105 | myProcessed = false; 106 | } 107 | 108 | virtual void evaluate() = 0; 109 | 110 | void setOrder(unsigned order) 111 | { 112 | myOrder = order; 113 | } 114 | 115 | unsigned order() 116 | { 117 | return myOrder; 118 | } 119 | 120 | virtual void logInstruction() = 0; 121 | 122 | // Note: return by reference 123 | // used to get and set 124 | double& adjoint() 125 | { 126 | return myAdjoint; 127 | } 128 | 129 | void resetAdjoints() 130 | { 131 | for (auto argument : myArguments) argument->resetAdjoints(); 132 | myAdjoint = 0.0; 133 | } 134 | 135 | virtual void propagateAdjoint() = 0; 136 | }; 137 | 138 | /******************************************************************************************************************/ 139 | class PlusNode : public Node 140 | { 141 | public: 142 | PlusNode(shared_ptr lhs, shared_ptr rhs) 143 | { 144 | myArguments.resize(2); 145 | myArguments[0] = lhs; 146 | myArguments[1] = rhs; 147 | } 148 | 149 | void evaluate() override 150 | { 151 | myResult = myArguments[0]->result() + myArguments[1]->result(); 152 | } 153 | 154 | void logInstruction() override 155 | { 156 | cout << "y" << order() << " = y" << myArguments[0]->order() << " + y" << myArguments[1]->order() << endl; 157 | } 158 | 159 | void propagateAdjoint() override 160 | { 161 | cout << "Propogating node " << myOrder 162 | << " adjoint = " << myAdjoint << endl; 163 | 164 | myArguments[0]->adjoint() += myAdjoint; 165 | myArguments[1]->adjoint() += myAdjoint; 166 | 167 | // Set the adjoint to 0 after its propagation to child nodes (see section 9.4, page 347). 168 | myAdjoint = 0.0; 169 | } 170 | }; 171 | 172 | /******************************************************************************************************************/ 173 | class TimesNode : public Node 174 | { 175 | public: 176 | TimesNode(shared_ptr lhs, shared_ptr rhs) 177 | { 178 | myArguments.resize(2); 179 | myArguments[0] = lhs; 180 | myArguments[1] = rhs; 181 | } 182 | 183 | void evaluate() override 184 | { 185 | myResult = myArguments[0]->result() * myArguments[1]->result(); 186 | } 187 | 188 | void logInstruction() override 189 | { 190 | cout << "y" << order() << " = y" << myArguments[0]->order() << " * y" << myArguments[1]->order() << endl; 191 | } 192 | 193 | void propagateAdjoint() override 194 | { 195 | cout << "Propogating node " << myOrder 196 | << " adjoint = " << myAdjoint << endl; 197 | 198 | myArguments[0]->adjoint() += myAdjoint * myArguments[1]->result(); 199 | myArguments[1]->adjoint() += myAdjoint * myArguments[0]->result(); 200 | 201 | // Set the adjoint to 0 after its propagation to child nodes (see section 9.4, page 347). 202 | myAdjoint = 0.0; 203 | } 204 | }; 205 | 206 | /******************************************************************************************************************/ 207 | class LogNode : public Node 208 | { 209 | public: 210 | LogNode(shared_ptr arg) 211 | { 212 | myArguments.resize(1); 213 | myArguments[0] = arg; 214 | } 215 | 216 | void evaluate() override 217 | { 218 | myResult = log(myArguments[0]->result()); 219 | } 220 | 221 | void logInstruction() override 222 | { 223 | cout << "y" << order() << " = log(y" << myArguments[0]->order() << ")" << endl; 224 | } 225 | 226 | void propagateAdjoint() override 227 | { 228 | cout << "Propogating node " << myOrder 229 | << " adjoint = " << myAdjoint << endl; 230 | 231 | myArguments[0]->adjoint() += myAdjoint / myArguments[0]->result(); 232 | 233 | // Set the adjoint to 0 after its propagation to child nodes (see section 9.4, page 347). 234 | myAdjoint = 0.0; 235 | } 236 | }; 237 | 238 | /******************************************************************************************************************/ 239 | class Leaf : public Node 240 | { 241 | double myValue; 242 | 243 | public: 244 | Leaf(double val) : myValue(val) {} 245 | 246 | double getVal() 247 | { 248 | return myValue; 249 | } 250 | 251 | void setVal(double val) 252 | { 253 | myValue = val; 254 | } 255 | 256 | void evaluate() override 257 | { 258 | myResult = myValue; 259 | } 260 | 261 | void logInstruction() override 262 | { 263 | cout << "y" << order() << " = " << myValue << endl; 264 | } 265 | 266 | void propagateAdjoint() override 267 | { 268 | cout << "Accumulating leaf " << myOrder 269 | << " adjoint = " << myAdjoint << endl; 270 | } 271 | }; 272 | 273 | /******************************************************************************************************************/ 274 | class Number 275 | { 276 | shared_ptr myNode; 277 | 278 | public: 279 | Number(double val) : myNode(new Leaf(val)) {} 280 | 281 | Number(shared_ptr node) : myNode(node) {} 282 | 283 | shared_ptr node() { return myNode; } 284 | 285 | void setVal(double val) 286 | { 287 | // Cast to Leaf, only leaves can be changed 288 | dynamic_pointer_cast(myNode)->setVal(val); 289 | } 290 | 291 | double getVal() 292 | { 293 | // Only leaves can be read 294 | return dynamic_pointer_cast(myNode)->getVal(); 295 | } 296 | 297 | double evaluate() 298 | { 299 | myNode->resetProcessed(); 300 | // The next line is the original code that works in VS15 301 | //myNode->postOrder([](Node& n) {n.evaluate(); }); 302 | // The next two lines work in both VS15 and VS17 303 | auto lam = [order = 0](Node& n) mutable {n.evaluate(); }; 304 | myNode->postOrder(lam); 305 | return myNode->result(); 306 | } 307 | 308 | void setOrder() 309 | { 310 | myNode->resetProcessed(); 311 | // The next line is the original code that works in VS15 312 | //myNode->postOrder([order = 0](Node& n) mutable {n.setOrder(++order); }); 313 | // The next two lines work in both VS15 and VS17 314 | auto lam = [order = 0](Node& n) mutable {n.setOrder(++order); }; 315 | myNode->postOrder(lam); 316 | } 317 | 318 | void logResults() 319 | { 320 | myNode->resetProcessed(); 321 | // The next line is the original code that works in VS15 322 | //myNode->postOrder([](Node& n) {cout << "Processed node " << n.order() << " result " << n.result() << endl; }); 323 | // The next two lines work in both VS15 and VS17 324 | auto lam = [order = 0](Node& n) mutable {cout << "Processed node " << n.order() << " result " << n.result() << endl; }; 325 | myNode->postOrder(lam); 326 | } 327 | 328 | void logProgram() 329 | { 330 | myNode->resetProcessed(); 331 | // The next line is the original code that works in VS15 332 | //myNode->postOrder([](Node& n) {n.logInstruction(); }); 333 | // The next two lines work in both VS15 and VS17 334 | auto lam = [order = 0](Node& n) mutable {n.logInstruction(); }; 335 | myNode->postOrder(lam); 336 | } 337 | 338 | // Accessor/setter, from the inputs 339 | double& adjoint() 340 | { 341 | return myNode->adjoint(); 342 | } 343 | 344 | // Propagator, from the result 345 | void propagateAdjoints() 346 | { 347 | myNode->resetAdjoints(); 348 | myNode->adjoint() = 1.0; 349 | // Preorder traversal code 350 | // The next line is the original code that works in VS15 351 | //myNode->preOrder([](Node& n) {n.propagateAdjoint(); }); 352 | // The next two lines work in both VS15 and VS17 353 | auto lam = [](Node& n) {n.propagateAdjoint(); }; 354 | myNode->preOrder(lam); 355 | 356 | // Breadth-first traversal code 357 | // The next line is the original code that works in VS15 358 | //myNode->breadthFirst([](Node& n) {n.propagateAdjoint(); }); 359 | // The next two lines work in both VS15 and VS17 360 | //auto lam = [](Node& n) {n.propagateAdjoint(); }; 361 | //myNode->breadthFirst(lam); 362 | } 363 | }; 364 | 365 | shared_ptr operator+(Number lhs, Number rhs) 366 | { 367 | return shared_ptr(new PlusNode(lhs.node(), rhs.node())); 368 | } 369 | 370 | shared_ptr operator*(Number lhs, Number rhs) 371 | { 372 | return shared_ptr(new TimesNode(lhs.node(), rhs.node())); 373 | } 374 | 375 | shared_ptr log(Number arg) 376 | { 377 | return shared_ptr(new LogNode(arg.node())); 378 | } 379 | 380 | /******************************************************************************************************************/ 381 | /* 382 | Templated calculation code (see section 9.2, page 331) 383 | */ 384 | template 385 | T f(T x[5]) 386 | { 387 | T y1 = x[2] * (5.0 * x[0] + x[1]); 388 | T y2 = log(y1); 389 | T y = (y1 + x[3] * y2) * (y1 + y2); 390 | return y; 391 | } 392 | 393 | /******************************************************************************************************************/ 394 | int main() 395 | { 396 | Number x[5] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; 397 | 398 | // Build the DAG 399 | Number y = f(x); 400 | 401 | // Set the order on the DAG 402 | y.setOrder(); 403 | 404 | // Log program 405 | y.logProgram(); 406 | 407 | // Evaluate on the DAG 408 | cout << y.evaluate() << endl; // 797.751 409 | 410 | // Log all results 411 | y.logResults(); 412 | 413 | // Uncomment the following code to evaluate the DAG with a different input (see page 336) 414 | /* 415 | // Change x0 on the DAG 416 | x[0].setVal(2.5); 417 | 418 | // Evaluate on the DAG again 419 | cout << y.evaluate() << endl; // 2769.76 420 | 421 | // Log results again 422 | y.logResults();*/ 423 | 424 | y.propagateAdjoints(); 425 | 426 | // Get derivatives 427 | for (size_t i = 0; i < 5; ++i) 428 | { 429 | cout << "a" << i << " = " << x[i].adjoint() << endl; 430 | } 431 | } 432 | -------------------------------------------------------------------------------- /AAD.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #include "AAD.h" 18 | #include 19 | 20 | // Statics 21 | 22 | size_t Node::numAdj = 1; 23 | bool Tape::multi = false; 24 | 25 | Tape globalTape; 26 | thread_local Tape* Number::tape = &globalTape; 27 | -------------------------------------------------------------------------------- /AAD.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | // So we can instrument Gaussians like standard math functions 22 | #include "gaussians.h" 23 | 24 | // Use traditional AAD of chapter 10 (false) 25 | // or expression templated (AADET) of chapter 15 (true) 26 | #define AADET true 27 | 28 | #if AADET 29 | 30 | #include "AADExpr.h" 31 | 32 | #else 33 | 34 | #include "AADNumber.h" 35 | 36 | #endif 37 | 38 | // Routines for multi-dimensional AAD (chapter 14) 39 | // Set static context for multi-dimensional AAD 40 | 41 | // RAII: reset dimension 1 on destruction 42 | struct numResultsResetterForAAD 43 | { 44 | ~numResultsResetterForAAD() 45 | { 46 | Tape::multi = false; 47 | Node::numAdj = 1; 48 | } 49 | }; 50 | 51 | // Routine: set dimension and get RAII resetter 52 | inline auto setNumResultsForAAD(const bool multi = false, const size_t numResults = 1) 53 | { 54 | Tape::multi = multi; 55 | Node::numAdj = numResults; 56 | return make_unique(); 57 | } 58 | 59 | // Other utilities 60 | 61 | // Put collection on tape 62 | template 63 | inline void putOnTape(IT begin, IT end) 64 | { 65 | for_each(begin, end, [](Number& n) {n.putOnTape(); }); 66 | } 67 | 68 | // Convert collection between double and Number or reverse 69 | template 70 | inline void convertCollection(It1 srcBegin, It1 srcEnd, It2 destBegin) 71 | { 72 | using destType = remove_reference_t; 73 | transform(srcBegin, srcEnd, destBegin, 74 | [](const auto& source) { return destType(source); }); 75 | } 76 | -------------------------------------------------------------------------------- /AADNode.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #pragma once 18 | 19 | // AAD implementation of chapter 10 20 | // (With multi-dimensional additions of chapter 14) 21 | 22 | // Implementation of Node = record on tape 23 | 24 | // Unchanged for AADET of chapter 15 25 | 26 | #include 27 | using namespace std; 28 | 29 | class Node 30 | { 31 | friend class Tape; 32 | friend class Number; 33 | friend auto setNumResultsForAAD(const bool, const size_t); 34 | friend struct numResultsResetterForAAD; 35 | 36 | // The adjoint(s) 37 | // in single case, self held (chapter 10) 38 | double mAdjoint = 0; 39 | // in multi case, held separately and accessed by pointer (chapter 14) 40 | double* pAdjoints; 41 | 42 | // Data lives in separate memory 43 | 44 | // the n derivatives to arguments, 45 | double* pDerivatives; 46 | 47 | // the n pointers to the adjoints of arguments 48 | double** pAdjPtrs; 49 | 50 | // Number of adjoints (results) to propagate, usually 1 51 | // See chapter 14 52 | static size_t numAdj; 53 | 54 | // Number of childs (arguments) 55 | const size_t n; 56 | 57 | public: 58 | 59 | Node(const size_t N = 0) : n(N) {} 60 | 61 | // Access to adjoint(s) 62 | // single 63 | double& adjoint() 64 | { 65 | return mAdjoint; 66 | } 67 | // multi 68 | double& adjoint(const size_t n) { return pAdjoints[n]; } 69 | 70 | // Back-propagate adjoints to arguments adjoints 71 | 72 | // Single case, chapter 10 73 | void propagateOne() 74 | { 75 | // Nothing to propagate 76 | if (!n || !mAdjoint) return; 77 | 78 | for (size_t i = 0; i < n; ++i) 79 | { 80 | *(pAdjPtrs[i]) += pDerivatives[i] * mAdjoint; 81 | } 82 | } 83 | 84 | // Multi case, chapter 14 85 | void propagateAll() 86 | { 87 | // No adjoint to propagate 88 | if (!n || all_of(pAdjoints, pAdjoints + numAdj, 89 | [](const double& x) { return !x; })) 90 | return; 91 | 92 | for (size_t i = 0; i < n; ++i) 93 | { 94 | double *adjPtrs = pAdjPtrs[i], ders = pDerivatives[i]; 95 | 96 | // Vectorized! 97 | for (size_t j = 0; j < numAdj; ++j) 98 | { 99 | adjPtrs[j] += ders * pAdjoints[j]; 100 | } 101 | } 102 | } 103 | }; -------------------------------------------------------------------------------- /AADTape.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #pragma once 18 | 19 | // AAD implementation of chapter 10 20 | // (With multi-dimensional additions of chapter 14) 21 | 22 | // Implementation of the Tape 23 | 24 | // Unchanged for AADET of chapter 15 25 | 26 | #include "blocklist.h" 27 | #include "AADNode.h" 28 | 29 | constexpr size_t BLOCKSIZE = 16384; // Number of nodes 30 | constexpr size_t ADJSIZE = 32768; // Number of adjoints 31 | constexpr size_t DATASIZE = 65536; // Data in bytes 32 | 33 | class Tape 34 | { 35 | // Working with multiple results / adjoints? 36 | static bool multi; 37 | 38 | // Storage for adjoints in multi-dimensional case (chapter 14) 39 | blocklist myAdjointsMulti; 40 | 41 | // Storage for derivatives and child adjoint pointers 42 | blocklist myDers; 43 | blocklist myArgPtrs; 44 | 45 | // Storage for the nodes 46 | blocklist myNodes; 47 | 48 | // Padding so tapes in a vector don't interfere 49 | char myPad[64]; 50 | 51 | friend auto setNumResultsForAAD(const bool, const size_t); 52 | friend struct numResultsResetterForAAD; 53 | friend class Number; 54 | 55 | public: 56 | 57 | // Build note in place and return a pointer 58 | // N : number of childs (arguments) 59 | template 60 | Node* recordNode() 61 | { 62 | // Construct the node in place on tape 63 | Node* node = myNodes.emplace_back(N); 64 | 65 | // Store and zero the adjoint(s) 66 | if (multi) 67 | { 68 | node->pAdjoints = myAdjointsMulti.emplace_back_multi(Node::numAdj); 69 | fill(node->pAdjoints, node->pAdjoints + Node::numAdj, 0.0); 70 | } 71 | 72 | // Store the derivatives and child adjoint pointers unless leaf 73 | if constexpr(N>0) 74 | { 75 | node->pDerivatives = myDers.emplace_back_multi(); 76 | node->pAdjPtrs = myArgPtrs.emplace_back_multi(); 77 | 78 | } 79 | 80 | return node; 81 | } 82 | 83 | // Reset all adjoints to 0 84 | void resetAdjoints() 85 | { 86 | if (multi) 87 | { 88 | myAdjointsMulti.memset(0); 89 | } 90 | else 91 | { 92 | for (Node& node : myNodes) 93 | { 94 | node.mAdjoint = 0; 95 | } 96 | } 97 | } 98 | 99 | // Clear 100 | void clear() 101 | { 102 | myAdjointsMulti.clear(); 103 | myDers.clear(); 104 | myArgPtrs.clear(); 105 | myNodes.clear(); 106 | } 107 | 108 | // Rewind 109 | void rewind() 110 | { 111 | 112 | #ifdef _DEBUG 113 | 114 | // In debug mode, always wipe 115 | // makes it easier to identify errors 116 | 117 | clear(); 118 | 119 | #else 120 | // In release mode, rewind and reuse 121 | 122 | if (multi) 123 | { 124 | myAdjointsMulti.rewind(); 125 | } 126 | myDers.rewind(); 127 | myArgPtrs.rewind(); 128 | myNodes.rewind(); 129 | 130 | #endif 131 | 132 | } 133 | 134 | // Set mark 135 | void mark() 136 | { 137 | if (multi) 138 | { 139 | myAdjointsMulti.setmark(); 140 | } 141 | myDers.setmark(); 142 | myArgPtrs.setmark(); 143 | myNodes.setmark(); 144 | } 145 | 146 | // Rewind to mark 147 | void rewindToMark() 148 | { 149 | if (multi) 150 | { 151 | myAdjointsMulti.rewind_to_mark(); 152 | } 153 | myDers.rewind_to_mark(); 154 | myArgPtrs.rewind_to_mark(); 155 | myNodes.rewind_to_mark(); 156 | } 157 | 158 | // Iterators 159 | 160 | using iterator = blocklist::iterator; 161 | 162 | auto begin() 163 | { 164 | return myNodes.begin(); 165 | } 166 | 167 | auto end() 168 | { 169 | return myNodes.end(); 170 | } 171 | 172 | auto markIt() 173 | { 174 | return myNodes.mark(); 175 | } 176 | 177 | auto find(Node* node) 178 | { 179 | return myNodes.find(node); 180 | } 181 | }; -------------------------------------------------------------------------------- /AutocallPricer.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/AutocallPricer.xlsx -------------------------------------------------------------------------------- /ConcurrentQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Concurrent queue of chapter 3, 4 | // Used in the thread pool 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | template 11 | class ConcurrentQueue 12 | { 13 | 14 | queue myQueue; 15 | mutable mutex myMutex; 16 | condition_variable myCV; 17 | bool myInterrupt; 18 | 19 | public: 20 | 21 | ConcurrentQueue() : myInterrupt(false) {} 22 | ~ConcurrentQueue() { interrupt(); } 23 | 24 | bool empty() const 25 | { 26 | // Lock 27 | lock_guard lk(myMutex); 28 | // Access underlying queue 29 | return myQueue.empty(); 30 | } // Unlock 31 | 32 | // Pop into argument 33 | bool tryPop(T& t) 34 | { 35 | // Lock 36 | lock_guard lk(myMutex); 37 | if (myQueue.empty()) return false; 38 | // Move from queue 39 | t = move(myQueue.front()); 40 | // Combine front/pop 41 | myQueue.pop(); 42 | 43 | return true; 44 | } // Unlock 45 | 46 | // Pass t byVal or move with push( move( t)) 47 | void push(T t) 48 | { 49 | { 50 | // Lock 51 | lock_guard lk(myMutex); 52 | // Move into queue 53 | myQueue.push(move(t)); 54 | } // Unlock before notification 55 | 56 | // Unlock before notification 57 | myCV.notify_one(); 58 | } 59 | 60 | // Wait if empty 61 | bool pop(T& t) 62 | { 63 | // (Unique) lock 64 | unique_lock lk(myMutex); 65 | 66 | // Wait if empty, release lock until notified 67 | while (!myInterrupt && myQueue.empty()) myCV.wait(lk); 68 | 69 | // Re-acquire lock, resume 70 | 71 | // Check for interruption 72 | if (myInterrupt) return false; 73 | 74 | // Combine front/pop 75 | t = move(myQueue.front()); 76 | myQueue.pop(); 77 | 78 | return true; 79 | 80 | } // Unlock 81 | 82 | void interrupt() 83 | { 84 | { 85 | lock_guard lk(myMutex); 86 | myInterrupt = true; 87 | } 88 | myCV.notify_all(); 89 | } 90 | 91 | void resetInterrupt() 92 | { 93 | myInterrupt = false; 94 | } 95 | 96 | void clear() 97 | { 98 | queue empty; 99 | swap(myQueue, empty); 100 | } 101 | }; -------------------------------------------------------------------------------- /Intro2AADinMachineLearningAndFinance.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/Intro2AADinMachineLearningAndFinance.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Companion code for "Modern Computational Finance: AAD and Parallel Simulations" (Antoine Savine, Wiley, 2018) 2 | 3 | ![Screenshot](back.jpg) 4 | 5 | This is the professional implementation in C++ of the book Modern Computational Finance: AAD and Parallel Simulations by Antoine Savine. The code is freely available to anyone. Any person who purchased a copy of the book is authorized to use, modify and distribute the code for any application, as long as the credits remain on the top of the files. 6 | 7 | In this repository, readers will find: 8 | 9 | The source code listed or referenced in the publication. 10 | 11 | The files AAD*.* (with a dependency on gaussians.h for the analytic differentiation of Gaussian functions, and blocklist.h for memory management, both included) constitute a self contained, general purpose AAD library. The code builds on the advanced techniques exposed in this publication, in particular those of chapters 10, 14 and 15 to produce a particularly fast differentiation library, applicable to many contexts. The code is progressively built and explained in part III. 12 | 13 | The files mc*.* (with dependency on various utility files, all included in the project) form a generic, parallel, financial simulation library. The code and its theoretical foundations are described in part II. 14 | Various files with support code for memory management, interpolation or concurrent data structures, such as threadPool.h, which is developed in part I and used throughout the book to execute tasks in parallel. 15 | 16 | A file main.h that lists all the higher level functions that provide an entry point into the combined library. 17 | 18 | A Visual Studio 2017 project wrapping all the source files, with project settings correctly set for maximum optimization. The code uses some C++ 17 constructs, so the project setting "C++ Language Standard" on the project property "C/C++ / Language / C++ Language Standard" must be set to "ISO C++ 17 standard". This setting is correctly set on the project file xlComp.vcxproj, but readers who compile the files by other means must be aware of this. 19 | 20 | A number of xl*.* files that contain utilities and wrappers to export the main functions to Excel, as a particularly convenient front end for the library. The project file xlComp.vcxproj is set to build an xll, a file that is opened from Excel and makes the exported library functions callable from Excel like its standard functions. We wrote a tutorial that explains how to export C++ code to Excel. The tutorial ExportingCpp2xl.pdf is available in the the folder xlCpp along with the necessary source files. The wrapper xlExport.cpp file in our project precisely follows the directives of the tutorial and readers can inspect it to better understand these techniques. 21 | 22 | Finally, we provide a pre-built xlComp.xll (to run xlComp.xll, readers may need to install Visual Studio redistributables VC_redist.x86.exe and VC_redist.x64.exe, also included in the repository) and a spreadsheet xlTest.xlsx that demonstrates the main functions of the library. All the figures and numerical results in this publication were obtained with this spreadsheet and this xll, so readers can reproduce them immediately. The computation times were measured on an iMac Pro (Xeon W 2140B, 8 cores, 3.20 GHz, 4.20 max) running Windows 10. We also carefully checked that we have \emph{consistent} calculation times on a recent quad core laptop (Surface Book 2, i7-8650U, 4 cores, 1.90 GHz, 4.20 max), that is, (virtually) identical time in single threaded mode, twice the time in multi-threaded mode. 23 | 24 | The code is entirely written in standard C++, and compiles on Visual Studio 2017 out of the box, without any dependency to a third party library. 25 | 26 | The branch 'AADBook' is frozen and reflects the code in the book as published. The master branch may evolve. Other branches contain specific implementations based on the library. For example, the 'MutliAssets' branch contains developments to extend the library to support multiple underlying assets, like basket options or autocalls. They will eventually merge into Master but not AADBook. 27 | 28 | # Comp Fin Lecture 29 | # Computational Finance and Machine Learning in Finance 30 | 31 | The repo 'CompFinLecture' contains the slides and material for the lectures based on the book. This is a softer introduction to some of the themes covered in the book, which also introduces deep learning and its application to derivatives finance, and establishes parallels between the back-propagation algorithm, at the core of deep learning, and AAD. This parallel, in turn, provides further intuition into the mechanics of AAD. 32 | 33 | These lectures are delivered as courses or workshops at Copenhagen University, Aarhus University and Kings College London. The lecture notes, C++ code and TensorFlow notebooks are freely available in the 'CompFinLectures' repo. 34 | 35 | The lectures demonstrate AAD and its application to finance with "toy code", which is particularly easy to understand and reproduce, but is not efficient or scalable to professional standard, and not suitable for production. The code in this repo ('CompFinance'), on the contrary, is efficient, compliant with professional C++ development standards and designed to scale to production. 36 | -------------------------------------------------------------------------------- /ThreadPool.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Antoine Savine in 2018 3 | 4 | This code is the strict IP of Antoine Savine 5 | 6 | License to use and alter this code for personal and commercial applications 7 | is freely granted to any person or company who purchased a copy of the book 8 | 9 | Modern Computational Finance: AAD and Parallel Simulations 10 | Antoine Savine 11 | Wiley, 2018 12 | 13 | As long as this comment is preserved at the top of the file 14 | */ 15 | 16 | #include "ThreadPool.h" 17 | 18 | // Statics 19 | ThreadPool ThreadPool::myInstance; 20 | thread_local size_t ThreadPool::myTLSNum = 0; -------------------------------------------------------------------------------- /VC_redist.x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/VC_redist.x64.exe -------------------------------------------------------------------------------- /VC_redist.x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/VC_redist.x86.exe -------------------------------------------------------------------------------- /Workshop/net1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/Workshop/net1.png -------------------------------------------------------------------------------- /Workshop/reval.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/Workshop/reval.xlsx -------------------------------------------------------------------------------- /Workshop/testWithToyCode.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/Workshop/testWithToyCode.xlsx -------------------------------------------------------------------------------- /analytics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gaussians.h" 4 | 5 | // Black and Scholes formula, templated 6 | 7 | // Price 8 | template 9 | inline T blackScholes( 10 | const U spot, 11 | const V strike, 12 | const T vol, 13 | const W mat) 14 | { 15 | const auto std = vol * sqrt(mat); 16 | if (std <= EPS) return max(T(0.0), T(spot - strike)); 17 | const auto d2 = log(spot / strike) / std - 0.5 * std; 18 | const auto d1 = d2 + std; 19 | return spot * normalCdf(d1) - strike * normalCdf(d2); 20 | } 21 | 22 | // Implied vol, untemplated 23 | inline double blackScholesIvol( 24 | const double spot, 25 | const double strike, 26 | const double prem, 27 | const double mat) 28 | { 29 | if (prem <= max(0.0, spot - strike) + EPS) return 0.0; 30 | 31 | double p, pu, pl; 32 | double u = 0.5; 33 | while (blackScholes(spot, strike, u, mat) < prem) u *= 2; 34 | double l = 0.05; 35 | while (blackScholes(spot, strike, l, mat) > prem) l /= 2; 36 | pu = blackScholes(spot, strike, u, mat); 37 | blackScholes(spot, strike, l, mat); 38 | 39 | while (u - l > 1.e-12) 40 | { 41 | const double m = 0.5 * (u + l); 42 | p = blackScholes(spot, strike, m, mat); 43 | if (p > prem) 44 | { 45 | u = m; 46 | pu = p; 47 | } 48 | else 49 | { 50 | l = m; 51 | pl = p; 52 | } 53 | } 54 | 55 | return l + (prem - pl) / (pu - pl) * (u - l); 56 | } 57 | 58 | // Merton, templated 59 | 60 | template 61 | inline T merton( 62 | const U spot, 63 | const V strike, 64 | const T vol, 65 | const W mat, 66 | const X intens, 67 | const X meanJmp, 68 | const X stdJmp) 69 | { 70 | const auto varJmp = stdJmp * stdJmp; 71 | const auto mv2 = meanJmp + 0.5 * varJmp; 72 | const auto comp = intens * (exp(mv2) - 1); 73 | const auto var = vol * vol; 74 | const auto intensT = intens * mat; 75 | 76 | unsigned fact = 1; 77 | X iT = 1.0; 78 | const size_t cut = 10; 79 | T result = 0.0; 80 | for (size_t n = 0; n < cut; ++n) 81 | { 82 | const auto s = spot*exp(n*mv2 - comp*mat); 83 | const auto v = sqrt(var + n * varJmp / mat); 84 | const auto prob = exp(-intensT) * iT / fact; 85 | result += prob * blackScholes(s, strike, v, mat); 86 | fact *= n + 1; 87 | iT *= intensT; 88 | } 89 | 90 | return result; 91 | } 92 | 93 | // Up and out call in Black-Scholes, untemplated 94 | 95 | inline double BlackScholesKO( 96 | const double spot, 97 | const double rate, 98 | const double div, 99 | const double strike, 100 | const double barrier, 101 | const double mat, 102 | const double vol) 103 | { 104 | const double std = vol * sqrt(mat); 105 | const double fwdFact = exp((rate - div)*mat); 106 | const double fwd = spot * fwdFact; 107 | const double disc = exp(-rate * mat); 108 | const double v = rate - div - 0.5 * vol * vol; 109 | const double d2 = (log(spot / barrier) + v * mat) / std; 110 | const double d2prime = (log(barrier / spot) + v * mat) / std; 111 | 112 | const double bar = blackScholes(fwd, strike, vol, mat) 113 | - blackScholes(fwd, barrier, vol, mat) 114 | - (barrier - strike) * normalCdf(d2) 115 | - pow(barrier / spot, 2 * v / vol / vol) * 116 | ( 117 | blackScholes(fwdFact * barrier* barrier / spot, strike, vol, mat) 118 | - blackScholes(fwdFact * barrier* barrier / spot, barrier, vol, mat) 119 | - (barrier - strike) * normalCdf(d2prime) 120 | ); 121 | 122 | return disc * bar; 123 | } 124 | -------------------------------------------------------------------------------- /back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asavine/CompFinance/6538e90c95993eebac6b728f1bf28b877bec9b5d/back.jpg -------------------------------------------------------------------------------- /blocklist.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #pragma once 18 | #pragma warning(disable : 4018) 19 | 20 | // Blocklist data structure for AAD memory management 21 | // See chapter 10, unchanged with expression templates of chapter 15 22 | 23 | #include 24 | #include 25 | #include 26 | using namespace std; 27 | 28 | template 29 | class blocklist 30 | { 31 | // Container = list of blocks 32 | list> data; 33 | 34 | using list_iter = decltype(data.begin()); 35 | using block_iter = decltype(data.back().begin()); 36 | 37 | // Current block 38 | list_iter cur_block; 39 | 40 | // Last block 41 | list_iter last_block; 42 | 43 | // Next free space in current block 44 | block_iter next_space; 45 | 46 | // Last free space (+1) in current block 47 | block_iter last_space; 48 | 49 | // Mark 50 | list_iter marked_block; 51 | block_iter marked_space; 52 | 53 | // Create new array 54 | void newblock() 55 | { 56 | data.emplace_back(); 57 | cur_block = last_block = prev(data.end()); 58 | next_space = cur_block->begin(); 59 | last_space = cur_block->end(); 60 | } 61 | 62 | // Move on to next array 63 | void nextblock() 64 | { 65 | // This is the last array: create new 66 | if (cur_block == last_block) 67 | { 68 | newblock(); 69 | } 70 | else 71 | { 72 | ++cur_block; 73 | next_space = cur_block->begin(); 74 | last_space = cur_block->end(); 75 | } 76 | } 77 | 78 | public: 79 | 80 | // Create first block on construction 81 | blocklist() 82 | { 83 | newblock(); 84 | } 85 | 86 | // Factory reset 87 | void clear() 88 | { 89 | data.clear(); 90 | newblock(); 91 | } 92 | 93 | // Rewind but keep all blocks 94 | void rewind() 95 | { 96 | cur_block = data.begin(); 97 | next_space = cur_block->begin(); 98 | last_space = cur_block->end(); 99 | } 100 | 101 | // Memset 102 | void memset(unsigned char value = 0) 103 | { 104 | for (auto& arr : data) 105 | { 106 | std::memset(&arr[0], value, block_size * sizeof(T)); 107 | } 108 | } 109 | 110 | // Construct object of type T in place 111 | // in the next free space and return a pointer on it 112 | // Implements perfect forwarding of constructor arguments 113 | template 114 | T* emplace_back(Args&& ...args) 115 | { 116 | // No more space in current array 117 | if (next_space == last_space) 118 | { 119 | nextblock(); 120 | } 121 | // Placement new, construct in memory pointed by next 122 | T* emplaced = new (&*next_space) // memory pointed by next as T* 123 | T(forward(args)...); // perfect forwarding of ctor arguments 124 | 125 | // Advance next 126 | ++next_space; 127 | 128 | // Return 129 | return emplaced; 130 | } 131 | 132 | // Overload for default constructed 133 | T* emplace_back() 134 | { 135 | // No more space in current array 136 | if (next_space == last_space) 137 | { 138 | nextblock(); 139 | } 140 | 141 | // Current space 142 | auto old_next = next_space; 143 | 144 | // Advance next 145 | ++next_space; 146 | 147 | // Return 148 | return &*old_next; 149 | } 150 | 151 | // Stores n default constructed elements 152 | // and returns a pointer on the first 153 | 154 | // Version 1: n known at compile time 155 | template 156 | T* emplace_back_multi() 157 | { 158 | // No more space in current array 159 | if (distance(next_space, last_space) < n) 160 | { 161 | nextblock(); 162 | } 163 | 164 | // Current space 165 | auto old_next = next_space; 166 | 167 | // Advance next 168 | next_space += n; 169 | 170 | // Return 171 | return &*old_next; 172 | } 173 | 174 | // Version 2: n unknown at compile time 175 | T* emplace_back_multi(const size_t n) 176 | { 177 | // No more space in current array 178 | if (distance(next_space, last_space) < n) 179 | { 180 | nextblock(); 181 | } 182 | 183 | // Current space 184 | auto old_next = next_space; 185 | 186 | // Advance next 187 | next_space += n; 188 | 189 | // Return 190 | return &*old_next; 191 | } 192 | 193 | // Marks 194 | 195 | // Set mark 196 | void setmark() 197 | { 198 | if (next_space == last_space) 199 | { 200 | nextblock(); 201 | } 202 | 203 | marked_block = cur_block; 204 | marked_space = next_space; 205 | } 206 | 207 | // Rewind to mark 208 | void rewind_to_mark() 209 | { 210 | cur_block = marked_block; 211 | next_space = marked_space; 212 | last_space = cur_block->end(); 213 | } 214 | 215 | // Iterator 216 | 217 | class iterator 218 | { 219 | // List and block 220 | list_iter cur_block; // current block 221 | block_iter cur_space; // current space 222 | block_iter first_space; // first space in block 223 | block_iter last_space; // last (+1) space in block 224 | 225 | public: 226 | 227 | // iterator traits 228 | using difference_type = ptrdiff_t; 229 | using reference = T&; 230 | using pointer = T*; 231 | using value_type = T; 232 | using iterator_category = bidirectional_iterator_tag; 233 | 234 | // Default constructor 235 | iterator() {} 236 | 237 | // Constructor 238 | iterator(list_iter cb, block_iter cs, block_iter fs, block_iter ls) : 239 | cur_block(cb), cur_space(cs), first_space(fs), last_space(ls) {} 240 | 241 | // Pre-increment (we do not provide post) 242 | iterator& operator++() 243 | { 244 | ++cur_space; 245 | if (cur_space == last_space) 246 | { 247 | ++cur_block; 248 | first_space = cur_block->begin(); 249 | last_space = cur_block->end(); 250 | cur_space = first_space; 251 | } 252 | 253 | return *this; 254 | } 255 | 256 | // Pre-decrement 257 | iterator& operator--() 258 | { 259 | if (cur_space == first_space) 260 | { 261 | --cur_block; 262 | first_space = cur_block->begin(); 263 | last_space = cur_block->end(); 264 | cur_space = last_space; 265 | } 266 | 267 | --cur_space; 268 | 269 | return *this; 270 | } 271 | 272 | // Access to contained elements 273 | T& operator*() 274 | { 275 | return *cur_space; 276 | } 277 | const T& operator*() const 278 | { 279 | return *cur_space; 280 | } 281 | T* operator->() 282 | { 283 | return &*cur_space; 284 | } 285 | const T* operator->() const 286 | { 287 | return &*cur_space; 288 | } 289 | 290 | // Check equality 291 | bool operator ==(const iterator& rhs) const 292 | { 293 | return (cur_block == rhs.cur_block && cur_space == rhs.cur_space); 294 | } 295 | bool operator !=(const iterator& rhs) const 296 | { 297 | return (cur_block != rhs.cur_block|| cur_space != rhs.cur_space); 298 | } 299 | }; 300 | 301 | // Access to iterators 302 | 303 | iterator begin() 304 | { 305 | return iterator(data.begin(), data.begin()->begin(), 306 | data.begin()->begin(), data.begin()->end()); 307 | } 308 | 309 | iterator end() 310 | { 311 | return iterator(cur_block, next_space, 312 | cur_block->begin(), cur_block->end()); 313 | } 314 | 315 | // Iterator on mark 316 | iterator mark() 317 | { 318 | return iterator(marked_block, marked_space, 319 | marked_block->begin(), marked_block->end()); 320 | } 321 | 322 | // Find element, by pointer, searching sequentially from the end 323 | iterator find(const T* const element) 324 | { 325 | // Search from the end 326 | iterator it = end(); 327 | iterator b = begin(); 328 | 329 | while (it != b) 330 | { 331 | --it; 332 | if (&*it == element) return it; 333 | } 334 | 335 | if (&*it == element) return it; 336 | 337 | return end(); 338 | } 339 | }; -------------------------------------------------------------------------------- /choldc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Choleski decomposition, inspired by Numerical Recipes 4 | 5 | #include "matrix.h" 6 | 7 | template 8 | void choldc(const matrix& in, matrix& out) 9 | { 10 | int n = in.rows(); 11 | T sum; 12 | 13 | fill(out.begin(), out.end(), T(0.0)); 14 | 15 | for(int i=0; i 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #define EPS 1.0e-08 9 | 10 | // Gaussian functions 11 | 12 | // Normal density 13 | inline double normalDens(const double x) 14 | { 15 | return x<-10.0 || 10.0 10.0) return 1.0; 25 | if (x < 0.0) return 1.0 - normalCdf(-x); 26 | 27 | static constexpr double p = 0.2316419; 28 | static constexpr double b1 = 0.319381530; 29 | static constexpr double b2 = -0.356563782; 30 | static constexpr double b3 = 1.781477937; 31 | static constexpr double b4 = -1.821255978; 32 | static constexpr double b5 = 1.330274429; 33 | 34 | const auto t = 1.0 / (1.0 + p*x); 35 | 36 | const auto pol = t*(b1 + t*(b2 + t*(b3 + t*(b4 + t*b5)))); 37 | 38 | const auto pdf = normalDens(x); 39 | 40 | return 1.0 - pdf * pol; 41 | } 42 | 43 | // Inverse CDF (for generation of Gaussians out of Uniforms) 44 | // Beasley-Springer-Moro algorithm 45 | // Moro, The full Monte, Risk, 1995 46 | // See Glasserman, Monte Carlo Methods in Financial Engineering, p 68 47 | inline double invNormalCdf(const double p) 48 | { 49 | const bool sup = p > 0.5; 50 | const double up = sup ? 1.0 - p : p; 51 | 52 | static constexpr double a0 = 2.50662823884; 53 | static constexpr double a1 = -18.61500062529; 54 | static constexpr double a2 = 41.39119773534; 55 | static constexpr double a3 = -25.44106049637; 56 | 57 | static constexpr double b0 = -8.47351093090; 58 | static constexpr double b1 = 23.08336743743; 59 | static constexpr double b2 = -21.06224101826; 60 | static constexpr double b3 = 3.13082909833; 61 | 62 | static constexpr double c0 = 0.3374754822726147; 63 | static constexpr double c1 = 0.9761690190917186; 64 | static constexpr double c2 = 0.1607979714918209; 65 | static constexpr double c3 = 0.0276438810333863; 66 | static constexpr double c4 = 0.0038405729373609; 67 | static constexpr double c5 = 0.0003951896511919; 68 | static constexpr double c6 = 0.0000321767881768; 69 | static constexpr double c7 = 0.0000002888167364; 70 | static constexpr double c8 = 0.0000003960315187; 71 | 72 | double x = up - 0.5; 73 | double r; 74 | 75 | if (fabs(x)<0.42) 76 | { 77 | r = x*x; 78 | r = x*(((a3*r + a2)*r + a1)*r + a0) / ((((b3*r + b2)*r + b1)*r + b0)*r + 1.0); 79 | return sup ? -r: r; 80 | } 81 | 82 | r = up; 83 | r = log(-log(r)); 84 | r = c0 + r*(c1 + r*(c2 + r*(c3 + r*(c4 + r*(c5 + r*(c6 + r*(c7 + r*c8))))))); 85 | 86 | return sup? r: -r; 87 | } 88 | -------------------------------------------------------------------------------- /interp.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | using namespace std; 21 | 22 | // Interpolation utility 23 | 24 | // Interpolates the vector y against knots x in value x0 25 | // Interpolation is linear or smooth, extrapolation is flat 26 | template 27 | inline auto interp( 28 | // sorted on xs 29 | ITX xBegin, 30 | ITX xEnd, 31 | // corresponding ys 32 | ITY yBegin, 33 | ITY yEnd, 34 | // interpolate for point x0 35 | const T& x0) 36 | ->remove_reference_t 37 | { 38 | // STL binary search, returns iterator on 1st no less than x0 39 | // upper_bound guarantees logarithmic search 40 | auto it = upper_bound(xBegin, xEnd, x0); 41 | 42 | // Extrapolation? 43 | if (it == xEnd) return *(yEnd - 1); 44 | if (it == xBegin) return *yBegin; 45 | 46 | // Interpolation 47 | size_t n = distance(xBegin, it) - 1; 48 | auto x1 = xBegin[n]; 49 | auto y1 = yBegin[n]; 50 | auto x2 = xBegin[n + 1]; 51 | auto y2 = yBegin[n + 1]; 52 | 53 | auto t = (x0 - x1) / (x2 - x1); 54 | 55 | if constexpr (smoothStep) 56 | { 57 | return y1 + (y2 - y1) * t * t * (3.0 - 2 * t); 58 | } 59 | else 60 | { 61 | return y1 + (y2 - y1) * t; 62 | } 63 | } 64 | 65 | // 2D 66 | template 67 | inline V interp2D( 68 | // sorted on xs 69 | const vector& x, 70 | // sorted on ys 71 | const vector& y, 72 | // zs in a matrix 73 | const matrix& z, 74 | // interpolate for point (x0,y0) 75 | const W& x0, 76 | const X& y0) 77 | { 78 | const size_t n = x.size(); 79 | const size_t m = y.size(); 80 | 81 | // STL binary search, returns iterator on 1st no less than x0 82 | // upper_boung guarantees logarithmic search 83 | auto it = upper_bound(x.begin(), x.end(), x0); 84 | const size_t n2 = distance(x.begin(), it); 85 | 86 | // Extrapolation in x? 87 | if (n2 == n) 88 | return interp(y.begin(), y.end(), z[n2 - 1], z[n2 - 1] + m, y0); 89 | if (n2 == 0) 90 | return interp(y.begin(), y.end(), z[0], z[0] + m, y0); 91 | 92 | // Interpolation in x 93 | const size_t n1 = n2 - 1; 94 | auto x1 = x[n1]; 95 | auto x2 = x[n2]; 96 | auto z1 = interp(y.begin(), y.end(), z[n1], z[n1] + m, y0); 97 | auto z2 = interp(y.begin(), y.end(), z[n2], z[n2] + m, y0); 98 | 99 | // Smooth step 100 | auto t = (x0 - x1) / (x2 - x1); 101 | if constexpr (smoothStep) 102 | { 103 | return z1 + (z2 - z1) * t * t * (3.0 - 2 * t); 104 | } 105 | else 106 | { 107 | return z1 + (z2 - z1) * t;; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /ivs.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Written by Antoine Savine in 2018 4 | 5 | This code is the strict IP of Antoine Savine 6 | 7 | License to use and alter this code for personal and commercial applications 8 | is freely granted to any person or company who purchased a copy of the book 9 | 10 | Modern Computational Finance: AAD and Parallel Simulations 11 | Antoine Savine 12 | Wiley, 2018 13 | 14 | As long as this comment is preserved at the top of the file 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "mcBase.h" 20 | #include "matrix.h" 21 | #include "analytics.h" 22 | 23 | // Implied Volatility Surfaces and Risk Views, 24 | // See chapter 13 25 | 26 | // Risk view 27 | template 28 | class RiskView 29 | { 30 | bool myEmpty; 31 | 32 | vector myStrikes; 33 | vector