<jupyter_start><jupyter_text>Compilation As you know, C++ is a compiled language. Since the beginning, you have used it as an interpreter language through the jupyter notebooks using xeus-cling. The further we go in this course, the more we will build applications requiring a finer structuring of the code, which will need to be split into several files. It is then no longer possible to use xeus-cling. So we will have to understand this compilation process to go further.In Jupyter notebooks, it is possible to create files by adding the magic `%%file filename` at the top of the cell. In the same way, it is possible to launch system commands by starting the cell with `!`.**Caution:** there must be only one line in the cell. First compilationLet's create our first C++ script.<jupyter_code>%%file first_compil.cpp
#include <iostream>
#include <vector>

void print(const std::vector<double>& v)
{
    for(auto& e: v)
    {
        std::cout << e << " ";
    }
    std::cout << std::endl; 
}

int main()
{
    std::vector<double> v{1.2, 4.2, 1.6};
    print(v);
    return 0;
}<jupyter_output><empty_output><jupyter_text>You can compile the program using the following command<jupyter_code>! g++ first_compil.cpp<jupyter_output><empty_output><jupyter_text>Let's see what has been created<jupyter_code>! ls -l<jupyter_output><empty_output><jupyter_text>We can see that the file `a.out` has been created and this file is an executable.<jupyter_code>! ./a.out<jupyter_output><empty_output><jupyter_text>You can specify the name of the executable using the option `-o`.<jupyter_code>! g++ first_compil.cpp -o my_exe
! ls -l
! ./my_exe<jupyter_output><empty_output><jupyter_text>Compilation flags and multiple source files Your project is growing and you now want to split it into several thematic files in order to gain readability. The main program is<jupyter_code>%%file main.cpp

#include<iostream>

int main()
{
    auto x = linspace(0, 1, 10);
    auto y = gaussian(0, 1, 10);
    auto z = add(x, y);
    
    std::cout << "c -> " << e << std::endl;
    return 0;
}<jupyter_output><empty_output><jupyter_text>And the other files are.<jupyter_code>%%file linspace.hpp
// add linspace declaration
%%file linspace.cpp
// add linspace definition
%%file gaussian.hpp
// add gaussian declaration
%%file gaussian.cpp

auto gaussian(double begin, double end, std::size_t n)
{
    auto x = linspace(begin, end, n);
    double middle = .5*(end - begin);
    std::vector<double> y(x.size());
    std::transform(x.cbegin(), x.cend(), y.begin(), [middle](auto v){return std::exp(-100*((v-middle)*(v-middle));};
    return y;
}
%%file operator.hpp

namespace operator
{
    auto add(const array_t& x, const array_t& y);
}

%%file operator.cpp
// add the implementation of the operator add<jupyter_output><empty_output><jupyter_text>The command line to build this application is<jupyter_code>! gcc main.cpp linspace.cpp gaussian.cpp operator.cpp -o my_app
! ./my_app<jupyter_output><empty_output><jupyter_text>Make the necessary changes for this program to compile and run correctly.Create a CMakeLists.txt that builds `my_app`  Compilation flags Each compiler has a huge list of options.<jupyter_code>! man gcc<jupyter_output><empty_output><jupyter_text>When you implement numerical methods to simulate physical phenomena, you want your application runs fast or be able to debug it.    The `-g` option allows the compiler to annotate your code. You can then debug it using an external tool such as [gdb](https://www.sourceware.org/gdb/).A compiler have many recipes to optimize your code. By default, the optimzations are not activated. The compilation flag is `-O` followed by the level of the optimization 1, 2, or 3.For more information about what the compiler performs during these steps, see [optimize options](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html).Let's take an example to see the benefit of such optimzation.<jupyter_code>%%file test_optimize_options.cpp

#include <array>
#include <vector>
#include <iostream>

int main()
{
    constexpr std::size_t n = 10000;
    std::vector<std::array<double, n>> a(n), b(n), c(n);
    
    for(std::size_t i = 0; i < n; ++i)
    {
        for(std::size_t j = 0; j < n; ++j)
        {
            c[i][j] = a[i][j] + b[i][j];
        }
    }
    std::cout << c[0][0] << std::endl;
    return 0;
}
! g++ test_optimize_options.cpp<jupyter_output><empty_output><jupyter_text>We measure the exectution time with the system command `time`<jupyter_code>! time ./a.out<jupyter_output>0
2.18user 0.67system 0:02.91elapsed 98%CPU (0avgtext+0avgdata 2346600maxresident)k
0inputs+0outputs (0major+586099minor)pagefaults 0swaps<jupyter_text>Invert the loop and see what happens.  Code organization A colleague has been working on a generative art project. He is very enthusiastic and would like to distribute what he has done. You realize that it's just a C++ file and that it would be nice to split it up to make it a bit more modular and add a build process using cmake.The file is called `splinart.cpp`.The code organization should be as followsAnd the functions will be in the following namespaces- `spline` and `splint` into `art::spline` and `searchsorted` into `art::spline::algorithm`- `linespace` and `line` into `art::shape`- `update_path` into `art::core`- `generative` into `art`Create this project with this organization using the implementation found in `splinart.cpp`. Your colleague is very happy with what you have done and would now like to see the results. So you suggest to add a dependency to [opencv](https://opencv.org/) to save the results as images.Modify the `CMakeLists.txt` in the root directory and add the opencv dependency as follows```find_package(OpenCV REQUIRED)```And when you build the library, `${OpenCV_LIBS}` must be added during the link.`main.cpp` in examples directory becomes<jupyter_code>#include <vector>
#include <random>
#include <tuple>
#include <algorithm>
#include <generative/core.hpp>
#include <generative/shape.hpp>

auto init_colors(std::size_t n)
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 255);

    std::vector<std::array<uchar, 4>> color(n);

    for(std::size_t i=0; i<n; ++i)
    {
        for(std::size_t c=0; c<3; ++c)
        {
            color[i][c] = dis(gen);
        }
        color[i][3] = 1;
    }
    return color;
}

int main()
{
    std::size_t nb_lines = 10;
    std::vector<art::array_t> x(nb_lines), y(nb_lines);

    double lo = .2, up = .8;
    std::size_t npoints = 15;

    auto yy = art::shape::linspace(lo, up, nb_lines);
    for(std::size_t i = 0; i < x.size(); ++i)
    {
        std::tie(x[i], y[i]) = art::shape::line(lo, up, yy[i], npoints);
        npoints++;
    }

    auto colors = init_colors(nb_lines);

    auto xs_func = [lo, up]()
    {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(0., 1.);

        std::size_t nsamples = 500;
        auto x = art::shape::linspace(lo + .05, up - .05, nsamples);
        std::for_each(x.begin(), x.end(), [&dis, &gen](double& e){ e += 1e-3*dis(gen);});
        return x;
    };

    cv::Mat img(1000, 1000, CV_8UC4);
    for(std::size_t i = 0; i < x.size(); ++i)
    {
        art::generative_art(img, x[i], y[i], xs_func, 1000, colors[i]);
    }
    cv::imwrite("output.png", img);

    return 0;
}<jupyter_output><empty_output><jupyter_text>Use the following code to see the output.<jupyter_code>#include <string>
#include <fstream>

#include "nlohmann/json.hpp"

#include "xtl/xbase64.hpp"

namespace nl = nlohmann;

namespace im
{
    struct image
    {   
        inline image(const std::string& filename)
        {
            std::ifstream fin(filename, std::ios::binary);   
            m_buffer << fin.rdbuf();
        }
        
        std::stringstream m_buffer;
    };
    
    nl::json mime_bundle_repr(const image& i)
    {
        auto bundle = nl::json::object();
        bundle["image/png"] = xtl::base64encode(i.m_buffer.str());
        return bundle;
    }
}
im::image picture("../cpp/splinart/step_2/build/output.png");
picture<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12678986660139518, 'fraction_numerical': 0.015298005140129727, 'mean_word_length': 3.9377643504531723, 'pattern_counts': {'":': 0, '<': 100, '<?xml version=': 0, '>': 77, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '447532', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2833, 'n_tokens_neox': 2703, 'n_words': 872, 'path': 'courses/compilation/notebooks/compilation.ipynb', 'repo_name': 'gouarin/MAP586', 'size': '8171'}