Thursday, June 24, 2021

Create Basic Python 3.10(beta) C++ Extensions on Fedora Linux 34

 Detecting all prime numbers in given range is supposed to be performed by C++ code below as a procedure invoked from Python.  Tested with both Python 3.9.5 and Python 3.10 (beta)  via Python API.  Refactoring code proposed in python-cpp-extension @github


Vectors are part of STL. Vectors in C++ are sequence containers representing arrays that can change their size during runtime . They use contiguous storage locations for their elements just as efficiently as in arrays, which means that their elements can also be accessed using offsets on regular pointers to its elements.

Procedure primesList(int lim_down,int lim_up) has type of std::vector<int> and accept 2 parameters rather then 1 in original version. Logic itself of primesList is different from the one implemented in "sieve_of_eratosthenes" in original code.

(.env) [boris@sever33fedora PRIMESPLUS]$ cat test.h   
#pragma once
#include <vector>
#include <cstddef>

namespace xps {

std::vector<int> primesList(int lim_down,int lim_up) ;

}  // namespace xps

(.env) [boris@sever33fedora PRIMESPLUS]$ cat test.cpp
#include <Python.h>
#include <iostream>
#include <vector>
#include "test.h"
#pragma GCC diagnostic ignored "-Wsign-compare"

namespace xps {

std::vector<int>  primesList(int lim_down,int lim_up)
{     
   std::vector<int> result;
   int i,prime,n;
   for(n=lim_down; n <= lim_up; n++)
   {
       prime = 1;
       for(i=2; i<n; i++)
           if(n%i == 0)
           {
               prime = 0;
               break;
           }
       if(prime)
       {
          result.push_back(n);
       }
   }
   return result;
 }
} //namespace

// Our Python binding to our C function
// This will take two non-keyword arguments

extern "C"{}
namespace {


static PyObject *primes(PyObject* self, PyObject* args)
{
   // PyArg_ParseTuple accepts two integer arguments
   // to obtain all prime numbers between "k" and "m"

   int m,k;
   if(!PyArg_ParseTuple(args,"ii",&k,&m))
       return NULL;

   std::vector<int> primes = xps::primesList(k,m);
   PyObject* result = PyList_New(primes.size());
   for(int i = 0; i < primes.size(); i++) {
       PyList_SetItem(result, i, PyLong_FromLong(primes[i]));
   }
   return result;
}

// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
   { "primes", primes, METH_VARARGS, "Calculate prime numbers" },
   { NULL, NULL, 0, NULL }
};

// Our Module Definition struct
static struct PyModuleDef myModule = {
   PyModuleDef_HEAD_INIT,
   "myModule",
   "Test Module",
   -1,
   myMethods
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
   return PyModule_Create(&myModule);
};
} // namespace

(.env) [boris@sever33fedora PRIMESPLUS]$ 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', ['test.cpp'])])

(.env) [boris@sever33fedora PRIMESPLUS]$ python3.10 setup.py install

(.env) [boris@sever33fedora PRIMESPLUS]$ ll
total 20
drwxrwxr-x. 4 boris boris   63 Jun 25 01:19 build
-rw-rw-r--. 1 boris boris  144 Jun 25 00:06 MyProgList.py
-rw-rw-r--. 1 boris boris  280 Jun 24 22:26 MyProg.py
-rw-rw-r--. 1 boris boris  348 Jun 24 21:32 setup.py
-rw-rw-r--. 1 boris boris 1690 Jun 25 01:17 test.cpp
-rw-rw-r--. 1 boris boris  145 Jun 25 01:14 test.h


(.env) [boris@sever33fedora PRIMESPLUS]$ cat MyProgList.py    
import myModule
b = int(input("\nInput down limit :"))
a = int(input("\nInput upper limit : "))
print(myModule.primes(b,a))

(.env) [boris@sever33fedora PRIMESPLUS]$ python3.10 MyProgList.py

Input down limit :100

Input upper limit : 500  
[101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191
, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 28
3, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 4
01, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]











































No comments:

Post a Comment