Project: s41467-024-47953-7 | Function: _smooth_kmer (cpp)

system: You are an expert C++ programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow C++ best practices and maintain consistent code style.
Return **only** the complete C++ function code.

user: Complete this C++ function:

**DESCRIPTION:** Smooths k-mer signals and calculates distances between observed and expected signals for RNA modification detection

**KEY TERMS:** {
  "signal_smoothed": "smoothed nanopore signal",
  "expected_smoothed": "expected unmodified signal",
  "distance_vector": "signal distance features",
  "kmer_name": "9-mer sequence identifier",
  "smooth_event": "signal smoothing function",
  "make_expected": "generate expected signal"
}

**CONTEXT CODE:**
    if (signal.size() % 2 == 0) {
        return {(signal[mid - 1] + signal[mid]) / 2.0};
    } else {
        return {signal[mid]};
    }
}

vector_float_t make_expected(const std::string& kmer, const vector_kmer_models_t& model_kmer) {
    vector_float_t expected_signal;
    for (int i = 0; i < 5; ++i) {
        std::string kmer_5 = kmer.substr(i, 5);
        for (const auto& model : model_kmer) {
            if (model.kmers == kmer_5) {
                std::vector<float> signal_add(20, model.mean);
                expected_signal.insert(expected_signal.end(), signal_add.begin(), signal_add.end());
            }
        }
    }
    return expected_signal;
}

vector_float_t distance_calculator(const vector_float_t& expected, const vector_float_t& observed) {
    vector_float_t distance_vector;
    distance_vector.resize(expected.size());
    for (int i = 0; i < expected.size(); ++i) {
        distance_vector[i] = std::abs(expected[i] - observed[i]);
    }
    return distance_vector;
}

kmer_smoothed _smooth_kmer(parsed_kmer_t& parsed_kmer, vector_kmer_models_t& model_kmer) {
    vector_float_t signal_smoothed;
    vector_float_t expected_smoothed;
    std::vector<float> event_smoothed;
    std::string kmer_name;

    // Smooth and collect the signals
    for (const auto& p : parsed_kmer) {
        event_smoothed = p.second.signal;
        event_smoothed = smooth_event(event_smoothed);
        signal_smoothed.insert(signal_smoothed.end(), event_smoothed.begin(), event_smoothed.end());
        kmer_name = p.first;
    }

    // Generate expected signals
    if (signal_smoothed.size() > 5) {
        expected_smoothed = make_expected(kmer_name, model_kmer);
    } else {
        expected_smoothed = make_expected(kmer_name, model_kmer);
    }

    // Ensure both vectors are of the same length (20)
    if (signal_smoothed.size() < 20) {
        signal_smoothed.resize(20, 0.0);
    }
    if (expected_smoothed.size() < 20) {
        expected_smoothed.resize(20, 0.0);
    }

    // Calculate distance
    vector_float_t distance_vector = distance_calculator(expected_smoothed, signal_smoothed);

    // Combine smoothed signal and distance vector
    combined_vector_t combined.vector;
    for (int i = 0; i < signal_smoothed.size(); ++i) {
        combined.vector.append(signal_smoothed[i]);
        combined.vector.append(distance_vector[i]);
    }

    return kmer_smoothed{signal_smoothed, expected_smoothed, kmer_name};
}

Arr _combine_vectors(const vector_float_t& smooth_signal, const vector_float_t& smooth_distance) {
    Arr combined;
    for (int i = 0; i < smooth_signal.size(); ++i) {
        combined.append(smooth_signal[i]);
        combined.append(smooth_distance[i]);
    }
    return combined;
}

void parse_nanopolish(const std::string& file, char symbol, vector_kmer_models_t& model_kmer, std::string name_out) {
    int counter = 0;
    parsed_kmer_t parsed_kmer;
    std::vector<std::string> stored_line;
    std::vector<int> signals_IDs;
    std::vector<std::string> checked_line;

    std::ifstream infile(file);
    std::string line;
    std::getline(infile, line);

    std::vector<std::string> header = split_string(line, '\t');

    if (header.back() != "samples") {
        throw "Error: nanopolish samples are not found, please run nanopolish with flag --samples";
    }

    int contig_idx = get_index(header, "contig");
    int position_idx = get_index(header, "position");
    int reference_kmer_idx = get_index(header, "reference_kmer");
    int model_kmer_idx = get_index(header, "model_kmer");
    int samples_idx = get_index(header, "samples");

    if (contig_idx == -1 || position_idx == -1 || reference_kmer_idx == -1 || model_kmer_idx == -1 || samples_idx == -1) {
        throw "Some nanopolish columns are not found\n";
    }

    while (!infile.eof()) {
        if (stored_line.empty()) {
            if (!std::getline(infile, line)) {
                break;
            }
            ++counter;

            checked_line = _check_line(line, contig_idx, position_idx, reference_kmer_idx, model_kmer_idx, samples_idx, symbol);
        } else {
            checked_line = stored_line;
            stored_line.clear();
        }

        if (!checked_line.empty()) {
            if ((checked_line[model_kmer_idx].back() == symbol) || (!parsed_kmer.empty())) {
                kmers_parse_r kmers_p = _parse_kmers(checked_line, contig_idx, position_idx, reference_kmer_idx, model_kmer_idx, samples_idx, infile, parsed_kmer, counter, symbol);
                parsed_kmer = kmers_p.kmers_lines;
                stored_line = kmers_p.checked_line;

                if (!parsed_kmer.empty()) {
                    if (parsed_kmer.size() < 5) {
                        continue;
                    }
                    for (const auto& p : parsed_kmer) {
                        // Process each parsed k-mer
                        auto result = _smooth_kmer(parsed_kmer, model_kmer);
                        // Further processing can be done here
                    }
                }
            }
        }
    }
}

/**
 * @brief
 * combine signals and distance vectors
 */
Arr _combine_vectors(vector<float> smooth_signal, vector<float> smooth_distance)
{
    Arr combined(100);
    for (int i = 0; i < smooth_signal.size(); ++i)