void testDerivativesFor()

in lib/maths/analytics/unittest/CBoostedTreeLeafNodeStatisticsTest.cc [82:200]


void testDerivativesFor(std::size_t numberParameters) {

    LOG_DEBUG(<< "Testing " << numberParameters << " parameters");

    test::CRandomNumbers rng;

    std::size_t numberGradients{numberParameters};
    std::size_t numberCurvatures{numberParameters * (numberParameters + 1) / 2};

    TDoubleVecVec gradients(numberGradients);
    TDoubleVecVec curvatures(numberCurvatures);
    for (std::size_t i = 0; i < numberGradients; ++i) {
        rng.generateUniformSamples(-1.0, 1.5, 20, gradients[i]);
    }
    for (std::size_t i = 0; i < numberCurvatures; ++i) {
        rng.generateUniformSamples(0.1, 0.5, 20, curvatures[i]);
    }

    LOG_DEBUG(<< "Accumulate");

    std::size_t paddedNumberGradients{core::CAlignment::roundup<double>(
        core::CAlignment::E_Aligned16, numberGradients)};

    TAlignedDoubleVec storage1(
        paddedNumberGradients + numberGradients * numberGradients + 1, 0.0);
    TAlignedDoubleVec storage1Plus2(
        paddedNumberGradients + numberGradients * numberGradients + 1, 0.0);
    TDerivatives derivatives1(static_cast<int>(numberParameters), storage1.data(),
                              storage1.data() + paddedNumberGradients,
                              storage1.data() + storage1.size() - 1);
    TDerivatives derivatives1Plus2(static_cast<int>(numberParameters),
                                   storage1Plus2.data(),
                                   storage1Plus2.data() + paddedNumberGradients,
                                   storage1Plus2.data() + storage1Plus2.size() - 1);
    for (std::size_t j = 0; j < 10; ++j) {
        TAlignedFloatVec rowStorage;
        for (std::size_t i = 0; i < numberGradients; ++i) {
            rowStorage.push_back(gradients[i][j]);
        }
        for (std::size_t i = 0; i < numberCurvatures; ++i) {
            rowStorage.push_back(curvatures[i][j]);
        }
        auto derivatives = makeAlignedVector<Eigen::Aligned16>(
            rowStorage.data(), numberGradients + numberCurvatures);
        derivatives1.add(1, derivatives);
        derivatives1Plus2.add(1, derivatives);
    }

    derivatives1.remapCurvature();
    BOOST_REQUIRE_EQUAL(10, derivatives1.count());
    for (std::size_t i = 0; i < numberGradients; ++i) {
        BOOST_REQUIRE_CLOSE(
            std::accumulate(gradients[i].begin(), gradients[i].begin() + 10, 0.0),
            derivatives1.gradient()(i), 1e-4);
    }
    for (std::size_t j = 0, k = 0; j < numberGradients; ++j) {
        for (std::size_t i = j; i < numberGradients; ++i, ++k) {
            BOOST_REQUIRE_CLOSE(std::accumulate(curvatures[k].begin(),
                                                curvatures[k].begin() + 10, 0.0),
                                derivatives1.curvature()(i, j), 1e-4);
        }
    }

    LOG_DEBUG(<< "Merge");

    TAlignedDoubleVec storage2(
        paddedNumberGradients + numberGradients * numberGradients + 1, 0.0);
    TDerivatives derivatives2(static_cast<int>(numberParameters), storage2.data(),
                              storage2.data() + paddedNumberGradients,
                              storage2.data() + storage2.size() - 1);

    for (std::size_t j = 10; j < 20; ++j) {
        TAlignedFloatVec storage;
        for (std::size_t i = 0; i < numberGradients; ++i) {
            storage.push_back(gradients[i][j]);
        }
        for (std::size_t i = 0; i < numberCurvatures; ++i) {
            storage.push_back(curvatures[i][j]);
        }
        auto derivatives = makeAlignedVector<Eigen::Aligned16>(
            storage.data(), numberGradients + numberCurvatures);
        derivatives2.add(1, derivatives);
    }

    derivatives1Plus2.add(derivatives2);

    derivatives1Plus2.remapCurvature();
    BOOST_REQUIRE_EQUAL(20, derivatives1Plus2.count());
    for (std::size_t i = 0; i < numberGradients; ++i) {
        BOOST_REQUIRE_CLOSE(std::accumulate(gradients[i].begin(), gradients[i].end(), 0.0),
                            derivatives1Plus2.gradient()(i), 1e-4);
    }
    for (std::size_t j = 0, k = 0; j < numberGradients; ++j) {
        for (std::size_t i = j; i < numberGradients; ++i, ++k) {
            BOOST_REQUIRE_CLOSE(
                std::accumulate(curvatures[k].begin(), curvatures[k].end(), 0.0),
                derivatives1Plus2.curvature()(i, j), 1e-4);
        }
    }

    LOG_DEBUG(<< "Difference");

    derivatives2.remapCurvature();
    derivatives1Plus2.subtract(derivatives2);

    BOOST_REQUIRE_EQUAL(10, derivatives1Plus2.count());
    for (std::size_t i = 0; i < numberGradients; ++i) {
        BOOST_REQUIRE_CLOSE(
            std::accumulate(gradients[i].begin(), gradients[i].begin() + 10, 0.0),
            derivatives1Plus2.gradient()(i), 1e-4);
    }
    for (std::size_t j = 0, k = 0; j < numberGradients; ++j) {
        for (std::size_t i = j; i < numberGradients; ++i, ++k) {
            BOOST_REQUIRE_CLOSE(std::accumulate(curvatures[k].begin(),
                                                curvatures[k].begin() + 10, 0.0),
                                derivatives1Plus2.curvature()(i, j), 1e-4);
        }
    }
}