void CMetricModel::fill()

in lib/model/CMetricModel.cc [633:761]


void CMetricModel::fill(model_t::EFeature feature,
                        std::size_t pid,
                        core_t::TTime bucketTime,
                        bool interim,
                        CProbabilityAndInfluenceCalculator::SCorrelateParams& params,
                        TStrCRefDouble1VecDouble1VecPrPrVecVecVec& influenceValues) const {

    using TStrCRefDouble1VecDoublePrPr = std::pair<TStrCRef, TDouble1VecDoublePr>;

    const CDataGatherer& gatherer{this->dataGatherer()};
    const maths::common::CModel* model{this->model(feature, pid)};
    const TSize2Vec1Vec& correlates{model->correlates()};
    const TTimeVec& firstBucketTimes{this->firstBucketTimes()};
    core_t::TTime bucketLength{gatherer.bucketLength()};
    double initialCountWeight{this->initialCountWeight(
        feature, pid, model_t::INDIVIDUAL_ANALYSIS_ATTRIBUTE_ID,
        model_t::sampleTime(feature, bucketTime, bucketLength))};

    params.s_Feature = feature;
    params.s_Model = model;
    params.s_ElapsedTime = std::numeric_limits<core_t::TTime>::max();
    params.s_Times.resize(correlates.size());
    params.s_Values.resize(correlates.size());
    params.s_Counts.resize(correlates.size());
    params.s_Variables.resize(correlates.size());
    params.s_CorrelatedLabels.resize(correlates.size());
    params.s_Correlated.resize(correlates.size());
    params.s_ComputeProbabilityParams
        .addCalculation(model_t::probabilityCalculation(feature))
        .initialCountWeight(initialCountWeight);

    // These are indexed as follows:
    //   influenceValues["influencer name"]["correlate"]["influence value"]
    // This is because we aren't guaranteed that each influence is present for
    // each feature.
    influenceValues.resize(
        this->featureData(feature, pid, bucketTime)->s_InfluenceValues.size(),
        TStrCRefDouble1VecDouble1VecPrPrVecVec(correlates.size()));

    // Declared outside the loop to minimize the number of times it is created.
    TDouble1VecDouble1VecPr value;
    TDouble2Vec seasonalWeights[2];
    TDouble2Vec weight(2);

    for (std::size_t i = 0; i < correlates.size(); ++i) {
        TSize2Vec variables(pid == correlates[i][0] ? TSize2Vec{0, 1} : TSize2Vec{1, 0});
        params.s_CorrelatedLabels[i] = gatherer.personName(correlates[i][variables[1]]);
        params.s_Correlated[i] = correlates[i][variables[1]];
        params.s_Variables[i] = variables;
        const maths::common::CModel* models[]{
            model, this->model(feature, correlates[i][variables[1]])};
        maths_t::TDouble2VecWeightsAry weights(maths_t::CUnitWeights::unit<TDouble2Vec>(2));
        models[0]->seasonalWeight(maths::common::DEFAULT_SEASONAL_CONFIDENCE_INTERVAL,
                                  bucketTime, seasonalWeights[0]);
        models[1]->seasonalWeight(maths::common::DEFAULT_SEASONAL_CONFIDENCE_INTERVAL,
                                  bucketTime, seasonalWeights[1]);
        weight[variables[0]] = seasonalWeights[0][0];
        weight[variables[1]] = seasonalWeights[1][0];
        maths_t::setSeasonalVarianceScale(weight, weights);

        const TFeatureData* data[2];
        data[0] = this->featureData(feature, correlates[i][0], bucketTime);
        data[1] = this->featureData(feature, correlates[i][1], bucketTime);
        if (data[0] && data[1] && data[0]->s_BucketValue && data[1]->s_BucketValue) {
            const TOptionalSample& bucket0{data[0]->s_BucketValue};
            const TOptionalSample& bucket1{data[1]->s_BucketValue};
            core_t::TTime times[] = {
                model_t::sampleTime(feature, bucketTime, bucketLength, bucket0->time()),
                model_t::sampleTime(feature, bucketTime, bucketLength, bucket1->time())};
            params.s_ElapsedTime = std::min(
                params.s_ElapsedTime, times[0] - firstBucketTimes[correlates[i][0]]);
            params.s_ElapsedTime = std::min(
                params.s_ElapsedTime, times[1] - firstBucketTimes[correlates[i][1]]);
            params.s_Times[i] = TTime2Vec{times[0], times[1]};
            params.s_Values[i].resize(2 * bucket0->value().size());
            for (std::size_t j = 0; j < bucket0->value().size(); ++j) {
                params.s_Values[i][2 * j + 0] = bucket0->value()[j];
                params.s_Values[i][2 * j + 1] = bucket1->value()[j];
            }
            params.s_Counts[i] = TDouble2Vec{bucket0->count(), bucket1->count()};
            weight[variables[0]] = bucket0->varianceScale();
            weight[variables[1]] = bucket1->varianceScale();
            maths_t::setCountVarianceScale(weight, weights);
            for (std::size_t j = 0; j < data[0]->s_InfluenceValues.size(); ++j) {
                for (const auto& influenceValue : data[0]->s_InfluenceValues[j]) {
                    TStrCRef influence = influenceValue.first;
                    std::size_t match = static_cast<std::size_t>(
                        std::find_if(data[1]->s_InfluenceValues[j].begin(),
                                     data[1]->s_InfluenceValues[j].end(),
                                     [influence](const TStrCRefDouble1VecDoublePrPr& value_) {
                                         return value_.first.get() == influence.get();
                                     }) -
                        data[1]->s_InfluenceValues[j].begin());
                    if (match < data[1]->s_InfluenceValues[j].size()) {
                        const TDouble1VecDoublePr& value0 = influenceValue.second;
                        const TDouble1VecDoublePr& value1 =
                            data[1]->s_InfluenceValues[j][match].second;
                        value.first.resize(2 * value0.first.size());
                        for (std::size_t k = 0; k < value0.first.size(); ++k) {
                            value.first[2 * k + 0] = value0.first[k];
                            value.first[2 * k + 1] = value1.first[k];
                        }
                        value.second = TDouble1Vec{value0.second, value1.second};
                        influenceValues[j][i].emplace_back(influence, value);
                    }
                }
            }
        }
        params.s_ComputeProbabilityParams.addWeights(weights);
    }
    if (interim && model_t::requiresInterimResultAdjustment(feature)) {
        core_t::TTime time{bucketTime + bucketLength / 2};
        TDouble2Vec1Vec modes(params.s_Model->correlateModes(
            time, params.s_ComputeProbabilityParams.weights()));
        for (std::size_t i = 0; i < modes.size(); ++i) {
            if (!params.s_Values.empty()) {
                TDouble2Vec value_{params.s_Values[i][0], params.s_Values[i][1]};
                TDouble2Vec correction(
                    this->interimValueCorrector().corrections(modes[i], value_));
                for (std::size_t j = 0; j < 2; ++j) {
                    params.s_Values[i][j] += correction[j];
                }
                this->currentBucketInterimCorrections().emplace(
                    core::make_triple(feature, pid, params.s_Correlated[i]),
                    TDouble1Vec{correction[params.s_Variables[i][0]]});
            }
        }
    }
}