Saturday, July 24, 2021

Assembly of Python External C++ procedure returning the vector of objects of string type

 This post is an immediate followup for the most recent post at Lxer.com regarding return of one string. Consider the task already been treated with 2D vector and dumping the content of vector to disk file. This approach would allow us to solve the same task via to straight forward  returning vector of strings  from C++ procedure to Python module.

Remind the task itself 

Write a program that searches among the integers that belong to the numerical segment [174457;174505], numbers that have exactly two different natural divisors, not counting the unit and the number itself. For each of the found number, write these two divisors into the table on the screen with a new lines in ascending order of the product of these two divisors. Divisors in the table row must also follow in ascending order.

We intend to assembly  Python External C++ procedure using vector of strings to solve the the task mentioned above for segment [1744457;3044505] without significant performance penalty, which would affect pure Python module runtime.

In fact, this is an alternative way to get a solution without 2D vector which was suggested  in  http://lxer.com/module/newswire/view/302902/index.html

C++ procedure requires just 4 seconds to scan segment [1744457;3044505]


(.env) [boris@fedora33server STRINGVEC]$ cat procVector.h
#pragma once
#include <iostream>
#include <vector>
#include <cstddef>
#include <string>

namespace abc {

std::vector<std::string>  resultList(int m, int n);

}
(.env) [boris@fedora33server STRINGVEC]$ cat procVector.cpp
#include <iostream>
#include <vector>
#include <cstddef>
#include <cmath>
#include <string>
#pragma GCC diagnostic ignored "-Wsign-compare"

namespace abc {

std::vector<std::string>   resultList(int m, int n)
{
   std::vector<std::string> vec;
   std::string blank = " ";
   int j,cCount,cntDiv;

    for (int i = m; i <= n  ; i++) {
       cCount = 0 ;
       cntDiv = 0 ; 
       j = 2 ;
      while (cCount <= 1 && j <= int(sqrt(i)))
      {
          if (i%j == 0)
          {
           cntDiv = j;
           cCount +=1;
          }
          j += 1;
      }           
      if (cCount == 1 && cntDiv != i/cntDiv) 
      {        
         std::string answer = std::to_string(cntDiv) + blank;
         answer = answer + std::to_string(i/cntDiv);
         vec.push_back(answer);
       }
     } 
    return vec;
};
} //namespace

The core solution is provided by the same operations and API call as it has been done for a single string , but now performed inside the loop as follows. PyList_New() and PyList_SetItem()  work in particular case as they did for vector of integers

 std::vector<std::string>rez = abc::resultList(m1,n1);
 PyObject* result = PyList_New(rez.size());
 for(int i = 0; i < rez.size(); i++) {
 PyList_SetItem(result,i,PyUnicode_FromString(rez[i].c_str()));   }

where we again rely PyUnicode_FromString(rez[i].c_str())

(.env) [boris@fedora33server STRINGVEC]$ cat mainVector.cpp
#include <Python.h>
#include <iostream>
#include <vector>
#include <cstddef>
#include <cstdlib>
#include <string>
#include "procVector.h"
#pragma GCC diagnostic ignored "-Wsign-compare"

extern "C"{}

namespace {

static PyObject *resList(PyObject* self, PyObject* args)

{
 int m1,n1;
 if(!PyArg_ParseTuple(args,"ii",&m1,&n1))
        return NULL;

 std::vector<std::string>rez = abc::resultList(m1,n1);
 PyObject* result = PyList_New(rez.size());
 for(int i = 0; i < rez.size(); i++) {
 PyList_SetItem(result,i,PyUnicode_FromString(rez[i].c_str()));   }
  return result;
};

static PyMethodDef myMethodsTable[] = {

    { "resList", resList, METH_VARARGS, "Tracking DEMO VAR #25" },
    { NULL, NULL, 0, NULL }

};

static struct PyModuleDef myModule = {
    PyModuleDef_HEAD_INIT,
    "myModule",
    "Test Module",
    -1,
    myMethodsTable
};

PyMODINIT_FUNC PyInit_myModule(void)
{
    return PyModule_Create(&myModule);
};
} //namespace

(.env) [boris@sever33fedora STRINGVEC]$ cat setup.py
from distutils.core import setup, Extension
import sysconfig
language = 'c++'
std = 'c++20'
default_compile_args = sysconfig.get_config_var('CFLAGS').split()
extra_compile_args = [f"-std={std}", "-Wall", "-Wextra", "-Werror", "-DNDEBUG", "-O3"]
setup(name = 'myModule', version = '1.0',  \
  ext_modules = [Extension('myModule', ['mainVector.cpp','procVector.cpp'])])

Now build and install

(.env) [boris@fedora33server STRINGVEC]$ python setup.py install
running install
running build
running build_ext
building 'myModule' 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/STRINGVEC/.env/include -I/usr/include/python3.9 -c mainVector.cpp -o build/temp.linux-x86_64-3.9/mainVector.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/STRINGVEC/.env/include -I/usr/include/python3.9 -c procVector.cpp -o build/temp.linux-x86_64-3.9/procVector.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/mainVector.o build/temp.linux-x86_64-3.9/procVector.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so
running install_lib
copying build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so -> /home/boris/STRINGVEC/.env/lib64/python3.9/site-packages
running install_egg_info
Removing /home/boris/STRINGVEC/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info
Writing /home/boris/STRINGVEC/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info

(.env) [boris@fedora33server STRINGVEC]$ cat MyString.py
import myModule
# a = int(input("Input start   number : "))
# b = int(input("Input finish  number : "))
a = 1744457
b = 3044505
# a = 174457
# b = 174505
lst = myModule.resList(a,b)
print(*lst, sep = "\n")

(.env) [boris@fedora33server STRINGVEC]$ cat speed.sh
date
python MyString.py
date

(.env) [boris@fedora33server STRINGVEC]$ ./speed.sh | tee log
(.env) [boris@fedora33server STRINGVEC]$ head -4 log
Sat Jul 24 03:45:30 PM MSK 2021
643 2713
2 872231
233 7487
(.env) [boris@fedora33server STRINGVEC]$ tail -4 log
2 1522249
3 1014833
199 15299
Sat Jul 24 03:45:34 PM MSK 2021

























No comments:

Post a Comment