Wednesday, May 31, 2017

C++ libraries, boost and eigen

c++ check point: Bjarne Stroutstrup, file io, class, template
c++ check point 2: vector/array, char/string, map, auto, lambda, sort, unique
I came to realize the huge blindspot in my “Data Structure” class 5 years ago. The professor, head of our CS department, never taught us how to use C++ libraries. He asked us to implement array, vector, linked list and tree from scratch. These assignments did help us understand the building block of data structure. But we should never end there.
Just a few days ago when I was preparing for a C++ interview, I learned to use vector and sort, and appreciated the beauty of pointer. I came to realize that Python has hidden so many implementation details. On one hand it is easy to use and reach more users, but on the other hand it slow down the calculation speed and it is less flexible to make some fundamental changes.
Python has package management tools such as pip and conda. But for c++, it only use brew. And the default C++ STL such as vector, algorithm is located at /Library/Developer/CommandLineTools/usr/include/c++/v1
I am confused that several places storing somewhat differently command lines:
/Library/Developer/CommandLineTools/usr/bin
/usr/bin
For the same command, there may be multiple alias, such as: c++, clang, cc.
What I really want to talk about is these 2 important c++ libraries:
Boost and Eigen.

how to use Boost

$ brew install boost
🍺  /usr/local/Cellar/boost/1.64.0_1: 12,628 files, 398.7MB
Boost is a collection of extensive libraries. And the most popular ones has been migrated into C++11, C++14, etc.
In my “warmup” project, my CMakeLists.txt file is as follows:
cmake_minimum_required(VERSION 3.7)
project(warmup)

find_package(Boost 1.64.0 COMPONENTS system filesystem REQUIRED)  # library + version
if(Boost_FOUND)
    message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
    message(STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}")
    message(STATUS "Boost_VERSION: ${Boost_VERSION}")
    include_directories(${Boost_INCLUDE_DIRS})
endif()

set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(warmup ${SOURCE_FILES})

if(Boost_FOUND)
    target_link_libraries(warmup ${Boost_LIBRARIES})  # link
endif()
Note: find_package() can automatically find the include and library dir: /usr/local/lib/*, which is actually the alias of the real ones that brew has installed /usr/local/Cellar/boost/1.64.0_1. Surprisingly, manually setting the dir will cause … version.hpp" cannot be read error.
Alternatively, you can copy all the library files to your project folder and use #include "boost/xxx", which is more space costly.
The following cpp codes can be used to test whether the boost library is properly configured.
#include <boost/lambda/lambda.hpp>
#include <iostream>
int main(){
    typedef std::istream_iterator<int> in;
    std::cout << "Type in any number: ";
    std::for_each(
            in(std::cin), in(), std::cout
                    << (boost::lambda::_1 * 10)
                    << "\nType in another number: " );
}

how to use Eigen

$ brew install eigen
$ brew list eigen
/usr/local/Cellar/eigen/3.3.3/include/eigen3/ (477 files)
/usr/local/Cellar/eigen/3.3.3/share/cmake/Modules/FindEigen3.cmake
/usr/local/Cellar/eigen/3.3.3/share/eigen3/ (4 files)
/usr/local/Cellar/eigen/3.3.3/share/pkgconfig/eigen3.pc
The whole Eigen folder is only 5.5 /3.8 MB (before/after compilation), which contains a batch of headers and their corresponding cpp files stored in src folder.
There are 2 ways to use eigen libraries:
  1. copy the whole eigen folder to the project folder. write #include "Eigen/Dense" in main.cpp.
  2. keep eigen folder where brew put it. write #include <Eigen/Dense> in main.cpp. Add include_directories (/usr/local/Cellar/eigen/3.3.3/include/eigen3/) in “CMakeLists.txt”.
We are using the Dense here, which is a header condensing 7 headers together, such as Coure, LU, QR, EigenValues, Geometry.

data type

In STL, list is implemented as vector<int> a (5,0) or array<int, 3> ={0,0,0}.
In Eigen, it is interesting that the data class is named as [Matrix/Vector][1234X][ifdc]. For example, MatrixXf means Matrix with a dynamic size and filled with float numbers.Vector3i means a Vector of size 3 and filled with integers.
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main(){
    MatrixXf m1;
    m1.setOnes(2,3);
    cout<<"m1_1=\n"<<m1<<endl;
    m1 << 1.3, 4,-8,
            0,0.9,2; // manual input, match existing size
    cout<<"m1_2=\n"<<m1<<endl;
    cout<< m1(1,1) <<endl; // access by ()
    m1 = MatrixXf:: Zero(2,5); // change sizes
    cout<<"m1_3=\n"<<m1<<endl;
    m1.setRandom();
    cout<<"m1_4=\n" <<m1 <<endl;
      m1 = m1.array() * m1.array(); // element-wise operation
    cout<<"m1_5=\n" <<m1 <<endl;

    Vector3i v1 = Vector3i::Ones();
    cout<<"v1=\n"<<v1<<endl;
    cout<< v1(0)<<v1[0]<<endl;
    cout<<"v1=\n"<<v1.transpose()<<endl;

    MatrixXf m2(5,2);
    m2.setRandom();
    cout << m1*m2 <<endl;
    cout << v1.dot(v1) <<endl;
    cout << m1.maxCoeff() <<endl;
    cout << m1.mean() <<endl;
}

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.