自定义numpy类型导致numpy.mean中的崩溃 我用C++的基本功能定义了自己的NUMPY类型。数组创建工作正常,可以添加和分割这种类型的数组。使用np.sum可以减少数组,但使用np.mean时解释器崩溃 import numpy as np from example import Dual x = np.array([Dual(1, 2), Dual(1, 3), Dual(1, 1)]) print(x.dtype) # dtype(Dual) -- correct type # Mean 1 m = x.sum() / x.size print(m.x, m.y) # 1.0 2.0 -- correct result # Mean 2 x.mean() # -- CRASH < P>通过在我的C++代码中插入调试输出,我验证了在我的代码中正确计算和和除法(3/3和6/3是实际执行的)。因此,在计算我的结果后,函数崩溃。(Windows告诉我Python停止工作了,所以可能在引擎盖下发生了一个SegFault。)
自定义numpy类型导致numpy.mean中的崩溃 我用C++的基本功能定义了自己的NUMPY类型。数组创建工作正常,可以添加和分割这种类型的数组。使用np.sum可以减少数组,但使用np.mean时解释器崩溃 import numpy as np from example import Dual x = np.array([Dual(1, 2), Dual(1, 3), Dual(1, 1)]) print(x.dtype) # dtype(Dual) -- correct type # Mean 1 m = x.sum() / x.size print(m.x, m.y) # 1.0 2.0 -- correct result # Mean 2 x.mean() # -- CRASH < P>通过在我的C++代码中插入调试输出,我验证了在我的代码中正确计算和和除法(3/3和6/3是实际执行的)。因此,在计算我的结果后,函数崩溃。(Windows告诉我Python停止工作了,所以可能在引擎盖下发生了一个SegFault。),python,c++,numpy,Python,C++,Numpy,与sum()/n的不同之处是什么?如何修改我的类型使其工作 我尝试将C++代码煮沸,以创建一个最小的完整的例子。不幸的是,在定义工作numpy类型时,minimal仍然相当长。以下是实施方案: #include <Python.h> #include <numpy/arrayobject.h> #include <numpy/npy_math.h> #include <numpy/ufuncobject.h> #include "structme
与sum()/n
的不同之处是什么?如何修改我的类型使其工作
<>我尝试将C++代码煮沸,以创建一个最小的完整的例子。不幸的是,在定义工作numpy类型时,minimal仍然相当长。以下是实施方案:
#include <Python.h>
#include <numpy/arrayobject.h>
#include <numpy/npy_math.h>
#include <numpy/ufuncobject.h>
#include "structmember.h"
#include <iostream>
#include <math.h>
struct Dual
{
public:
double x;
double y;
Dual(double x, double y) : x(x), y(y) { }
inline static Dual add(const Dual& a, const Dual& b) {
return Dual(a.x + b.x, a.y + b.y); }
inline static Dual div(const Dual& a, const Dual& b) {
return Dual(a.x / b.x, a.y / b.y); }
};
typedef struct {
PyObject_HEAD
Dual ob_val;
} PyDual;
PyArray_Descr* dual_descr;
static PyObject *
PyDual_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyDual *self;
self = (PyDual *)type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
}
double x = 0;
double y = 0;
static char *kwlist[] = {"x", "y", NULL};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "d|d", kwlist, &x, &y))
return NULL;
self->ob_val = Dual(x, y);
return (PyObject *)self;
}
static PyTypeObject PyDual_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"example.Dual", /* tp_name */
sizeof(PyDual), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Dual value/derivative", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyDual_new, /* tp_new */
};
static int PyDual_Check(PyObject* obj)
{
return PyObject_IsInstance(obj, (PyObject*)&PyDual_Type);
}
static PyObject*
PyDual_from_Dual(Dual d)
{
PyDual *obj = (PyDual*)PyDual_Type.tp_alloc(&PyDual_Type, 0);
if(obj)
obj->ob_val = d;
return (PyObject*)obj;
}
static PyMemberDef PyDual_members[] = {
{"x", T_DOUBLE, offsetof(PyDual, ob_val) + offsetof(Dual, x), READONLY, "value"},
{"y", T_DOUBLE, offsetof(PyDual, ob_val) + offsetof(Dual, y), READONLY, "derivative"},
{NULL}
};
//----------------------------------------------------------------------------
static PyArray_ArrFuncs _PyDual_ArrFuncs;
static void
DUAL_copyswap(Dual *dst, Dual *src, int swap, void *NPY_UNUSED(arr))
{
PyArray_Descr *descr;
descr = PyArray_DescrFromType(NPY_DOUBLE);
descr->f->copyswapn(dst, sizeof(double), src, sizeof(double), 2, swap, NULL);
Py_DECREF(descr);
}
static int DUAL_setitem(PyObject* item, void* data, void* ap)
{
Dual d(0, 0);
if(PyDual_Check(item)) {
memcpy(data, &(((PyDual *)item)->ob_val),sizeof(Dual));
} else if(PySequence_Check(item) && PySequence_Length(item)==4) {
auto element = PySequence_GetItem(item, 0);
if(element == NULL) { return -1; } /* Not a sequence, or other failure */
d.x = PyFloat_AsDouble(element);
Py_DECREF(element);
element = PySequence_GetItem(item, 1);
if(element == NULL) { return -1; } /* Not a sequence, or other failure */
d.y = PyFloat_AsDouble(element);
Py_DECREF(element);
} else {
PyErr_SetString(PyExc_TypeError,
"Unknown input to DUAL_setitem");
return -1;
}
return 0;
}
static PyObject *DUAL_getitem(void* data, void* arr)
{
Dual d(0, 0);
memcpy(&d, data, sizeof(Dual));
return PyDual_from_Dual(d);
}
template<typename T>
scalar_to_dual(T* ip, Dual* op, npy_intp n,
PyArrayObject *NPY_UNUSED(aip), PyArrayObject *NPY_UNUSED(aop))
{
while(n--)
{
op->x = *ip++;
op->y = op->x;
}
}
static void register_cast_function(int sourceType, int destType, PyArray_VectorUnaryFunc *castfunc)
{
PyArray_Descr *descr = PyArray_DescrFromType(sourceType);
PyArray_RegisterCastFunc(descr, destType, castfunc);
PyArray_RegisterCanCast(descr, destType, NPY_NOSCALAR);
Py_DECREF(descr);
}
static void sum_ufunc(char** args, npy_intp* dimensions, npy_intp* steps, void* data)
{
char *ip1 = args[0], *ip2 = args[1], *op1 = args[2];
npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2];
npy_intp n = dimensions[0];
for(npy_intp i=0; i<n; i++, ip1+=is1, ip2+=is2, op1+=os1)
{
const Dual in1 = *(Dual*)ip1;
const Dual in2 = *(Dual*)ip2;
*((Dual*)op1) = Dual::add(in1, in2);
}
}
static void div_ufunc(char** args, npy_intp* dimensions, npy_intp* steps, void* data)
{
char *ip1 = args[0], *ip2 = args[1], *op1 = args[2];
npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2];
npy_intp n = dimensions[0];
for(npy_intp i=0; i<n; i++, ip1+=is1, ip2+=is2, op1+=os1)
{
const Dual in1 = *(Dual*)ip1;
const Dual in2 = *(Dual*)ip2;
*((Dual*)op1) = Dual::div(in1, in2);
std::cout << in1.x << "/" << in2.x << std::endl;
std::cout << in1.y << "/" << in2.y << std::endl;
}
}
//----------------------------------------------------------------------------
static struct PyModuleDef examplemodule = {
PyModuleDef_HEAD_INIT,
"example", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
NULL, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC PyInit_example(void)
{
// initialize numpy
import_array(); if(PyErr_Occurred()) return NULL;
import_umath(); if(PyErr_Occurred()) return NULL;
auto numpy = PyImport_ImportModule("numpy"); if(!numpy) return NULL;
auto numpy_dict = PyModule_GetDict(numpy); if(!numpy_dict) return NULL;
PyDual_Type.tp_members = PyDual_members;
PyDual_Type.tp_base = &PyGenericArrType_Type;
if( PyType_Ready(&PyDual_Type) < 0)
return NULL;
PyArray_InitArrFuncs(&_PyDual_ArrFuncs);
_PyDual_ArrFuncs.copyswap = (PyArray_CopySwapFunc*)DUAL_copyswap;
_PyDual_ArrFuncs.setitem = (PyArray_SetItemFunc*)DUAL_setitem;
_PyDual_ArrFuncs.getitem = (PyArray_GetItemFunc*)DUAL_getitem;
dual_descr = PyObject_New(PyArray_Descr, &PyArrayDescr_Type);
dual_descr->typeobj = &PyDual_Type;
dual_descr->kind = 'x';
dual_descr->type = 'x';
dual_descr->byteorder = '=';
dual_descr->flags = 0;
dual_descr->type_num = 0; // assigned at registration
dual_descr->elsize = 8*2;
dual_descr->alignment = 8;
dual_descr->subarray = NULL;
dual_descr->fields = NULL;
dual_descr->names = NULL;
dual_descr->f = &_PyDual_ArrFuncs;
dual_descr->metadata = NULL;
dual_descr->c_metadata = NULL;
Py_INCREF(&PyDual_Type);
auto dualNum = PyArray_RegisterDataType(dual_descr);
if(dualNum < 0) return NULL;
int AD = dual_descr->type_num;
register_cast_function(NPY_BOOL, dualNum, (PyArray_VectorUnaryFunc*)scalar_to_dual<npy_bool>);
register_cast_function(NPY_LONG, dualNum, (PyArray_VectorUnaryFunc*)scalar_to_dual<npy_long>);
register_cast_function(NPY_DOUBLE, dualNum, (PyArray_VectorUnaryFunc*)scalar_to_dual<npy_double>);
int arg_types[] = {AD, AD, AD};
PyUFuncObject* ufunc = (PyUFuncObject*)PyObject_GetAttrString(numpy, "add");
PyUFunc_RegisterLoopForType(ufunc, AD, sum_ufunc, arg_types, NULL);
ufunc = (PyUFuncObject*)PyObject_GetAttrString(numpy, "true_divide");
PyUFunc_RegisterLoopForType(ufunc, AD, div_ufunc, arg_types, NULL);
auto module = PyModule_Create(&examplemodule);
if( module == NULL )
return NULL;
Py_INCREF(&PyDual_Type);
PyModule_AddObject(module, "Dual", (PyObject*)&PyDual_Type);
return module;
}
#包括
#包括
#包括
#包括
#包括“structmember.h”
#包括
#包括
结构对偶
{
公众:
双x;
双y;
双(双x,双y):x(x),y(y){}
内联静态双添加(常量双a、常量双b){
返回双(a.x+b.x,a.y+b.y);}
内联静态双分区(常数双分区a、常数双分区b){
返回双(a.x/b.x,a.y/b.y);}
};
类型定义结构{
皮尤头
双重观察;
}PyDual;
PyArray_Descr*双_Descr;
静态PyObject*
PyDual_new(PyTypeObject*type,PyObject*args,PyObject*kwds)
{
双重自我;
self=(PyDual*)类型->tp_alloc(类型,0);
if(self==NULL){
返回NULL;
}
双x=0;
双y=0;
静态字符*kwlist[]={“x”,“y”,NULL};
if(!PyArg_ParseTupleAndKeywords(args,kwds,“d | d”,kwlist,&x,&y))
返回NULL;
self->ob_val=Dual(x,y);
返回(PyObject*)self;
}
静态PyTypeObject PyDual_类型={
PyVarObject\u HEAD\u INIT(NULL,0)
“example.Dual”,/*tp_名称*/
sizeof(PyDual),/*tp_basicsize*/
0,/*tp\u itemsize*/
0,/*tp_dealoc*/
0,/*tp_打印*/
0,/*tp\u getattr*/
0,/*tp_setattr*/
0,/*tp_保留*/
0,/*tp_repr*/
0,/*tp\U作为\U编号*/
0,/*tp\u作为\u序列*/
0,/*tp_作为映射*/
0,/*tp_散列*/
0,/*tp\u调用*/
0,/*tp_str*/
0,/*tp_getattro*/
0,/*tp_setattro*/
0,/*tp作为缓冲区*/
Py_TPFLAGS_默认值,/*tp_标志*/
“双重价值/衍生工具”,/*tp_文件*/
0,/*tp\u导线测量*/
0,/*tp_清除*/
0,/*tp_*/
0,/*tp_弱偏移*/
0,/*tp_iter*/
0,/*tp_iternext*/
0,/*tp_方法*/
0,/*tp_成员*/
0,/*tp\u getset*/
0,/*tp_基*/
0,/*tp_dict*/
0,/*tp\u descr\u get*/
0,/*tp\u descr\u集*/
0,/*tp\u偏移量*/
0,/*tp_init*/
0,/*tp_alloc*/
PyDual_new,/*tp_new*/
};
静态整数PyDual_检查(PyObject*obj)
{
返回PyObject实例(obj,(PyObject*)&PyDual类型);
}
静态PyObject*
Pydoul_from_Dual(双d)
{
PyDual*obj=(PyDual*)PyDual\u Type.tp\u alloc(&PyDual\u Type,0);
如果(obj)
obj->ob_val=d;
返回(PyObject*)对象;
}
静态PyMemberDef PyDual_成员[]={
{“x”,T_DOUBLE,offsetof(PyDual,ob_val)+offsetof(Dual,x),只读,“value”},
{“y”,T_DOUBLE,offsetof(PyDual,ob_val)+offsetof(Dual,y),只读,“导数”},
{NULL}
};
//----------------------------------------------------------------------------
静态PyArray_ArrFuncs _PyDual_ArrFuncs;
静态空隙
双拷贝交换(双*dst、双*src、整数交换、无效*NPY\U未使用(arr))
{
PyArray_Descr*Descr;
descr=PyArray\u DescrFromType(NPY\u DOUBLE);
descr->f->copyswapn(dst、sizeof(双精度)、src、sizeof(双精度)、2、swap、NULL);
Py_DECREF(descr);
}
静态int DUAL_setitem(PyObject*项,void*数据,void*ap)
{
双d(0,0);
if(PyDual_检查(项目)){
memcpy(数据和((PyDual*)项)->obval,sizeof(Dual));
}否则如果(序列检查(项目)和序列长度(项目)==4){
auto元素=PySequence\u GetItem(item,0);
如果(element==NULL){return-1;}/*不是序列,或其他故障*/
d、 x=PyFloat_AsDouble(元素);
Py_DECREF(元素);
元素=PySequence\u GetItem(项目,1);
如果(element==NULL){return-1;}/*不是序列,或其他故障*/
d、 y=PyFloat_AsDouble(元素);
Py_DECREF(元素);
}否则{
PyErr_设置字符串(PyExc_类型错误,
“DUAL_setitem的未知输入”);
返回-1;
}
返回0;
}
静态PyObject*DUAL_getitem(void*data,void*arr)
{
双d(0,0);
memcpy(&d,data,sizeof(Dual));
从_Dual返回PyDual_(d);
}
模板
标量对对偶(T*ip,对偶*op,npy\u intp n,
PyArrayObject*NPY_未使用(aip),PyArrayObject*NPY_未使用(aop))
{
而(n--)
{
op->x=*ip++;
op->y=op->x;
}
}
静态无效寄存器\u cast\u函数(int sourceType、int destType、PyArray\u VectorUnaryFunc*castfunc)
{
PyArray_Descr*Descr=PyArray_DescrFromType(sourceType);
PyArray_寄存器
import numpy as np
###code
np.mean(x) # instead of x.mean?
ret = ret.dtype.type(ret / rcount)
Dual(dual_object)
static char *kwlist[] = {"x", "y", NULL};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "d|d", kwlist, &x, &y))
return NULL;