Advertisement
homer512

Eigen Mandelbrot

Apr 22nd, 2017
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * Author: F. Philipp
  3.  *
  4.  * Translation of
  5.  * https://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=rust&id=4
  6.  * with minor changes
  7.  *
  8.  * Contains a bug resulting in slightly different results
  9.  */
  10.  
  11. #include <Eigen/Dense>
  12.  
  13.  
  14. #include <vector>
  15. // using std::vector
  16. #include <string>
  17. // using std::stoi
  18. #include <iostream>
  19. // using std::cout
  20. #include <algorithm>
  21. // using std::transform
  22. #include <climits>
  23. // using CHAR_BIT
  24.  
  25.  
  26. namespace {
  27.  
  28.   constexpr int MAX_ITER = 50;
  29.   constexpr int VLEN = CHAR_BIT;
  30.   using double_t = double;
  31.  
  32.   using Vecf64 = Eigen::Array<double_t, VLEN, 1>;
  33.  
  34.   template<class T>
  35.   using vector = std::vector<T, Eigen::aligned_allocator<T> >;
  36.  
  37.   struct CrCr2Chunk
  38.   {
  39.     Vecf64 cr, cr2;
  40.  
  41.     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  42.   };
  43.  
  44.   class Mandelbrot8
  45.   {
  46.     Vecf64 zr, zi, tr, ti, cr;
  47.     double_t ci, ci2;
  48.  
  49.     void advance(int iterations) noexcept
  50.     {
  51.       for(int i = 0; i < iterations; ++i) {
  52.         zi = 2. * zr * zi + ci;
  53.         zr = tr - ti + cr;
  54.         tr = zr.square();
  55.         ti = zi.square();
  56.       }
  57.     }
  58.     bool all_diverged() const noexcept
  59.     {
  60.       return ((tr + ti) > 4).all();
  61.     }
  62.     unsigned char to_byte() const noexcept
  63.     {
  64.       const Vecf64 trti = tr + ti;
  65.       unsigned char accu = 0;
  66.       for(int i = 0; i < VLEN; ++i) {
  67.         if(trti[i] <= 4.)
  68.           accu |= 0x80 >> i;
  69.       }
  70.       return accu;
  71.     }
  72.   public:
  73.     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  74.  
  75.     explicit Mandelbrot8(double_t ci) noexcept
  76.       : ci(ci),
  77.         ci2(ci * ci)
  78.     {}
  79.     unsigned char operator()(const CrCr2Chunk& col_invariant) noexcept
  80.     {
  81.       zr = col_invariant.cr;
  82.       zi = ci;
  83.       tr = col_invariant.cr2;
  84.       ti = ci2;
  85.       cr = col_invariant.cr;
  86.       advance(4);
  87.       constexpr int n = MAX_ITER / 5 - 1;
  88.       for(int i = 0; i < n; ++i) {
  89.         if(all_diverged())
  90.           return 0;
  91.         advance(4);
  92.       }
  93.       return to_byte();
  94.     }
  95.   };
  96.  
  97.   vector<CrCr2Chunk> make_column_invariant(int bytes_per_line)
  98.   {
  99.     const int pixels_per_line = bytes_per_line * VLEN;
  100.     const double_t inv = 2. / pixels_per_line;
  101.     vector<CrCr2Chunk> rtrn(bytes_per_line);
  102. #   pragma omp parallel for
  103.     for(int col_byte = 0; col_byte < bytes_per_line; ++col_byte) {
  104.       CrCr2Chunk& chunk = rtrn[col_byte];
  105.       for(int bit = 0; bit < VLEN; ++bit) {
  106.         const int col = col_byte * VLEN + bit;
  107.         chunk.cr[bit] = col * inv - 1.5;
  108.       }
  109.       chunk.cr2 = chunk.cr.square();
  110.     }
  111.     return rtrn;
  112.   }
  113.  
  114.   std::vector<unsigned char>
  115.   make_bitmap(const vector<CrCr2Chunk>& column_invariants)
  116.   {
  117.     const int bytes_per_line = static_cast<int>(column_invariants.size());
  118.     const int pixels_per_line = bytes_per_line * VLEN;
  119.     const double_t inv = 2. / pixels_per_line;
  120.     std::vector<unsigned char> bitmap(pixels_per_line * bytes_per_line);
  121. #   pragma omp parallel for
  122.     for(int row = 0; row < pixels_per_line; ++row) {
  123.       const int start = row * bytes_per_line;
  124.       const double_t ci = row * inv - 1.;
  125.       std::transform(column_invariants.begin(), column_invariants.end(),
  126.                      bitmap.begin() + start,
  127.                      Mandelbrot8(ci));
  128.     }
  129.     return bitmap;
  130.   }
  131.   void print_pbm(const std::vector<unsigned char>& bitmap,
  132.                  int pixels_per_line,
  133.                  std::ostream& binary_output)
  134.   {
  135.     binary_output << "P4\n" << pixels_per_line
  136.                   << ' ' << pixels_per_line
  137.                   << '\n';
  138.     binary_output.write(reinterpret_cast<const char*>(bitmap.data()),
  139.                         bitmap.size());
  140.     binary_output.flush();
  141.   }
  142. }
  143.  
  144. int main(int argc, char** argv)
  145. {
  146.   /* number of pixels in each dimension */
  147.   int pixels_per_line = 200;
  148.   if(argc > 1)
  149.     pixels_per_line = std::stoi(argv[1]);
  150.   const int bytes_per_line = pixels_per_line / VLEN;
  151.   pixels_per_line = bytes_per_line * VLEN;
  152.   const vector<CrCr2Chunk> column_invariants =
  153.     make_column_invariant(bytes_per_line);
  154.   const std::vector<unsigned char> bitmap = make_bitmap(column_invariants);
  155.   print_pbm(bitmap, pixels_per_line, std::cout);
  156. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement