I'm new to both Python and SWIG, so maybe this is a common mistake. I have the following simple C++ class:
Header File:
class myMath
{
public:
myMath(void);
~myMath(void);
int add(int x, int y);
int minusOne(int x);
void sub(int *x, int *y, int *result);
int divide(int n, int d, int *r);
double avg_array(double *array, int len);
int sum_array(int *array, int len);
};
C++ File:
/* File : example.cpp */
#include "Example.h"
myMath::myMath()
{
}
myMath::~myMath()
{
}
int myMath::add(int x, int y)
{
return x + y;
}
int myMath::minusOne(int x)
{
return x - 1;
}
void myMath::sub(int *x, int *y, int *result)
{
*result = *x - *y;
}
int myMath::divide(int n, int d, int *r)
{
int q;
q = n/d;
*r = n - q*d;
return q;
}
double myMath::avg_array(double *array, int len)
{
double sum = 0.0;
double avg;
for (int i = 0; i < len; i++)
{
sum += array[i];
}
avg = sum / (double) len;
return avg;
}
int myMath::sum_array(int *array, int len)
{
int sum = 0;
for (int i = 0; i < len; i++)
{
sum += array[i];
}
return sum;
}
Interface File:
/* File : example.i */
%module example
%{
#include "Example.h"
%}
%include "Example.h"
And here is the Python code:
# file: swigExample.py
import sys
# Include the local Python modules
sys.path.append('C:/Temp/PTest_3')
import example
a = 37
b = 42
c = 0
print " a =",a
print " b =",b
print " c =",c
ex = example.myMath()
d = ex.myMath.minusOne( 10 )
print " d =",d
This is the error I get when I run the Python code:
Traceback (most recent call last):
File "C:\Temp\PTest_3\swigExample.py", line 20
d = ex.myMath.minusOne( 10 )
File "C:\Temp\PTest_3\example.py", line 94, in <lambda>
__getattr__ = lambda self, name: _swig_getattr(self, myMath, name)
File "C:\Temp\PTest_3\example.py", line 71, in _swig_getattr
return _swig_getattr_nondynamic(self, class_type, name, 0)
File "C:\Temp\PTest_3\example.py", line 66, in _swig_getattr_nondynamic
return object.__getattr__(self, name)
AttributeError: type object 'object' has no attribute '__getattr__'
I'm sure this must be something really basic, but I can't find a similar problem on the site. Thanks in advance.
Related
i am trying to use https://github.com/Spyros-DC/words-in-some-editdistance/blob/master/my_distance.cpp C++ implementation in python, however i kept receiving Segmentation fault (core dumped). Below is the entire code in python and C++, i have edited small parts of the original library to suit my use case. I have managed to find that when trying to use the unordered_map children.count(remaining_w.at(0)) it is throwing the segmentation fault error. I was wondering if anyone knows what is causing the error. Thank you so much in advance.
#include <iostream>
#include <unordered_map>
#include <string>
#include <fstream>
#include <unordered_set>
#include <vector>
#include <sstream>
#include <typeinfo>
using namespace std;
// using namespace std::chrono;
class trie{
public:
string word;
unordered_map<char, trie*> children;
// this function works
// with the argument flag set to zero
int insert(string w, int flag, string remaining_w = ""){
//the first time we call insert
if(flag == 0)
remaining_w = w;
int the_size = remaining_w.size();
if(children.count(remaining_w.at(0)) == 0){
children[remaining_w.at(0)] = new trie();
}
if(the_size == 0){
word = w;
return 0;
}else{
//the recursive calls with flag one
children[remaining_w.at(0)]->insert(w, 1, remaining_w.erase(0, 1));
return 0;
}
}
};
class AutoCorrect{
public:
// The tree
trie tree;
//the dictionary with the words
const int max_cost = 2;
const int too_big_distance = 10;
void insert(char* word){
ifstream ifp(word);
while(ifp >> word){
cout << word <<endl;
tree.insert(word, 0);
// }
}
}
void test(char* test){
cout << test << endl;
}
void search_recursive(trie* p_tree, char ch, const string& word, vector<int>& previous_row, int max_cost, unordered_map <string, int>& results)
{
int sz = previous_row.size();
int min_row = 12;
vector<int> current_row(sz, too_big_distance);
current_row[0] = previous_row[0] + 1;
// Calculate the min cost of insertion, deletion, match or substution
int insert_or_del, replace;
for (int i = 1; i < sz; i++) {
insert_or_del = min(current_row[i-1] + 1, previous_row[i] + 1);
replace = (word[i-1] == ch) ? previous_row[i-1] : (previous_row[i-1] + 1);
current_row[i] = min(insert_or_del, replace);
}
if ((current_row[sz-1] <= max_cost) && (p_tree->word != "")) {
results[p_tree->word] = current_row[sz-1];
}
for(auto& it: current_row){
if (it < min_row)
min_row = it;
}
if(min_row <= max_cost){
for(auto& it: p_tree->children){
search_recursive(it.second, it.first, word, current_row, max_cost, results);
}
}
}
int search(string word)
{
unordered_map <string, int> results;
int sz = word.size();
vector<int> current_row(sz + 1);
for (int i = 0; i <= sz; ++i){
current_row[i] = i;
}
for(auto& it: tree.children){
search_recursive(it.second, it.first, word, current_row, max_cost, results);
}
for(auto& p:results)
cout << p.first << ", " << p.second << endl;
return 0;
}
};
// The cost and a distance for vector initialization
extern "C" {
AutoCorrect* AutoCorrect_new(){ return new AutoCorrect(); }
void AutoCorrect_insert(AutoCorrect* autocorrect, char* word){ autocorrect->insert(word); }
void AutoCorrect_search(AutoCorrect* autocorrect, string input_word){ autocorrect->search(input_word); }
void AutoCorrect_test(AutoCorrect* autocorrect, char* name){ autocorrect-> test(name); }
}
Python main.py:
from ctypes import cdll
lib = cdll.LoadLibrary('autocorrect.so')
class AutoCorrect(object):
def __init__(self):
self.obj = lib.AutoCorrect_new()
def insert(self, word):
lib.AutoCorrect_insert(self.obj,word)
def search(self,input_word):
lib.AutoCorrect_search(self.obj,input_word)
def test(self,test):
lib.AutoCorrect_test(self.obj,test)
if __name__ == "__main__":
import json
WordCount = 0
autocorrect = AutoCorrect()
data_dir = "some_txt_file.txt"
autocorrect.insert(bytes(str(data_dir), encoding='utf8'))
Looking at the line you specified, i think there is an instance you are trying to add a value to a non existent key:
if(children.count(remaining_w.at(0)) == 0){
children[remaining_w.at(0)] = new trie();
if "children.count" returns 0 then that character is not present, then trying to add a value on the second line there means....
what i think you want to do on that line is:
if(children.count(remaining_w.at(0)) == 1){
children[remaining_w.at(0)] = new trie();
meaning you add the value only if key is present.
I tried to call this C++ file (myfunc.cpp) from Python. I decided to use ctypes module, since it seems to work pretty well for both C and C++ code.
I followed several tutorial (e.g., Modern/2020 way to call C++ code from Python), which suggests to add 'extern C' on the top of the C++ function to be called in Python.
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdio>
using namespace std;
int from_xy(int x, int y, int nside) {
return x + (nside * y);
}
std::vector<int> to_xy(int k, int nside) {
int x = k%nside;
int y = floor(k / nside);
vector<int> res(x, y);
return res;
}
int modNegOperator(int k, int n){
return ((k %= n) < 0) ? k+n : k;
}
extern "C"
double** create2Darray(unsigned nside, double mx, double my) {
int n_matrix = nside * nside;
double **array2D = 0;
array2D = new double *[n_matrix];
for (int h = 0; h < n_matrix; h++) {
array2D[h] = new double[n_matrix];
for (int w = 0; w < n_matrix; w++) {
// fill in some initial values
// (filling in zeros would be more logic, but this is just for the example)
array2D[h][w] = 0;
}
}
for (int h = 0; h < n_matrix; h++){
std::vector<int> xy_vec = to_xy(h, nside);
int modneg1 = modNegOperator(xy_vec[0] + 1,nside);
int modneg2 = modNegOperator(xy_vec[0] - 1,nside);
int modneg3 = modNegOperator(xy_vec[1] + 1,nside);
int modneg4 = modNegOperator(xy_vec[1] - 1,nside);
int pos1 = from_xy(modneg1, xy_vec[1], nside);
int pos2 = from_xy(modneg2, xy_vec[1], nside);
int pos3 = from_xy(xy_vec[0], modneg3, nside);
int pos4 = from_xy(xy_vec[0], modneg4, nside);
double half_mx = mx / 2;
double half_my = my / 2;
array2D[h][h] = 0;
array2D[h][pos1] = half_mx;
array2D[h][pos2] = half_mx;
array2D[h][pos3] = half_my;
array2D[h][pos4] = half_my;
}
return array2D;
}
I have then created a shared library:
g++ -fPIC -shared -o libTest.so myfunc.cpp
Created a myLib.py file including:
import ctypes
import sys
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
handle = ctypes.CDLL(dir_path + "/libTest.so")
handle.create2Darray.argtypes = [ctypes.c_int, ctypes.c_double, ctypes.c_double]
def create2Darray(nside, mx, my):
return handle.create2Darray(nside, mx, my)
However, when I then try to run my function in python:
from myLib import *
create2Darray(4, 0.01,0.01)
I get 'Segmentation fault'.
Do you know what am I doing wrong? Do you have any suggestion? Or perhaps suggest another approach with which I can import my C++ function in python. The alternative ofcourse would be to re-write the code in C.
As mentioned in the chat we had, the code posted in the question segfaults because the following code returns a zero-length vector when first called:
std::vector<int> to_xy(int k, int nside) {
int x = k%nside;
int y = floor(k / nside);
vector<int> res(x, y); // if k==0, this is length 0
return res;
}
then this code faults here:
for (int h = 0; h < n_matrix; h++){
std::vector<int> xy_vec = to_xy(h, nside); // length 0
int modneg1 = modNegOperator(xy_vec[0] + 1,nside); // xy_vec[0] faults.
The code we discussed in chat didn't fail because:
vector<int> res(x, y); // if k==0, this is length 0
had been changed to:
vector<int> res{x, y}; // curly braces, length 2
After resolving that, the Python code just needed .restype defined, and technically c_uint for the first parameter:
handle.create2Darray.argtypes = ctypes.c_uint, ctypes.c_double, ctypes.c_double
handle.create2Darray.restype = ctypes.POINTER(ctypes.POINTER(ctypes.c_double))
Then the code would return the double** correctly.
I'm trying to execute a C function using Python ctypes, but I'm doing something wrong.
The C function was originally converted from MATLAB to C code using MATLAB coder. The function gives as output an array of undefined length, which depends on the input.
This is the MATLAB code:
function a = array_output(n)
%$codegen
if n > 2*pi
a = 1:n;
else
a = [1,2,3];
end
end
And this is the obtained C code:
void array_output(double n, emxArray_real_T *a)
{
int i;
int loop_ub;
if (n > 6.2831853071795862) {
i = a->size[0] * a->size[1];
a->size[0] = 1;
loop_ub = (int)floor(n - 1.0);
a->size[1] = loop_ub + 1;
emxEnsureCapacity_real_T(a, i);
for (i = 0; i <= loop_ub; i++) {
a->data[i] = (double)i + 1.0;
}
} else {
i = a->size[0] * a->size[1];
a->size[0] = 1;
a->size[1] = 3;
emxEnsureCapacity_real_T(a, i);
a->data[0] = 1.0;
a->data[1] = 2.0;
a->data[2] = 3.0;
}
}
struct emxArray_real_T
{
double *data;
int *size;
int allocatedSize;
int numDimensions;
boolean_T canFreeData;
};
Please, find at the end of my question an example implementation they provide.
I am trying to execute it using Python's ctype using the following code:
dll = ctypes.cdll.LoadLibrary(dll_path)
class DataStruct(ctypes.Structure):
_fields_ = [
('data', ctypes.POINTER(ctypes.c_double)),
('size', ctypes.POINTER(ctypes.c_int)),
('allocatedSize', ctypes.c_int),
('numDimensions', ctypes.c_int),
('canFreeData', ctypes.c_bool)
]
array = ctypes.POINTER(ctypes.c_double)()
size = numpy.array([0, 0]).ctypes.data_as(ctypes.POINTER(ctypes.c_int))
allocatedSize = 0
numDimensions = 2
canFreeData = True
data_struct = DataStruct(array, size, allocatedSize, numDimensions, canFreeData)
dll.array_output.argtypes = [ctypes.c_double, DataStruct]
dll.array_output.restype = None
dll.array_output(50, data_struct)
The output data_struct contains the right size field (data_struct.size[1] is 50), but when I try to access data_struct.data[0], I get the following error:
ValueError: NULL pointer access
Can anyone help me understanding what I'm doing wrong here?
--
Example implementation (code snippets):
void main(){
// pseudo-code here
emxArray_real_T *a;
emxInitArray_real_T(&a, 2);
/* Initialize function 'array_output' input arguments. */
/* Call the entry-point 'array_output'. */
array_output(5.0, a);
}
void emxInitArray_real_T(emxArray_real_T **pEmxArray, int numDimensions)
{
emxInit_real_T(pEmxArray, numDimensions);
}
void emxInit_real_T(emxArray_real_T **pEmxArray, int numDimensions)
{
emxArray_real_T *emxArray;
int i;
*pEmxArray = (emxArray_real_T *)malloc(sizeof(emxArray_real_T));
emxArray = *pEmxArray;
emxArray->data = (double *)NULL;
emxArray->numDimensions = numDimensions;
emxArray->size = (int *)malloc(sizeof(int) * numDimensions);
emxArray->allocatedSize = 0;
emxArray->canFreeData = true;
for (i = 0; i < numDimensions; i++) {
emxArray->size[i] = 0;
}
}
void emxEnsureCapacity_real_T(emxArray_real_T *emxArray, int oldNumel)
{
int newNumel;
int i;
void *newData;
if (oldNumel < 0) {
oldNumel = 0;
}
newNumel = 1;
for (i = 0; i < emxArray->numDimensions; i++) {
newNumel *= emxArray->size[i];
}
if (newNumel > emxArray->allocatedSize) {
i = emxArray->allocatedSize;
if (i < 16) {
i = 16;
}
while (i < newNumel) {
if (i > 1073741823) {
i = MAX_int32_T;
} else {
i *= 2;
}
}
newData = calloc((unsigned int)i, sizeof(double));
if (emxArray->data != NULL) {
memcpy(newData, emxArray->data, sizeof(double) * oldNumel);
if (emxArray->canFreeData) {
free(emxArray->data);
}
}
emxArray->data = (double *)newData;
emxArray->allocatedSize = i;
emxArray->canFreeData = true;
}
}
The second argument of array_output is a emxArray_real_T *, but you're trying to pass the structure by value as if it were just a emxArray_real_T. To fix that, change dll.array_output.argtypes = [ctypes.c_double, DataStruct] to dll.array_output.argtypes = [ctypes.c_double, ctypes.POINTER(DataStruct)] and dll.array_output(50, data_struct) to dll.array_output(50, ctypes.byref(data_struct)).
I'm working with Python and C++ integration, and I'm on MacOS.
When I use all of the PyObject methods they all seem to work but none of the PyModule methods seem to be working.
This is my code:
#include <iostream>
#include <cmath>
#include <vector>
#if PY_MAJOR_VERSION >= 3
#define PY3K
#endif
#ifdef __APPLE__
#include <Python/Python.h>
#else
#include <Python.h>
#endif
#define space " "
#define epoch int(1000)
using namespace std;
double hypothesis(const std::vector<double>& b_val, double x){
return b_val[0] + b_val[1] * x;
}
std::vector<double> regression(const std::vector<double>& x, const std::vector<double>& y,
int epochs, double learning_rate){
if(!epochs) epochs = epoch;
double _m = 0;
double _b = 0;
std::vector<double> _values(2);
int N = x.size();
for(int i = 0; i < epochs; i++){
_values[0] = _b, _values[1] = _m;
double dm = 0;
double db = 0;
double cost = 0;
for(int j = 0; j < N; j++){
double p = hypothesis(_values, x[j]);
cost += pow(y[j] - p, 2);
dm += (-2.0 / N) * (x[j] * (y[j] - p));
db += (-2.0 / N) * (y[j] - p);
}
cost /= N;
_m = _m - (learning_rate * dm);
_b = _b - (learning_rate * db);
if ((i + 1) % 100 == 0)
std::cout << "Epoch: " << (i + 1) << " Cost: " << cost << std::endl;
}
std::vector<double> result(2);
result[0] = _m, result[1] = _b;
return result;
}
static PyObject * fit(PyObject * self, PyObject * args){
PyObject *x;
PyObject *y;
double learning_rate;
int epochs;
int N;
if(!PyArg_ParseTuple(args, "00di0i", &x, &y, &epochs, &learning_rate, &N)){
return nullptr;
}
std::vector<double> _x(N), _y(N);
for(int i = 0; i < N; i++){
_x[i] = PyFloat_AsDouble(PyList_GetItem(x, (Py_ssize_t)i));
_y[i] = PyFloat_AsDouble(PyList_GetItem(y, (Py_ssize_t)i));
}
std::vector<double> _result = regression(_x, _y, epochs, learning_rate);
PyObject *result = PyTuple_New(2);
for(int i = 0; i < 2; i++){
PyTuple_SetItem(result, i, PyFloat_FromDouble(_result[i]));
}
return Py_BuildValue("s", result);
}
static PyMethodDef linreg_methods[] = {
{"fit", (PyCFunction)fit, METH_VARARGS, "Linear Regression"},
{nullptr}
};
static PyModuleDef linear_regression = {
PyModuleDef_HEAD_INIT,
"linear_regression"
"Linear Regression",
-1,
linreg_methods
};
PyMODINIT_FUNC PyInit_linear_regression(void){
return PyModule_Create(&linear_regression);
}
The output I get is error: unknown type name 'PyModuleDef'.
I can't seem to understand what the problem is.
You will need to make sure the included Python.h is from the Python3.x build, and that you link to the corresponding library, for example, on Linux that would be:
g++ my_module.cpp -I/usr/include/python3.8/ -lpython3.8
But on MacOS this file would be dependent on where/how you installed Python3. You should be able to use locate Python.h and find the Python3 directory.
I have the following c++ and header file, which I would like to compile in Cython:
c++ code:
\\ CA.cpp c++ code
#include "CA.h"
#include<iostream>
#include <vector>
Cell::Cell() {}
// construct cell: cell is defined with position (x,y,z coordinates) and neighborhood
Cell::Cell(int x, int y, int z) {
this->x = x;
this->y = y;
this->z = z;
std::vector<int> ngh;
}
// Return the neighbors of the cell
void Cell::neighbors( ) {
std::vector<int> a{ -1, 0, 1 };
std::vector<int> ranges(gridSize, 0);
for (int i = 0; i < ranges.size(); i++) {
ranges[i] = i;
}
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
for (int k = -1; k <= 1; k++) {
int x_ngh = ranges[Cell::x + i];
int y_ngh = ranges[Cell::y + j];
int z_ngh = ranges[Cell::z + k];
int id_ngh = x_ngh + (y_ngh - 1) * gridSize + (z_ngh - 1) * gridSize * gridSize;
Cell:ngh.push_back(id_ngh);
}
}
}
}
and header file:
\\CA.h
#ifndef CA_H
#define CA_H
#include <vector>
const int gridSize = 400;
class Cell {
public:
int x, y, z;
std::vector<int> ngh;
Cell();
Cell(int x, int y, int z);
void neighbors();
};
#endif
In order to compile the code using cython I created CA.pxd file:
cdef extern from "CA.cpp":
pass
# Declare the class with cdef
cdef extern from "CA.h":
cdef cppclass Cell:
Cell() except +
Cell(int, int, int) except +
int x,y,z
neighbors()
and CA.pyx
# distutils: language = c++
from CA cimport *
from libcpp.vector cimport vector
cdef class PyCell:
cdef Cell c_cell
def __cinit__(self, int x, int y, int z):
self.c_cell = Cell(x,y,z)
def neighbors(self):
return self.c_cell.neighbors()
Finally, I created setup.py file:
from Cython.Build import cythonize
setup(ext_modules=cythonize("CA.pyx"))
When I run the command:
python setup.py build_ext --inplace
I get an error LINK : error LNK2001: unresolved external symbol PyInit_CA. I don't know why. Any help greatly appreciated.