Skip to content

Commit f7c029e

Browse files
authored
Add native version of black scholes algo as an example (#572)
* Add native version of black scholes algo as an examples
1 parent 0774ab6 commit f7c029e

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-0
lines changed

dpnp/backend/examples/example_bs.cpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//*****************************************************************************
2+
// Copyright (c) 2016-2020, Intel Corporation
3+
// All rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are met:
7+
// - Redistributions of source code must retain the above copyright notice,
8+
// this list of conditions and the following disclaimer.
9+
// - Redistributions in binary form must reproduce the above copyright notice,
10+
// this list of conditions and the following disclaimer in the documentation
11+
// and/or other materials provided with the distribution.
12+
//
13+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
// THE POSSIBILITY OF SUCH DAMAGE.
24+
//*****************************************************************************
25+
26+
/**
27+
* Example BS.
28+
*
29+
* This example shows simple usage of the DPNP C++ Backend library
30+
* to calculate black scholes algorithm like in Python version
31+
*
32+
* Possible compile line:
33+
* clang++ -g -fPIC dpnp/backend/examples/example_bs.cpp -Idpnp -Idpnp/backend/include -Ldpnp -Wl,-rpath='$ORIGIN'/dpnp -ldpnp_backend_c -o example_bs
34+
*
35+
*/
36+
37+
#include <iostream>
38+
#include <cmath>
39+
40+
#include "dpnp_iface.hpp"
41+
42+
double* black_scholes_put(double* S, double* K, double* T, double* sigmas, double* r_sigma_sigma_2,
43+
double* nrs, double* sqrt2, double* ones, double* twos, const size_t size)
44+
{
45+
double* d1 = (double*)dpnp_memory_alloc_c(size * sizeof(double));
46+
dpnp_divide_c<double, double, double>(S, K, d1, size); // S/K
47+
dpnp_log_c<double, double>(d1, d1, size); // np.log(S/K)
48+
49+
double* bs_put = (double*)dpnp_memory_alloc_c(size * sizeof(double));
50+
dpnp_multiply_c<double, double, double>(r_sigma_sigma_2, T, bs_put, size); // r_sigma_sigma_2*T
51+
dpnp_add_c<double, double, double>(d1, bs_put, d1, size); // np.log(S/K) + r_sigma_sigma_2*T
52+
53+
dpnp_sqrt_c<double, double>(T, bs_put, size); // np.sqrt(T)
54+
dpnp_multiply_c<double, double, double>(sigmas, bs_put, bs_put, size); // sigmas*np.sqrt(T)
55+
56+
// (np.log(S/K) + r_sigma_sigma_2*T) / (sigmas*np.sqrt(T))
57+
dpnp_divide_c<double, double, double>(d1, bs_put, d1, size);
58+
59+
double* d2 = (double*)dpnp_memory_alloc_c(size * sizeof(double));
60+
dpnp_sqrt_c<double, double>(T, bs_put, size); // np.sqrt(T)
61+
dpnp_multiply_c<double, double, double>(sigmas, bs_put, bs_put, size); // sigmas*np.sqrt(T)
62+
dpnp_subtract_c<double, double, double>(d1, bs_put, d2, size); // d1 - sigmas*np.sqrt(T)
63+
64+
double* cdf_d1 = (double*)dpnp_memory_alloc_c(size * sizeof(double));
65+
dpnp_divide_c<double, double, double>(d1, sqrt2, cdf_d1, size); // d1 / sqrt2
66+
dpnp_erf_c<double>(cdf_d1, cdf_d1, size); // np.erf(d1 / sqrt2)
67+
dpnp_add_c<double, double, double>(ones, cdf_d1, cdf_d1, size); // ones + np.erf(d1 / sqrt2)
68+
dpnp_add_c<double, double, double>(ones, cdf_d1, cdf_d1, size); // (ones + np.erf(d1 / sqrt2)) / twos
69+
dpnp_memory_free_c(d1);
70+
71+
double* cdf_d2 = (double*)dpnp_memory_alloc_c(size * sizeof(double));
72+
dpnp_divide_c<double, double, double>(d2, sqrt2, cdf_d2, size); // d2 / sqrt2
73+
dpnp_erf_c<double>(cdf_d2, cdf_d2, size); // np.erf(d2 / sqrt2)
74+
dpnp_add_c<double, double, double>(ones, cdf_d2, cdf_d2, size); // ones + np.erf(d2 / sqrt2)
75+
dpnp_add_c<double, double, double>(ones, cdf_d2, cdf_d2, size); // (ones + np.erf(d2 / sqrt2)) / twos
76+
dpnp_memory_free_c(d2);
77+
78+
double* bs_call = (double*)dpnp_memory_alloc_c(size * sizeof(double));
79+
dpnp_multiply_c<double, double, double>(S, cdf_d1, bs_call, size); // S*cdf_d1
80+
dpnp_memory_free_c(cdf_d1);
81+
82+
dpnp_multiply_c<double, double, double>(nrs, T, bs_put, size); // nrs*T
83+
dpnp_exp_c<double, double>(bs_put, bs_put, size); // np.exp(nrs*T)
84+
dpnp_multiply_c<double, double, double>(K, bs_put, bs_put, size); // K*np.exp(nrs*T)
85+
86+
// K*np.exp(nrs*T)*cdf_d2
87+
dpnp_multiply_c<double, double, double>(bs_put, cdf_d2, bs_put, size);
88+
dpnp_memory_free_c(cdf_d2);
89+
90+
// S*cdf_d1 - K*np.exp(nrs*T)*cdf_d2
91+
dpnp_subtract_c<double, double, double>(bs_call, bs_put, bs_call, size);
92+
93+
dpnp_multiply_c<double, double, double>(nrs, T, bs_put, size); // nrs*T
94+
dpnp_exp_c<double, double>(bs_put, bs_put, size); // np.exp(nrs*T)
95+
dpnp_multiply_c<double, double, double>(K, bs_put, bs_put, size); // K*np.exp(nrs*T)
96+
dpnp_subtract_c<double, double, double>(bs_put, S, bs_put, size); // K*np.exp(nrs*T) - S
97+
dpnp_add_c<double, double, double>(bs_put, bs_call, bs_put, size); // K*np.exp(nrs*T) - S + bs_call
98+
dpnp_memory_free_c(bs_call);
99+
100+
return bs_put;
101+
}
102+
103+
int main(int, char**)
104+
{
105+
const size_t SIZE = 256;
106+
107+
const size_t SEED = 7777777;
108+
const long SL = 10, SH = 50;
109+
const long KL = 10, KH = 50;
110+
const long TL = 1, TH = 2;
111+
const double RISK_FREE = 0.1;
112+
const double VOLATILITY = 0.2;
113+
114+
dpnp_queue_initialize_c(QueueOptions::GPU_SELECTOR);
115+
std::cout << "SYCL queue is CPU: " << dpnp_queue_is_cpu_c() << std::endl;
116+
117+
double* S = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
118+
double* K = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
119+
double* T = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
120+
121+
dpnp_rng_srand_c(SEED);
122+
dpnp_rng_uniform_c<double>(S, SL, SH, SIZE); // np.random.uniform(SL, SH, SIZE)
123+
dpnp_rng_uniform_c<double>(K, KL, KH, SIZE); // np.random.uniform(KL, KH, SIZE)
124+
dpnp_rng_uniform_c<double>(T, TL, TH, SIZE); // np.random.uniform(TL, TH, SIZE)
125+
126+
double* r = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
127+
r[0] = RISK_FREE;
128+
129+
double* sigma = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
130+
sigma[0] = VOLATILITY;
131+
132+
double* rss2 = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
133+
rss2[0] = RISK_FREE + VOLATILITY*VOLATILITY/2.;
134+
135+
double* nr = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
136+
nr[0] = -RISK_FREE;
137+
138+
double* sq2 = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
139+
sq2[0] = sqrt(2.);
140+
141+
double* one = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
142+
one[0] = 1.;
143+
144+
double* two = (double*)dpnp_memory_alloc_c(1 * sizeof(double));
145+
two[0] = 2.;
146+
147+
double* sigmas = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
148+
double* r_sigma_sigma_2 = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
149+
double* nrs = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
150+
double* sqrt2 = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
151+
double* ones = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
152+
double* twos = (double*)dpnp_memory_alloc_c(SIZE * sizeof(double));
153+
154+
dpnp_full_c<double>(sigma, sigmas, SIZE); // np.full((SIZE,), sigma, dtype=DTYPE)
155+
dpnp_full_c<double>(rss2, r_sigma_sigma_2, SIZE); // np.full((SIZE,), r + sigma*sigma/2., dtype=DTYPE)
156+
dpnp_full_c<double>(nr, nrs, SIZE); // np.full((SIZE,), -r, dtype=DTYPE)
157+
dpnp_full_c<double>(sq2, sqrt2, SIZE); // np.full((SIZE,), np.sqrt(2), dtype=DTYPE)
158+
dpnp_full_c<double>(one, ones, SIZE); // np.full((SIZE,), 1, dtype=DTYPE)
159+
dpnp_full_c<double>(two, twos, SIZE); // np.full((SIZE,), 2, dtype=DTYPE)
160+
161+
dpnp_memory_free_c(one);
162+
dpnp_memory_free_c(two);
163+
dpnp_memory_free_c(sq2);
164+
dpnp_memory_free_c(nr);
165+
dpnp_memory_free_c(rss2);
166+
dpnp_memory_free_c(sigma);
167+
dpnp_memory_free_c(r);
168+
169+
double* bs_put = black_scholes_put(S, K, T, sigmas, r_sigma_sigma_2, nrs, sqrt2, ones, twos, SIZE);
170+
171+
std::cout << std::endl;
172+
for (size_t i = 0; i < 10; ++i)
173+
{
174+
std::cout << bs_put[i] << ", ";
175+
}
176+
std::cout << std::endl;
177+
178+
dpnp_memory_free_c(bs_put);
179+
180+
dpnp_memory_free_c(twos);
181+
dpnp_memory_free_c(ones);
182+
dpnp_memory_free_c(sqrt2);
183+
dpnp_memory_free_c(nrs);
184+
dpnp_memory_free_c(r_sigma_sigma_2);
185+
dpnp_memory_free_c(sigmas);
186+
187+
dpnp_memory_free_c(T);
188+
dpnp_memory_free_c(K);
189+
dpnp_memory_free_c(S);
190+
191+
return 0;
192+
}

examples/example_bs.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# cython: language_level=3
2+
# -*- coding: utf-8 -*-
3+
# *****************************************************************************
4+
# Copyright (c) 2016-2020, Intel Corporation
5+
# All rights reserved.
6+
#
7+
# Redistribution and use in source and binary forms, with or without
8+
# modification, are permitted provided that the following conditions are met:
9+
# - Redistributions of source code must retain the above copyright notice,
10+
# this list of conditions and the following disclaimer.
11+
# - Redistributions in binary form must reproduce the above copyright notice,
12+
# this list of conditions and the following disclaimer in the documentation
13+
# and/or other materials provided with the distribution.
14+
#
15+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25+
# THE POSSIBILITY OF SUCH DAMAGE.
26+
# *****************************************************************************
27+
28+
"""Example BS.
29+
30+
This example shows simple usage of the DPNP
31+
to calculate black scholes algorithm
32+
33+
"""
34+
35+
try:
36+
import dpnp as np
37+
except ImportError:
38+
import sys
39+
import os
40+
41+
root_dir = os.path.join(os.path.dirname(__file__), os.pardir)
42+
sys.path.append(root_dir)
43+
44+
import dpnp as np
45+
46+
47+
SIZE = 2 ** 20
48+
SHAPE = (SIZE,)
49+
DTYPE = np.float64
50+
51+
SEED = 7777777
52+
SL, SH = 10.0, 50.0
53+
KL, KH = 10.0, 50.0
54+
TL, TH = 1.0, 2.0
55+
RISK_FREE = 0.1
56+
VOLATILITY = 0.2
57+
58+
59+
def black_scholes_put(S, K, T, sigmas, r_sigma_sigma_2, nrs, sqrt2, ones, twos):
60+
d1 = (np.log(S/K) + r_sigma_sigma_2*T) / (sigmas*np.sqrt(T))
61+
d2 = d1 - sigmas * np.sqrt(T)
62+
63+
cdf_d1 = (ones + np.erf(d1 / sqrt2)) / twos
64+
cdf_d2 = (ones + np.erf(d2 / sqrt2)) / twos
65+
66+
bs_call = S*cdf_d1 - K*np.exp(nrs*T)*cdf_d2
67+
68+
return K*np.exp(nrs*T) - S + bs_call
69+
70+
71+
np.random.seed(SEED)
72+
S = np.random.uniform(SL, SH, SIZE)
73+
K = np.random.uniform(KL, KH, SIZE)
74+
T = np.random.uniform(TL, TH, SIZE)
75+
76+
r, sigma = RISK_FREE, VOLATILITY
77+
78+
sigmas = np.full(SHAPE, sigma, dtype=DTYPE)
79+
r_sigma_sigma_2 = np.full(SHAPE, r + sigma*sigma/2., dtype=DTYPE)
80+
nrs = np.full(SHAPE, -r, dtype=DTYPE)
81+
82+
sqrt2 = np.full(SHAPE, np.sqrt(2), dtype=DTYPE)
83+
ones = np.full(SHAPE, 1, dtype=DTYPE)
84+
twos = np.full(SHAPE, 2, dtype=DTYPE)
85+
86+
bs_put = black_scholes_put(S, K, T, sigmas, r_sigma_sigma_2, nrs, sqrt2, ones, twos)
87+
print(bs_put[:10])

0 commit comments

Comments
 (0)