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]]});
}
}
}
}