1 /*
  2  * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package hat.test;
 26 
 27 import hat.Accelerator;
 28 import hat.ComputeContext;
 29 import hat.NDRange;
 30 
 31 import static hat.KernelContext.*;
 32 import hat.backend.Backend;
 33 import hat.buffer.F32Array;
 34 import jdk.incubator.code.Reflect;
 35 import hat.test.annotation.HatTest;
 36 import hat.test.exceptions.HATAsserts;
 37 
 38 import java.lang.invoke.MethodHandles;
 39 import java.util.Random;
 40 
 41 public class TestBlackscholes {
 42 
 43     @Reflect
 44     public static void blackScholesKernel(
 45             F32Array call, F32Array put,
 46             F32Array sArray, F32Array xArray, F32Array tArray,
 47             float r, float v) {
 48         if (GIX() < GSX()) {
 49             float S = sArray.array(GIX());
 50             float X = xArray.array(GIX());
 51             float T = tArray.array(GIX());
 52             float expNegRt = (float) Math.exp(-r * T);
 53             float d1 = (float) ((Math.log(S / X) + (r + v * v * .5f) * T) / (v * Math.sqrt(T)));
 54             float d2 = (float) (d1 - v * Math.sqrt(T));
 55             float cnd1 = CND(d1);
 56             float cnd2 = CND(d2);
 57             float value = S * cnd1 - expNegRt * X * cnd2;
 58             call.array(GIX(), value);
 59             put.array(GIX(), expNegRt * X * (1 - cnd2) - S * (1 - cnd1));
 60         }
 61     }
 62 
 63     @Reflect
 64     public static float CND(float input) {
 65         float x = input;
 66         if (input < 0f) {
 67             x = -input;
 68         }
 69         float term = 1f / (1f + (0.2316419f * x));
 70         float term_pow2 = term * term;
 71         float term_pow3 = term_pow2 * term;
 72         float term_pow4 = term_pow2 * term_pow2;
 73         float term_pow5 = term_pow2 * term_pow3;
 74         float part1 = (1f / (float)Math.sqrt(2f * 3.1415926535f)) * (float)Math.exp((-x * x) * 0.5f);
 75         float part2 = (0.31938153f * term) +
 76                 (-0.356563782f * term_pow2) +
 77                 (1.781477937f * term_pow3) +
 78                 (-1.821255978f * term_pow4) +
 79                 (1.330274429f * term_pow5);
 80         if (input >= 0f) {
 81             return 1f - part1 * part2;
 82         }
 83         return part1 * part2;
 84     }
 85 
 86     @Reflect
 87     public static void blackScholes(ComputeContext cc, F32Array call, F32Array put, F32Array S, F32Array X, F32Array T, float r, float v) {
 88         cc.dispatchKernel(NDRange.of1D(call.length()),()-> blackScholesKernel( call, put, S, X, T, r, v));
 89     }
 90 
 91     static F32Array floatArray(Accelerator accelerator, int size, float low, float high) {
 92         F32Array array = F32Array.create(accelerator, size);
 93         Random random = new Random();
 94         for (int i = 0; i <size; i++) {
 95             array.array(i, random.nextFloat() * (high - low) + low);
 96         }
 97         return array;
 98     }
 99 
100     public static void blackScholesKernelSeq(F32Array call, F32Array put, F32Array sArray, F32Array xArray, F32Array tArray, float r, float v) {
101         for (int i = 0; i <call.length() ; i++) {
102             float S = sArray.array(i);
103             float X = xArray.array(i);
104             float T = tArray.array(i);
105             float expNegRt = (float) Math.exp(-r * T);
106             float d1 = (float) ((Math.log(S / X) + (r + v * v * .5f) * T) / (v * Math.sqrt(T)));
107             float d2 = (float) (d1 - v * Math.sqrt(T));
108             float cnd1 = CND(d1);
109             float cnd2 = CND(d2);
110             float value = S * cnd1 - expNegRt * X * cnd2;
111             call.array(i, value);
112             put.array(i, expNegRt * X * (1 - cnd2) - S * (1 - cnd1));
113         }
114     }
115 
116     @HatTest
117     @Reflect
118     public void testBlackscholes() {
119         int size = 1024;
120         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
121         var call = F32Array.create(accelerator, size);
122         var put = F32Array.create(accelerator, size);
123         for (int i = 0; i < put.length(); i++) {
124             put.array(i, i);
125             call.array(i, i);
126         }
127 
128         var S = floatArray(accelerator, size,1f, 100f);
129         var X = floatArray(accelerator, size,1f, 100f);
130         var T = floatArray(accelerator,size, 0.25f, 10f);
131         float r = 0.02f;
132         float v = 0.30f;
133 
134         accelerator.compute(cc -> blackScholes(cc, call, put, S, X, T, r, v));
135 
136         var seqCall = F32Array.create(accelerator, size);
137         var seqPut = F32Array.create(accelerator, size);
138         for (int i = 0; i < seqCall.length(); i++) {
139             seqCall.array(i, i);
140             seqPut.array(i, i);
141         }
142 
143         blackScholesKernelSeq(seqCall, seqPut, S, X, T, r, v);
144 
145         for (int i = 0; i < call.length(); i++) {
146             HATAsserts.assertEquals(seqCall.array(i), call.array(i), 0.01f);
147             HATAsserts.assertEquals(seqPut.array(i), put.array(i), 0.01f);
148         }
149     }
150 }