2017-10-23 7 views
0

나는 포인터 배열 (interv)을 반환하는 C 형 함수를 작성하기 위해 노력하고 내가 python- 내에서이 함수를 호출하고 싶습니다에 대한 포인터 배열을 반환하는 C 형 기능 함수 (sampler)을 입력하십시오. 다음 코드를 작성했지만 결과가 잘못되었습니다. 코드가 컴파일되지만 sampler 함수의 memoryview 개체로 함수 doubling이 반환하는 포인터 배열이 올바르지 않습니다.사이 썬

from cpython cimport array 
import cython 
import numpy as np 
import ctypes 
cimport numpy as np 
cimport cython 
from libc.stdlib cimport malloc, free 

from libcpp.vector cimport vector 
cdef extern from "gsl/gsl_rng.h":#nogil: 
    ctypedef struct gsl_rng_type: 
     pass 
    ctypedef struct gsl_rng: 
     pass 
    gsl_rng_type *gsl_rng_mt19937 
    gsl_rng *gsl_rng_alloc(gsl_rng_type * T) 

cdef gsl_rng *r = gsl_rng_alloc(gsl_rng_mt19937) 

cdef extern from "gsl/gsl_randist.h" nogil: 
    double unif "gsl_rng_uniform"(gsl_rng * r) 
    double unif_interval "gsl_ran_flat"(gsl_rng * r,double,double) ## syntax; (seed, lower, upper) 
    double exponential "gsl_ran_exponential"(gsl_rng * r,double) ## syntax; (seed, mean) ... mean is 1/rate 


cdef double* doubling(double x0, double y, double w, int p): 
    cdef double* interv = <double *>malloc(2 * cython.sizeof(double)) 
    if interv is NULL: 
     raise MemoryError() 
    cdef double u 
    cdef int K  
    cdef bint now_left 
    cdef double g_interv[2] 
    u = unif_interval(r,0,1) 
    interv[0] = x0 - w*u 
    interv[1] = interv[0] + w 
    if p>0: 
     K = p 
    g_interv[0]= f(interv[0]) 
    g_interv[1]= f(interv[1]) 
    while ((g_interv[0] > y) or (g_interv[1] > y)): 
      u = unif_interval(r,0,1)    
      now_left = (u < 0.5)   
      if (now_left): 
       interv[0] -= (interv[1] - interv[0]) 
       g_interv[0]=f(interv[0]) 
      else: 
       interv[1] += (interv[1] - interv[0]) 
       g_interv[1]=f(interv[1]) 
      if p>0: 
       K-=1 
       if (K<=0): 
        break 
    try: 
     return interv 
    finally: 
     if interv is not NULL: 
      free(interv) 

def sampler(int n_sample, 
        int p = 0, 
        double x0=0.0, 
        double w=0.1): 
    cdef vector[double] samples 
    cdef double vertical 
    cdef Py_ssize_t i 
    cdef np.ndarray[ndim=1, dtype=np.float64_t] interv 
    cdef np.float64_t[:] view 
    for 0<= i <n_sample: 
       vertical = f(x0) - exponential(r, 1)  
       view=<np.float64_t[:2]>doubling(x0, vertical, w, p) 
       interv= np.asarray(view) 
       samples.push_back(interv[0]) 
    return samples 

cdef double f(double x): 
    cdef double a=5. 
    return log(a)+(a-1.)*log(x) 

파이썬 함수에서 포인터 배열을 numpy 배열로 반환하는 올바른 방법은 무엇입니까? 미리 감사드립니다.

+0

'doubling' 함수는 반환하는 포인터를 해제합니다. 그 포인터가 어떻게 데이터를 가질 것으로 기대합니까? – danny

+0

@danny 정말요? 이유인가? 그렇다면 포인터에 대한 메모리는 어디에서 해제해야합니까? – Dalek

+1

[c malloc 배열 포인터가 cython에서 반환 될 수 있습니다] 가능한 복제본 (https://stackoverflow.com/questions/25102409/c-malloc-array-pointer-return-in-cython) – DavidW

답변

3

doubling 함수에서 할당 된 메모리가 해제되고 방금 해제 된 포인터가 반환됩니다. sampler에서 사용될 때 해당 포인터는 더 이상 데이터가 해제 될 때 해당 데이터를 가리 키지 않습니다.

try: 
    return interv 
finally: 
    if interv is not NULL: 
     free(interv) 

당신은 아마 최고의 독점적으로 데이터를 할당 주위 포인터와 사이 썬 배열을 전달하는 메모리 뷰를 사용하기 위해, NumPy와의 배열을 사용하기 때문에.

Cython 배열은 객체 수명을 기반으로 메모리 관리를 자동화하며 메모리보기는 포인터 및 수동 메모리 관리를 대신하여 복사하지 않고 cython 및/또는 numpy 배열을 허용 할 수 있습니다.

documentation for examplescoercion of numpy arrays to cython arrays을 참조하십시오.