File: example_sparse_grids_07.cpp

package info (click to toggle)
tasmanian 8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,852 kB
  • sloc: cpp: 34,523; python: 7,039; f90: 5,080; makefile: 224; sh: 64; ansic: 8
file content (147 lines) | stat: -rw-r--r-- 6,219 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

#include "Tasmanian.hpp"
#include <chrono>
#include <random>

using namespace std;

/*!
 * \internal
 * \file example_sparse_grids_07.cpp
 * \brief Examples for the Tasmanian Sparse Grid module.
 * \author Miroslav Stoyanov
 * \ingroup TasmanianSGExamples
 *
 * Tasmanian Sparse Grids Example 7.
 * \endinternal
 */

/*!
 * \ingroup TasmanianSGExamples
 * \addtogroup TasmanianSGExamples7 Tasmanian Sparse Grids module, example 7
 *
 * \par Example 7
 * Benchmark Global vs. Sequence grids.
 */

/*!
 * \ingroup TasmanianSGExamples7
 * \brief Sparse Grids Example 7: Global vs. Sequence grids
 *
 * Sequence rules are those that form the next level by adding one point to the previous one,
 * in Tasmanian those rules are: TasGrid::rule_leja, TasGrid::rule_rleja, TasGrid::rule_rlejashifted,
 * TasGrid::rule_maxlebesgue, TasGrid::rule_minlebesgue, TasGrid::rule_mindelta.
 * Two implementations are provided that deal with such rules, Global grids that use
 * the standard Lagrange polynomial interpolation and Sequence grids that use Newton polynomials.
 * Mathematically the two implementations yield the same result (to within rounding error),
 * but the two processes can have very different computational overhead.
 * Sequence grids offer much faster TasmanianSparseGrid::evaluate() and TasmanianSparseGrid::evaluateBatch()
 * algorithms, at the cost of nearly double the storage and more than double the cost
 * of TasmanianSparseGrid::loadNeededValues().
 *
 * This example serves as a simple demonstration of the difference.
 *
 * \snippet SparseGrids/Examples/example_sparse_grids_07.cpp SG_Example_07 example
 */
void sparse_grids_example_07(){
#ifndef __TASMANIAN_DOXYGEN_SKIP
//! [SG_Example_07 example]
#endif

    cout << "\n---------------------------------------------------------------------------------------------------\n";
    cout << std::scientific; cout.precision(4);
    cout << "Example 7: interpolate f(x_1, x_2, x_3, x_4) = exp(-x_1^2 - x_3^2) * exp(x_2) * cos(x_4)\n"
         << "           using rleja rule and comparing Global and Sequence grids\n";

    auto time_start = std::chrono::system_clock::now();
    auto global = TasGrid::makeGlobalGrid(4, 1, 15, TasGrid::type_iptotal, TasGrid::rule_leja);
    auto time_end = std::chrono::system_clock::now();
    long long make_global =
        std::chrono::duration_cast<std::chrono::microseconds>(time_end - time_start).count();

    time_start = std::chrono::system_clock::now();
    auto sequence = TasGrid::makeSequenceGrid(4, 1, 15, TasGrid::type_iptotal, TasGrid::rule_leja);
    time_end = std::chrono::system_clock::now();
    long long make_sequence =
        std::chrono::duration_cast<std::chrono::microseconds>(time_end - time_start).count();

    // define batch model
    auto model = [](std::vector<double> const &points)->
        std::vector<double>{
            size_t num_points = points.size() / 4;
            std::vector<double> result(num_points);
            for(size_t i=0; i<num_points; i++){
                double x1 = points[4*i];
                double x2 = points[4*i + 1];
                double x3 = points[4*i + 2];
                double x4 = points[4*i + 3];
                result[i] = std::exp(-x1*x1) * std::cos(x2) * std::exp(-x3*x3) * std::cos(x4);
            }
            return result;
        };

    // load the model values into the grids
    time_start = std::chrono::system_clock::now();
    global.loadNeededValues(model(global.getNeededPoints()));
    time_end = std::chrono::system_clock::now();
    long long load_global =
        std::chrono::duration_cast<std::chrono::microseconds>(time_end - time_start).count();

    time_start = std::chrono::system_clock::now();
    sequence.loadNeededValues(model(sequence.getNeededPoints()));
    time_end = std::chrono::system_clock::now();
    long long load_sequence =
        std::chrono::duration_cast<std::chrono::microseconds>(time_end - time_start).count();

    // the benchmark surrogate models is measure from 1000 random reference points
    int const num_test_points = 1000;
    std::vector<double> test_points(4 * num_test_points);
    std::minstd_rand park_miller(42);
    std::uniform_real_distribution<double> domain(-1.0, 1.0);
    for(auto &t : test_points) t = domain(park_miller);

    // reference points
    std::vector<double> reference_result = model(test_points);

    // get the surrogate values at the test points
    time_start = std::chrono::system_clock::now();
    std::vector<double> global_result;
    global.evaluateBatch(test_points, global_result);
    time_end = std::chrono::system_clock::now();
    long long eval_global =
        std::chrono::duration_cast<std::chrono::microseconds>(time_end - time_start).count();

    time_start = std::chrono::system_clock::now();
    std::vector<double> sequence_result;
    sequence.evaluateBatch(test_points, sequence_result);
    time_end = std::chrono::system_clock::now();
    long long eval_sequence =
        std::chrono::duration_cast<std::chrono::microseconds>(time_end - time_start).count();

    double global_error = 0.0;
    for(int i=0; i<num_test_points; i++)
        global_error = std::max(global_error,
                                std::abs(global_result[i] - reference_result[i]));

    double sequence_error = 0.0;
    for(int i=0; i<num_test_points; i++)
        sequence_error = std::max(sequence_error,
                                  std::abs(sequence_result[i] - reference_result[i]));

    cout.precision(4);
    cout << std::scientific;
    cout << " Using " << global.getNumPoints() << " points,  "
         << " Global error: " << global_error << ",  Sequence error: " << sequence_error << "\n";

    cout << setw(15) << " " << setw(20) << "Global" << setw(20) << "Sequence" << "\n";
    cout << setw(15) << "make grid" << setw(20) << make_global << setw(20) << make_sequence
         << "  microseconds\n";
    cout << setw(15) << "load values" << setw(20) << load_global << setw(20) << load_sequence
         << "  microseconds\n";
    cout << setw(15) << "evaluate" << setw(20) << eval_global << setw(20) << eval_sequence
         << "  microseconds\n";

#ifndef __TASMANIAN_DOXYGEN_SKIP
//! [SG_Example_07 example]
#endif
}