Mar 032014
 

This quote is from a book on the administration of Linux systems, but it applies as well to the world of programming.

More accurately, it may work perfectly almost all of the time but fail mysteriously and sporadically, leaving no evidence of what went wrong. Welcome to hell.

 March 3, 2014  Programming No Responses »
Apr 262013
 

I recently compiled my psi4 libraries using C++11 and started using some of the features of this language. There are several new useful features of the language and library additions. Here are some that I have started to use in my code.

  • Tuples – Tuples are containers that can collect different type of data. Here is an example of how I have been using tuples in my code:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    // a vector of tuples (double,int,int)
    std::vector<std::tuple<double,int,int>> vec_tuple;
     
    // tuples can be added with std::make_tuple
    vec_tuple.push_back( std::make_tuple(1.0,2,3) );
    vec_tuple.push_back( std::make_tuple(3.0,3,5) );
     
    // Let's sort the vector of tuples
    std::sort(vec_tuple.begin(),vec_tuple.end());
     
    // Loop over the first ten elements of the sorted vector
    for (int i = 0; i < 10; ++i){
         double c;
         int m,n;
         // access the elements by unpacking them with std::tie ...
         std::tie(c,m,n) = vec_tuple[i];
     
        // ... or use the std::get function
        c = std::get<0>(vec_tuple[i]); 
    }
 April 26, 2013  Programming No Responses »
Feb 202013
 

Recently I have been using the Boost C++ library to perform some string manipulations in the programs that I write. The functions included in Boost are so useful that I wanted to share some of the ones that I like the most.

  • split (and trim_copy)
    The Boost string algorithm library contains many routines that are found in scripting languages but that are not included in the C++ standard library. A good example is extracting all the words in a string containing words separated by spaces.
    The following bit of code trims all the leading and trailing spaces in the string line

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #include <boost/algorithm/string.hpp>
     
    using namespace std;
    using namespace boost; // trim_copy, split, and is_any_of are contained in the boost namespace
     
    // Trim spaces so that later we can split properly
    string trimmed_line = trim_copy(line);
    // Create a vector of strings
    vector<string> split_string;
    // Split the words in the string line when one or more spaces are found
    split(split_string, trimmed_line, is_any_of(" "), token_compress_on );

    So if line = "C 0.000 0.000 1.000" then the code above will give split_string = {"C", "0.000", "0.000", "1.000"}.

  • format
    I am a big fan of format because it offers a printf-style syntax and is string-friendly. The output of format can be directed to a stream via <<, but I find myself using it mostly as a string and so I use the utility function str to convert the output of format:

    1
    2
    3
    4
    5
    6
    7
    8
    
    #include <boost/format.hpp>
     
    using namespace std;
    using namespace boost; // format is contained in the boost namespace
     
    double x = 19.2224;
    double y = 127.001;
    string formatted_double = str(format("%12.9f %12.9f") % x % y);
  • join
    Boost join is a useful function to join strings placing a separator between them:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #include <boost/algorithm/string/join.hpp>
     
    using namespace std;
    using namespace boost; // join is contained in the boost namespace
     
    std::vector<std::string> list;
    list.push_back("3");
    list.push_back("5");
    list.push_back("7");
    std::string joined = boost::algorithm::join(list, ",");
    std::cout << joined << std::endl;  // will print "3,5,7"
 February 20, 2013  Programming No Responses »
Dec 152012
 

Today, as I was debugging a molecular dynamics code I stumbled on a bug. After finding the bug and correcting it, I went to make a tea and while I was waiting for the microwave to heat up the water, I realized that although I could still remember the exasperating way in which the bug manifested itself, I already forgot the cause of the bug. I then concluded that it would be wise-and perhaps even useful-to other programmers to collect the bugs that I have stumbled upon so as to remember and avoid to make the same mistakes more than once. Here is the first one.

Forgetting to define the copy constructor. This is a pretty silly mistake, since once you create a class in C++ you should quickly write the copy constructor and the assignment operator (=). In my case when I ran my MD code in gdb I was getting an error in the line:

1
2
3
4
5
6
7
void FF_TullyTest1::compute_force(Snapshot& snapshot)
{
  ...
  // Build the electronic Hamiltonian
  double V11 = sign * A * (1.0 - std::exp(-B * std::fabs(x)));
  double V12 = C * std::exp(-D * x * x);
  H[0][0] = V11;  // GDB says: "H[0][0] is not a valid memory address"

After confirming that H (a matrix member of the class FF_TullyTest1) is allocated, I was a bit puzzled. It turns out that the bug originated from a different class:

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/// Stores a trajectory
class Trajectory
{
public:
    /// Initialize with no snapshot data
    Trajectory(int id, int natoms, int nstates, std::vector<double> mass, std::vector<int> Z);
    /// Initialize with snapshot data
    Trajectory(int id, int natoms, int nstates, std::vector<double> mass, std::vector<int> Z,
               std::vector<vec_double> r, std::vector<vec_double> v, int state);
    ~Trajectory();
    ...
    /// Position (au)
    vec_double* r_;
    /// Position in the image cell (au)
    vec_double* ri_;

The problem is that the class Trajectory contains a few pointers and does not define a copy constructor. This combination is pretty dangerous because the default copy constructor is not pointer friendly. So a when a Trajectory object is copied using the default copy constructor, like in the code below, you have a bug:

    // Copy the trajectory object and link the snapshot object
    trajectory_ = SharedTrajectory(new Trajectory(trajectory));

The problem is that instead of creating a copy of the data, the default copy constructor just performs a copy of all the class data (including pointers) and calls the default constructor for each of its member objects. Solution: write (and remember to update) a customized copy constructor. All this may be avoided if instead of storing the coordinates as arrays (vec_double* r_;) I were to use the standard template library vector (std::vector r_;). However, I doubt vector would be as fast as a raw array [In C++11 one can easily access the underlying array of a std::vector directly with a new function called data()].

 December 15, 2012  Programming No Responses »