Please stay healthy and well!

Marty Walsh

UMB Chromebook Drive

Remote Lectures

All Meetings

Schedule here:

Functions, Classes

Arrays, Vectors

Templates

GIBBS Cluster

Cython

Run our C++ code in Python using Cython

and compare timing against NumPy

Analyze a bunch of numbers and calculate min, max, mean, stddev.

void test_get_min_float() {

  std::vector<float> somevalues;

  somevalues.push_back(1.1);
  somevalues.push_back(2.31);
  somevalues.push_back(3.4);
  somevalues.push_back(-241.44);
  
  assert(get_min_float(somevalues)==-241.44);
  std::cout << "Test OK!" << std::endl;
    
}

Never got executed!

void test_get_min_float() {

  std::vector<float> somevalues;

  somevalues.push_back(1.1);
  somevalues.push_back(2.31);
  somevalues.push_back(3.4);
  somevalues.push_back(-241.44);
  
  float diff = std::abs( -241.44 ) - std::abs( get_min_float(somevalues) );
  
  assert(diff < 0.0005);
  std::cout << "Test OK!" << std::endl;
    
}

Check if we have a very small difference between two floats..

We can not just compare floats..

float onevalue = 0.33333333333333;

float secondvalue = 1/3;

if (onevalue == secondvalue) {

	// cancel life-support
	// ...
}

Developer is in charge of precision..

All languages do this more or less problematically!

Software Development Models

Predictive

Adaptive

As rigid as possible as flexible as needed

Templates

Generic Programming

Type-Independent

"Blueprint"

Advanced!

template <typename T>
class Stats {
    
    public:
        static T get_min(std::vector<T> v);
        static T get_max(std::vector<T> v);
        static float get_mean(std::vector<T> v);
        
};

template <typename T>
T Stats<T>::get_min(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::min(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
T Stats<T>::get_max(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::max(minvalue, v[i]);
        
    }
    
    return minvalue;
}
template <typename T>
float Stats<T>::get_mean(std::vector<T> v) {
    
    float sum = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        sum += v[i];
        
    }
    
    sum /= v.size();
    
    return sum;
}

Templated Classes!

Cython!

Calling C++ from Python

Why?

Python code might be slow

def sum_even_no(x):
  y = 0
  for i in range(x):
    if i%2 == 0:
      y += i
  return y
def sum_even_no(x):
  cdef int y = 0
  cdef int i
  for i in range(x):
    if i%2 == 0:
      y += i
  return y
import timeit

cy = timeit.timeit('''test_cy.sum_even_no(500)''',setup = 'import test_cy', number=1000)

py = timeit.timeit('''test_py.sum_even_no(500)''',setup = 'import test_py', number=1000)

py/cy

Cython is 18.43x faster!

Python

Cython

Python

Cython

m.pyx

m.c

m.so

Generated C++ Code

Compiled to Shared Library

But before we do this...

Python vs. cppyy Comparison by Steve Pieper, Isomics Inc.

Code?

What do we have?

stats.cc

What do we need?

setup.py

statistics.pyx

#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cmath>

template <typename T>
class Stats {
    
    public:
        T get_min(std::vector<T> v);
        T get_max(std::vector<T> v);
        float get_mean(std::vector<T> v);
        float get_stddev(std::vector<T> v);
        
};

template <typename T>
T Stats<T>::get_min(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::min(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
T Stats<T>::get_max(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::max(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
float Stats<T>::get_mean(std::vector<T> v) {
    
    float sum = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        sum += v[i];
        
    }
    
    sum /= v.size();
    
    return sum;
}

template <typename T>
float Stats<T>::get_stddev(std::vector<T> v) {

    float stddev = 0;

    float mean = Stats<T>::get_mean(v);

    for(int i=1; i<v.size(); i++) {
        
        stddev += std::pow(v[i] - mean, 2);
        
    }

    return std::sqrt(stddev / v.size());

}

void test_get_min() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;
  
  assert(stats.get_min(somevalues)==-241);
  std::cout << "Test OK!" << std::endl;
    
}

void test_get_max() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;
  
  assert(stats.get_max(somevalues)==3);
  std::cout << "Test OK!" << std::endl;
    
}

void test_get_mean() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;

  float diff = std::abs(stats.get_mean(somevalues)) - std::abs(-58.675);

  assert(diff < 0.0005);

  std::cout << "Test OK!" << std::endl;
    
}

void test_get_stddev() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;

  float diff = std::abs(stats.get_stddev(somevalues)) - std::abs(105.26712152899404);

  assert(diff < 0.0005);

  std::cout << "Test OK!" << std::endl;

}

int main()
{
    
  test_get_min();
  test_get_max();
  test_get_mean();
  test_get_stddev();
  
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>

template <typename T>
class Stats {
    
    public:
        static T get_min(std::vector<T> v);
        static T get_max(std::vector<T> v);
        static float get_mean(std::vector<T> v);
        
};

template <typename T>
T Stats<T>::get_min(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::min(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
T Stats<T>::get_max(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::max(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
float Stats<T>::get_mean(std::vector<T> v) {
    
    float sum = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        sum += v[i];
        
    }
    
    sum /= v.size();
    
    return sum;
}

void test_get_min() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);
  
  assert(Stats<float>::get_min(somevalues)==-241);
  std::cout << "Test OK!" << std::endl;
    
}

void test_get_max() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);
  
  assert(Stats<float>::get_max(somevalues)==3);
  std::cout << "Test OK!" << std::endl;
    
}

void test_get_mean() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  assert(Stats<float>::get_mean(somevalues) == -58.675);

  std::cout << "Test OK!" << std::endl;
    
}

int main()
{
    
  test_get_min();
  test_get_max();
  test_get_mean();
  
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cmath>

template <typename T>
class Stats {
    
    public:
        T get_min(std::vector<T> v);
        T get_max(std::vector<T> v);
        float get_mean(std::vector<T> v);
        float get_stddev(std::vector<T> v);
        
};

template <typename T>
T Stats<T>::get_min(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::min(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
T Stats<T>::get_max(std::vector<T> v) {
    
    T minvalue = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        minvalue = std::max(minvalue, v[i]);
        
    }
    
    return minvalue;
}

template <typename T>
float Stats<T>::get_mean(std::vector<T> v) {
    
    float sum = v[0];
    
    for(int i=1; i<v.size(); i++) {
        
        sum += v[i];
        
    }
    
    sum /= v.size();
    
    return sum;
}

template <typename T>
float Stats<T>::get_stddev(std::vector<T> v) {

    float stddev = 0;

    float mean = Stats<T>::get_mean(v);

    for(int i=1; i<v.size(); i++) {
        
        stddev += std::pow(v[i] - mean, 2);
        
    }

    return std::sqrt(stddev / v.size());

}

void test_get_min() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;
  
  assert(stats.get_min(somevalues)==-241);
  std::cout << "Test OK!" << std::endl;
    
}

void test_get_max() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;
  
  assert(stats.get_max(somevalues)==3);
  std::cout << "Test OK!" << std::endl;
    
}

void test_get_mean() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;

  float diff = std::abs(stats.get_mean(somevalues)) - std::abs(-58.675);

  assert(diff < 0.0005);

  std::cout << "Test OK!" << std::endl;
    
}

void test_get_stddev() {

  std::vector<float> somevalues;

  somevalues.push_back(1.3);
  somevalues.push_back(2);
  somevalues.push_back(3);
  somevalues.push_back(-241);

  Stats<float> stats;

  float diff = std::abs(stats.get_stddev(somevalues)) - std::abs(105.26712152899404);

  assert(diff < 0.0005);

  std::cout << "Test OK!" << std::endl;

}

int main()
{
    
  test_get_min();
  test_get_max();
  test_get_mean();
  test_get_stddev();
  
}

What do we have?

stats.cc

What do we need?

setup.py

statistics.pyx

python setup.py build_ext --inplace

.so

conda install cython

from setuptools import setup

from Cython.Build import cythonize

setup(ext_modules=cythonize("statistics.pyx"))

setup.py

statistics.pyx

CS410 Lecture 26

By Daniel Haehn

CS410 Lecture 26

Slides for CS410 Software Engineering at UMass Boston. See https://cs410.net!

  • 286

More from Daniel Haehn