Python调用cuRandSobol生成Sobol

Sobol低偏差序列期权蒙特卡洛估值中非常有用。scipyqmc模块提供相关函数,但是速度比普通的伪随机数要慢cuRand提供了sobol生成器,速度很快,但是cupy目前还没有集成scipy下面的qmc模块在cupy中没有对应。Python下想使用cuRandSobol目前还没有特别好用的模块所以我们可以用c++编写共享库,然后通过Python的Ctypes方式调用。cuRandSobolscipyqmc的Sobol算法都是JoeKuoD6,支持的最大维度21201

首先编写一个gen_sobol.cu文件

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <vector>

#include <cuda_runtime.h>
#include <curand.h>

// CUDA API error checking
#define CUDA_CHECK(err)                                                        \
  do {                                                                         \
    cudaError_t err_ = (err);                                                  \
    if (err_ != cudaSuccess) {                                                 \
      std::printf("CUDA error %d at %s:%d\n", err_, __FILE__, __LINE__);       \
      throw std::runtime_error("CUDA error");                                  \
    }                                                                          \
  } while (0)

// curand API error checking
#define CURAND_CHECK(err)                                                      \
  do {                                                                         \
    curandStatus_t err_ = (err);                                               \
    if (err_ != CURAND_STATUS_SUCCESS) {                                       \
      std::printf("curand error %d at %s:%d\n", err_, __FILE__, __LINE__);     \
      throw std::runtime_error("curand error");                                \
    }                                                                          \
  } while (0)


using data_type = float;
extern "C"{
void  gen_sobol(const int &n, const unsigned long long &offset,
                 const unsigned int &num_dimensions,                 
                 float* h_data) {

  curandOrdering_t order= CURAND_ORDERING_QUASI_DEFAULT;
  curandRngType_t rng= CURAND_RNG_QUASI_SOBOL32;
  cudaStream_t stream=NULL;
  curandGenerator_t gen=NULL;
  CUDA_CHECK(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));

  /* Create quasi-random number generator */
  CURAND_CHECK(curandCreateGeneratorHost(&gen, CURAND_RNG_QUASI_SOBOL32));

  /* Set cuRAND to stream */
  CURAND_CHECK(curandSetStream(gen, stream));

  /* Set offset */
  CURAND_CHECK(curandSetGeneratorOffset(gen, offset));

  /* Set Dimension */
  CURAND_CHECK(curandSetQuasiRandomGeneratorDimensions(gen, num_dimensions));

  /* Set ordering */
  CURAND_CHECK(curandSetGeneratorOrdering(gen, order));

  /* 可以直接生成正态分布,也可以生成均匀分布 */
 // CURAND_CHECK(curandGenerateUniform(gen, h_data, n*num_dimensions));  
  CURAND_CHECK(curandGenerateNormal(gen, h_data, n*num_dimensions,0,1));

  /* Cleanup */
  CURAND_CHECK(curandDestroyGenerator(gen));
}
}

之后可以nvcc生成so

nvcc -Xcompiler -fPIC -shared -o gen_sobol.so  gen_sobol.cu -lcurand

python可以使用ctypes调用


import numpy as np
import ctypes
from ctypes import *
from scipy.stats import norm
# extract cuda_sum function pointer in the shared object cuda_sum.so
def get_gen_sobol():
    dll = ctypes.CDLL('./gen_sobol.so', mode=ctypes.RTLD_GLOBAL)
    func = dll.gen_sobol
    func.argtypes = [POINTER(c_int), POINTER(c_ulonglong), POINTER(c_uint), POINTER(c_float)]
    return func

# create __cuda_sum function with get_cuda_sum()
__cuda_gen_sobol = get_gen_sobol()

# convenient python wrapper for __cuda_sum
# it does all job with types convertation
# from python ones to C++ ones
def cuda_gen_sobol(n, offset, num_dimensions, h_data):
#    a_p = n.ctypes.data_as(POINTER(c_int))
#    b_p = offset.ctypes.data_as(POINTER(c_ulonglong))
#    c_p = num_dimensions.ctypes.data_as(POINTER(c_uint))
    h_data_p=h_data.ctypes.data_as(POINTER(c_float))

    __cuda_gen_sobol(byref(n), byref(offset), byref(num_dimensions), h_data_p)
# testing, sum of two arrays of ones and output head part of resulting array
if __name__ == '__main__':
    n=65535
    offset=c_ulonglong(n+1)
    num_dimensions=520
    size=(num_dimensions,n)
    h_data = np.zeros(size).astype('float32')

    cuda_gen_sobol(c_int(n), offset, c_uint(num_dimensions), h_data)

    print(h_data)
    #和qmc比较
    dimension = num_undl * num_tp
    soboleng = qmc.Sobol(d=dimension, scramble=False)
    soboleng.fast_forward(n+1)        
    qs =soboleng.random(num_path)
    z=norm.ppf(qs)
    print(z)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘉诩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值