2014-10-09 4 views
3

numpy API를 사용하여 일반화 된 ufunc를 만들려고합니다. 입력은 하나의 (n x m) 행렬 및 스칼라이고 출력은 두 행렬 ((n x p)(p x m))입니다. 그러나 나는 그것을하는 방법을 모른다. 누군가 나를 도울 수 있니? I는 입력 (행렬 및 스칼라)를 읽을 수일반화 된 범용 함수 (numpy)

"(n,m),()->(n,p),(p,m)" 

하지만 서명의 치수 (P)와 같은 스칼라 입력을 사용하고자 : 초기화 기능에 난 서명 PyUFunc_FromFuncAndDataAndSignature 함수를 사용하고 있습니다. 가능한가? 여기

바로 입력 인쇄 예제 코드 :

#include "Python.h" 
#include "math.h" 
#include "numpy/ndarraytypes.h" 
#include "numpy/ufuncobject.h" 

static PyMethodDef nmfMethods[] = { 
     {NULL, NULL, 0, NULL} 
}; 


static void double_nmf(char **args, npy_intp *dimensions, 
          npy_intp* steps, void* data) 
{ 
    npy_intp i, j, 
      n = dimensions[1], //dimensions of input matrix 
      m = dimensions[2]; // 

    printf("scalar: %d\n",*(int*)args[1]); // input scalar 

    // just print input matrix 
    printf("Input matrix:\n"); 
    for(i=0;i<n;i++){ 
     for(j=0;j<m;j++){ 
      printf("%.1f ",*(double*)(args[0]+8*(i*m+j))); 
     } 
    printf("\n"); 
    } 
    return; 

} 

static PyUFuncGenericFunction nmf_functions[] = { double_nmf }; 
static void * nmf_data[] = { (void *)NULL }; 
static char nmf_signatures[] = { PyArray_DOUBLE, PyArray_INT, PyArray_DOUBLE, PyArray_DOUBLE }; 
char *nmf_signature = "(n,m),()->(n,p),(p,m)"; 

PyMODINIT_FUNC initnmf(void) 
{ 
    PyObject *m, *d, *version, *nmf; 

    m = Py_InitModule("nmf", nmfMethods); 
    if (m == NULL) { 
     return; 
    } 

    import_array(); 
    import_umath(); 
    d = PyModule_GetDict(m); 
    version = PyString_FromString("0.1"); 
    PyDict_SetItemString(d, "__version__", version); 
    Py_DECREF(version); 

    nmf = PyUFunc_FromFuncAndDataAndSignature(nmf_functions, nmf_data, nmf_signatures, 1, 
            2, 2, PyUFunc_None, "nmf", 
            "", 0, nmf_signature); 
    PyDict_SetItemString(d, "nmf", nmf); 
    Py_DECREF(nmf); 
} 

이 코드는 컴파일 및 작동합니다.

#/usr/bin/python 

import numpy as np 
import nmf 

x = np.array([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]]) 
y,z = nmf.nmf(x,2) 
print "Shapes of outputs: ", y.shape, z.shape 

와 단자 출력된다 : Python 스크립트는 여기

scalar: 2 
Input matrix: 
1.0 2.0 3.0 4.0 5.0 
6.0 7.0 8.0 9.0 10.0 
11.0 12.0 13.0 14.0 15.0 
16.0 17.0 18.0 19.0 20.0 
Shapes of outputs: (4, 1) (1, 5) 

내 의심 출력 매트릭스의 치수 (P)과 같은 (경우 2) 스칼라 입력을 사용하는 방법이다. 예를 들어 p = 1이고 설정하지 않았습니다.

+0

원본 배열, 스칼라 및 최종 배열의 최소 예를 보여주십시오. – wwii

+1

아쉽게도 불가능합니다.따라서 gufuncs의 서명 구문 분석기가 작동하면 출력 배열은 항상'p == 1'을 갖게됩니다. 다른 값을 원하면, 출력 배열을 미리 할당하고 gufunc의'out' 키워드 인수를 사용하여 전달하십시오. NumPy 1.10은 사용자가하려는 일을 가능하게하는 추가 기능을 제공 할 것입니다. – Jaime

+3

'p '가 스칼라 입력의 * value *에 의해 결정되기를 원한다는 말입니까? 그렇다면 gufunc는 원하는 것이 아닙니다. 그냥 규칙적인 함수를 만듭니다. gufunc의 개념은 인수를 통해 방송 할 수 있지만, 두 개의 서로 다른 스칼라를 전달하고자한다고 가정합니다. 출력 모양은 (2, n, 3)이 될 수 없습니다 (2,3 , m) 및 (2, n, 4), (2,4, m)을 동시에 출력한다. (2는 입력 벡터를 통한 브로드 캐스팅에서 나온 것입니다.) –

답변

2

특정 크기의 배열을 제공하는 것 외에도 gufunc에 차원을 설정하는 방법이 없습니다. 1은 모든 치수가 내부적으로 초기화되는 값이며 변경하지 않는 치수에 의존해서는 안됩니다. 그것에 대한 내 개인적인 견해는 정의되지 않은 차원이 오류를 제기해야한다는 것입니다.

올바른 모양으로 빈 배열을 만들어 출력 배열로 전달하면됩니다. 이를 달성하기 위해, 당신은 당신의 nmf이 서명 "(m,n)->(m,p),(p,n)"을 가지고와 비슷한 파이썬으로 포장을 재정의합니다 :

def nmf_wrap(x, p): 
    x = np.asarray(x) 
    assert x.ndim >= 2 
    shape = x.shape[:-2] 
    m, n = x.shape[-2:] 
    out1 = np.empty(shape+(m, p), dtype=x.dtype) 
    out2 = np.empty(shape+(p, n), dtype=x.dtype) 
    return nmf.nmf(x, out1, out2) 

것은 gufuncs 서명 on the numpy-dev mailing list recently에서 제공하는 기능을 확장에 대한 몇 가지 지속적인 논의가 있었다. 당신이 설명하는 것은 내가 "계산 된 차원"이라고 부르는 것에 약간의 유사점을 가지고 있습니다. 1.10에서 numpy로 구현 된 것을보고 싶다면 유스 케이스를 그 목록에 더 자세히 설명하면 좋을 것입니다 : 우리는 야생에서 많은 (모든?) gufunc 코더를 알지 못합니다!

1

답장을 보내 주신 @jaime, 고맙습니다. 당신이 제안한 변화를 만들었고 효과가 있습니다. 여기에 C 예제 코드가 있습니다. 입력 행렬 요소를 출력에 복사합니다.

#include "Python.h" 
#include "numpy/ndarraytypes.h" 
#include "numpy/ufuncobject.h" 

static PyMethodDef nmfMethods[] = { 
     {NULL, NULL, 0, NULL} 
}; 


static void double_nmf(char **args, npy_intp *dimensions, 
          npy_intp* steps, void* data) 
{ 
    npy_intp i, j, 
      n = dimensions[1], 
      m = dimensions[2], 
      p = dimensions[3]; 
    char *in = args[0], *out1 = args[1], *out2 = args[2]; 

    for(i=0; i<n; i++){ 
     for(j=0; j<p; j++){ 
      *(double*)(out1 + 8*(j + p*i)) = *(double*)(in + 8*(j + m*i)); 
     } 
    } 
    for(i=0; i<p; i++){ 
     for(j=0; j<m; j++){ 
      *(double*)(out2 + 8*(j + m*i)) = *(double*)(in + 8*(j + m*i)); 
     } 
    } 
    return; 

} 

static PyUFuncGenericFunction nmf_functions[] = { double_nmf }; 
static void * nmf_data[] = { (void *)NULL }; 
static char nmf_signatures[] = { PyArray_DOUBLE, PyArray_DOUBLE, PyArray_DOUBLE }; 
char *nmf_signature = "(n,m)->(n,p),(p,m)"; 

PyMODINIT_FUNC initnmf(void) 
{ 
    PyObject *m, *d, *version, *nmf; 

    m = Py_InitModule("nmf", nmfMethods); 
    if (m == NULL) { 
     return; 
    } 

    import_array(); 
    import_umath(); 
    d = PyModule_GetDict(m); 
    version = PyString_FromString("0.1"); 
    PyDict_SetItemString(d, "__version__", version); 
    Py_DECREF(version); 

    nmf = PyUFunc_FromFuncAndDataAndSignature(nmf_functions, nmf_data, nmf_signatures, 1, 
            1, 2, PyUFunc_None, "nmf", 
            "", 0, nmf_signature); 
    PyDict_SetItemString(d, "nmf", nmf); 
    Py_DECREF(nmf); 
} 

여기 파이썬 예제 코드와 터미널 출력.


Input: 
[[ 1 2 3 4 5] 
[ 6 7 8 9 10] 
[11 12 13 14 15] 
[16 17 18 19 20]] 
Output 1: 
[[ 1 2] 
[ 6 7] 
[11 12] 
[16 17]] 
Output 2: 
[[ 1 2 3 4 5] 
[ 6 7 8 9 10]] 

#/usr/bin/python 

import numpy as np 
import nmf 

def nmf_wrap(x,p): 
    x = np.asarray(x) 
    assert x.ndim >=2 
    shape = x.shape[-2:] 
    n,m = shape[-2:] 
    out1 = np.empty((n, p), dtype=x.dtype) 
    out2 = np.empty((p, m), dtype=x.dtype) 
    return nmf.nmf(x, out1, out2) 

x = np.array([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]]) 
y,z = nmf_wrap(x,2) 
print 'Input:\n', x 
print 'Output 1:\n', y 
print 'Output 2:\n', z 

는 지금은 프로그램을 계속할 수 있습니다.

또한 @ nathaniel-j-smith가 제안한대로 (파이썬/C API (numpy 없음) 사용) 비 ufunc를 작성하고 있습니다. 몇 가지 결과를 얻고 두 가지 방법을 간단히 비교하길 바랍니다.

+1

질문을 편집하여 추가 정보로 대답하지 말아야합니다. – Jaime