より大きなクラスの地域依存ハッシュの一部としてペア間距離を計算するCythonモジュールを作成しようとしています。Cython:pythonによって呼び出されるcdef関数から拡張型cdefメソッドを呼び出す
cdef class Metric:
def __init__(self):
pass
cdef class Euclidean(Metric):
cdef numeric c_evaluate(self, numeric[:] x, numeric[:] y, int dims):
....
cdef numeric[:,:] pairwise(numeric[:] x, numeric[:] y, Metric func, bint symmetric):
...
dm[i,j] = func.c_evaluate(x,y,dims)
...
は、Pythonからこの機能にアクセスするには:
def py_pairwise(numeric[:,:] x, numeric[:,:] y, str func, bint symmetric = 1, **kwargs):
cdef Metric mfunc = to_Metric(func, **kwargs)
return pairwise(x, y, mfunc, symmetric)
代わりに、それぞれのタイプとメトリックの各距離のためにコードを書くのは、私はメトリックを継承し、様々な拡張子の種類を取る1つのCDEF関数を作成しようとしています
しかし、私は "c_distance。[Metric]オブジェクトには属性 'c_evaluate'がないというエラーが発生しています。"私はc_evaluateメソッドにアクセスできないのだろうかと疑問に思っているのは、クラスオブジェクトがPython関数to_Metricを介してPythonコードで作成されているからです。しかし、def関数とcdef関数はCythonモジュール内で自由に呼び出せると考えられます。このメソッドは、cpefメソッドにc_evaluateを変更しても機能しますが、cdefオブジェクトがpythonをcythonに渡すことを許可するか、単に低速のpythonメソッドを使用することで問題が解決するかどうかはわかりません。すべての提案(私は自宅のコンピュータではないので、今はすべてのコードを持っていません。後で更新する予定ですか?)また、to_Metric
ctypedef fused floating:
float
double
cdef class Euclidean(Metric):
cdef public floating c_evaluate(self, floating[:] x, floating[:] y, int dims):
cdef int i
cdef floating tmp, d = 0
for i in range(dims):
tmp = x[i]-y[i]
d += tmp*tmp
return sqrt(d)
#@cython.boundscheck(False)
#@cython.wraparound(False)
def py_pairwise(numeric[:,::1] x, numeric[:,::1] y,str metric, bint symmetric,**kwargs):
cdef Metric func = to_Metric(metric,**kwargs)
return pairwise(x,y,func,symmetric)
cdef numeric[:,::1] pairwise(numeric[:,::1] x,numeric[:,::1] y, Metric met, bint symmetric):#
cdef int n,m,k,i,j
n = x.shape[0]
m = y.shape[0]
dims = x.shape[1]
if numeric in floating:
mdtype = np.float
else:
mdtype = np.int
#mdtype = np.float
cdef numeric[:,::1] dm = (np.empty((n,m),dtype = mdtype)).fill(0)
if symmetric:
interval = lambda i,n,m: range(i+1,m)
else:
interval = lambda i,n,m: range(m)
for i in range(n):
for j in interval(i,n,m):
dm[i,j] = met.c_evaluate(x[i,:],y[j,:],dims)
return np.asarray(dm)
:
編集:それタイプミスが本来の機能ではありませんが(まだ他の人があるかもしれない)
def to_Metric(str m, **kwargs):
if len(kwargs) == 0:
if m == 'euclidean':
met = Euclidean()
elif m in {'cos','cosine'}:
met = Cosine()
elif m in {'hamming','matching'}:
met = Hamming()
else:
raise ValueError('Unrecognized metric {}'.format('\''+m+'\''))
else:
if m in {'pnorm','p-norm'}:
met = Pnorm(kwargs['p'])
elif m == 'maximal':
met = Maximal(kwargs['m1'],kwargs['m2'],kwargs['sep'])
else:
raise ValueError('Unrecognized metric {}'.format('\''+m+'\''))
return met
これは単なるスペルミスですか? – hpaulj