Thursday, August 5, 2021

Python Wrapper for C++ solving the recent YandexQ problem

In this post I follow approach suggested  in How to wrap a C++ object using pure Python Extension API  which differs from C++ coding technique been presented earlier.  Public Class Strike containing method "filter" is supposed to be declared. Later on in PyStrike_init( ) new instance of this class is been created. Structure PyStrike been declared right after "using abc::Strike", has a field PtrObject which is a pointer to Strike in PyStrike_init( ) following assignment is taken place  self->ptrObj=new Strike(fftSize). This assignment allows in PyStrike_filter( ) to invoke "filter" method and obtain the resulting number via call "retval = (self->ptrObj)->filter(freq,sqnc)" to return retval to Python as follows "return Py_BuildValue("l",retval)"

Same technique has been used in my recent blog entry Another version of Python to C++ Extension building Catalan Sequence

Problem itself

ABCDEF is a six-digit number. They are all different and are arranged from left to right in ascending order. The number is a complete square. Detect at least one six-digit ABCDEFs having this feature .

(.env) [boris@fedora33server VOICE]$ ll

total 20

drwxrwxr-x. 4 boris boris   63 Aug  5 19:13 build

drwxrwxr-x. 2 boris boris  120 Aug  5 17:41 CPP

-rw-rw-r--. 1 boris boris  164 Aug  5 17:36 setup.py

-rw-rw-r--. 1 boris boris  824 Aug  5 19:10 Strike.cpp

-rw-rw-r--. 1 boris boris  272 Aug  5 18:58 Strike.h

-rw-rw-r--. 1 boris boris 2104 Aug  5 19:09 strikeWrapper.cpp

-rw-rw-r--. 1 boris boris  130 Aug  5 19:01 test.py

(.env) [boris@fedora33server VOICE]$ cat Strike.h

#pragma once

#include <cstddef>

#include <cstdio>

namespace abc {

    class Strike {

    public:

        double *mem;

        long fftSize;

        Strike(long fftSize);

        ~Strike();

        long filter(long freq,long nqc);

        long CaughIt(int n);

    };

}

(.env) [boris@fedora33server VOICE]$ cat Strike.cpp

#include <cstdio>

#include <cstddef>

#include <string>

#include "Strike.h"

#pragma GCC diagnostic ignored "-Wsign-compare"

namespace abc

    Strike::Strike(long fftSize) {

        printf("c++ constructor of Strike\n");

        this->fftSize=fftSize;

        mem=new double[fftSize];

        } 

    Strike::~Strike() { delete [] mem; } 

    long Strike::filter(long freq,long sqc) {

        printf("c++ Strike filter method\n");

        return (CaughIt(sqc));

    }

    long Strike::CaughIt(int n) 

    { 

     for (int i=200; i < n; i++)

     {

     std::string ans = std::to_string(i*i);

      if ((int(ans[0])< int(ans[1])) && \ 

         (int(ans[1]) < int(ans[2])) && \

         (int(ans[2]) < int(ans[3])) && \

         (int(ans[3]) < int(ans[4])) && \

         (int(ans[4]) < int(ans[5])))    

              return (i*i);

     }

    }

}

(.env) [boris@fedora33server VOICE]$ cat strikeWrapper.cpp

#include <Python.h>

#include <cstdio>

#include <string.h>

#include "Strike.h"

#pragma GCC diagnostic ignored "-Wsign-compare"

using abc::Strike;

typedef struct {

    PyObject_HEAD

    Strike * ptrObj;

PyStrike;

static PyModuleDef blademodule = {

    PyModuleDef_HEAD_INIT,

    "blade",

    "Example module that wrapped a C++ object",

    -1,

    NULL, NULL, NULL, NULL, NULL

};

static int PyStrike_init(PyStrike *self, PyObject *args, PyObject *kwds)

// initialize PyStrike Object

{

    long fftSize;

    if (! PyArg_ParseTuple(args, "l", &fftSize))

        return -1;

    self->ptrObj=new Strike(fftSize);

    return 0;

}

static void PyStrike_dealloc(PyStrike * self)

// destruct the object

{

    delete self->ptrObj;

    Py_TYPE(self)->tp_free(self);

}

static PyObject * PyStrike_filter(PyStrike* self, PyObject* args)

{

    long freq;

    long retval;

    long sqnc ;

    if (! PyArg_ParseTuple(args, "ll", &freq,&sqnc))

        return Py_False;

    retval = (self->ptrObj)->filter(freq,sqnc);

    return Py_BuildValue("l",retval);

}

static PyMethodDef PyStrike_methods[] = {

    { "filter", (PyCFunction)PyStrike_filter,METH_VARARGS,"filter the mem blade" },

    {NULL}  /* Sentinel */

};

static PyTypeObject PyStrikeType = { PyVarObject_HEAD_INIT(NULL, 0)

           "blade.Strike"   /* tp_name */

                                };

PyMODINIT_FUNC PyInit_blade(void)

// create the module

{

    PyObject* m;

    PyStrikeType.tp_new = PyType_GenericNew;

    PyStrikeType.tp_basicsize=sizeof(PyStrike);

    PyStrikeType.tp_dealloc=(destructor) PyStrike_dealloc;

    PyStrikeType.tp_flags=Py_TPFLAGS_DEFAULT;

    PyStrikeType.tp_doc="Strike objects";

    PyStrikeType.tp_methods=PyStrike_methods;

    PyStrikeType.tp_init=(initproc)PyStrike_init;

    if (PyType_Ready(&PyStrikeType) < 0)

        return NULL;

    m = PyModule_Create(&blademodule);

    if (m == NULL)

        return NULL;

    Py_INCREF(&PyStrikeType);

    PyModule_AddObject(m, "Strike", (PyObject *)&PyStrikeType); 

    return m;

}

(.env) [boris@fedora33server VOICE]$ cat setup.py

from distutils.core import setup, Extension

setup(name='bladePkg', version='1.0',  \

      ext_modules=[Extension('blade', ['strikeWrapper.cpp','Strike.cpp'])])

(.env) [boris@fedora33server VOICE]$ python setup.py install

running install

running build

running build_ext

building 'volume' extension

creating build

creating build/temp.linux-x86_64-3.9

gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/VOICE/.env/include -I/usr/include/python3.9 -c Strike.cpp -o build/temp.linux-x86_64-3.9/Strike.o

gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/VOICE/.env/include -I/usr/include/python3.9 -c strikeWrapper.cpp -o build/temp.linux-x86_64-3.9/strikeWrapper.o

creating build/lib.linux-x86_64-3.9

g++ -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.9/Strike.o build/temp.linux-x86_64-3.9/strikeWrapper.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/volume.cpython-39-x86_64-linux-gnu.so

running install_lib

copying build/lib.linux-x86_64-3.9/volume.cpython-39-x86_64-linux-gnu.so -> /home/boris/VOICE/.env/lib64/python3.9/site-packages

running install_egg_info

Removing /home/boris/VOICE/.env/lib64/python3.9/site-packages/volumePkg-1.0-py3.9.egg-info

Writing /home/boris/VOICE/.env/lib64/python3.9/site-packages/volumePkg-1.0-py3.9.egg-info

===================================

Python Wrapper itself

===================================

(.env) [boris@fedora33server VOICE]$ cat test.py

import blade

n = int(input("Input upper scan limit : " ))

v=blade.Strike(512)

result=v.filter(5,n)

print('result='+str(result))

===============

Runtime

===============

(.env) [boris@fedora33server VOICE]$ python test.py

Input upper scan limit : 1000

c++ constructor of Strike

c++ Strike filter method

result=134689

(.env) [boris@fedora33server VOICE]$ python test.py

Input upper scan limit : 500

c++ constructor of Strike

c++ Strike filter method

result=134689




















Now consider the different initial task

ABCDEF is a six-digit number. They are all different and are arranged from left to right in ascending order. The number is a complete square. Detect "all" six-digit ABCDEFs having this feature .

(.env) [boris@fedora33server ABCDFE]$ cat Strike.h
#pragma once
#include <cstddef>
#include <cstdio>
#include <vector>

namespace abc {

    class Strike {
    public:
        double *mem;
        long fftSize;
        Strike(long fftSize);
        ~Strike();
        std::vector<long> filter(long freq,long nqc);
        std::vector<long> CaughIt(int n);
    };
}
(.env) [boris@fedora33server ABCDFE]$ cat Strike.cpp
#include <cstdio>
#include <cstddef>
#include <string>
#include <vector>
#include "Strike.h"
#pragma GCC diagnostic ignored "-Wsign-compare"

namespace abc
    Strike::Strike(long fftSize) {
        printf("c++ constructor of Strike\n");
        this->fftSize=fftSize;
        mem=new double[fftSize];
        } 

    Strike::~Strike() { delete [] mem; } 

    std::vector<long> Strike::filter(long freq,long sqc) {
        printf("c++ Strike filter method\n");
        return (CaughIt(sqc));
    }
    std::vector<long> Strike::CaughIt(int n) 
    {
    std::vector<long>  vect; 
     for (int i=200; i < n; i++)
     {
     std::string ans = std::to_string(i*i);
      if ((int(ans[0])< int(ans[1])) && \ 
         (int(ans[1]) < int(ans[2])) && \
         (int(ans[2]) < int(ans[3])) && \
         (int(ans[3]) < int(ans[4])) && \
         (int(ans[4]) < int(ans[5])))    
              vect.push_back(i*i);
         
     }
     return(vect);
    }
} //namespace abc

(.env) [boris@fedora33server ABCDFE]$ cat strikeWrapper.cpp
#include <Python.h>
#include <cstdio>
#include <string.h>
#include <vector>
#include "Strike.h"
#pragma GCC diagnostic ignored "-Wsign-compare"
using abc::Strike;
typedef struct {
    PyObject_HEAD
    Strike * ptrObj;
} PyStrike;

static PyModuleDef blademodule = {
    PyModuleDef_HEAD_INIT,
    "blade",
    "Example module that wrapped a C++ object",
    -1,
    NULL, NULL, NULL, NULL, NULL
};
static int PyStrike_init(PyStrike *self, PyObject *args, PyObject *kwds)
// initialize PyStrike Object
{
    long fftSize;
    if (! PyArg_ParseTuple(args, "l", &fftSize))
        return -1;
    self->ptrObj=new Strike(fftSize);
    return 0;
}
static void PyStrike_dealloc(PyStrike * self)
// destruct the object
{
    delete self->ptrObj;
    Py_TYPE(self)->tp_free(self);
}
static PyObject * PyStrike_filter(PyStrike* self, PyObject* args)
{
    long freq;
    long sqnc ;
    if (! PyArg_ParseTuple(args, "ll", &freq,&sqnc))
        return Py_False;
    std::vector<long> retval = (self->ptrObj)->filter(freq,sqnc);
    PyObject* result = PyList_New(retval.size());
    for(int i = 0; i < retval.size(); i++) {
        PyList_SetItem(result, i, PyLong_FromLong(retval[i]));
    }
    return result;
}
static PyMethodDef PyStrike_methods[] = {
    { "filter", (PyCFunction)PyStrike_filter,METH_VARARGS,"filter the mem blade" },
    {NULL}  /* Sentinel */
};

static PyTypeObject PyStrikeType = { PyVarObject_HEAD_INIT(NULL, 0)
            "blade.Strike"   /* tp_name */
                                };

PyMODINIT_FUNC PyInit_blade(void)
// create the module
{
    PyObject* m;

    PyStrikeType.tp_new = PyType_GenericNew;
    PyStrikeType.tp_basicsize=sizeof(PyStrike);
    PyStrikeType.tp_dealloc=(destructor) PyStrike_dealloc;
    PyStrikeType.tp_flags=Py_TPFLAGS_DEFAULT;
    PyStrikeType.tp_doc="Strike objects";
    PyStrikeType.tp_methods=PyStrike_methods;
    PyStrikeType.tp_init=(initproc)PyStrike_init;

    if (PyType_Ready(&PyStrikeType) < 0)
        return NULL;

    m = PyModule_Create(&blademodule);
    if (m == NULL)
        return NULL;

    Py_INCREF(&PyStrikeType);
    PyModule_AddObject(m, "Strike", (PyObject *)&PyStrikeType); 
    return m;
}

(.env) [boris@fedora33server ABCDFE]$ python setup.py install

































No comments:

Post a Comment