Back to accumux

Examples

Code examples and use cases for accumux.

Examples

Practical examples demonstrating accumux capabilities.

Example 1: Complete Statistics Program

#include "accumux/accumulators/kbn_sum.hpp"
#include "accumux/accumulators/welford.hpp"
#include "accumux/accumulators/minmax.hpp"
#include "accumux/core/composition.hpp"
#include <iostream>
#include <vector>

using namespace accumux;

int main() {
    // Create comprehensive statistics accumulator
    auto stats = kbn_sum<double>() +
                 welford_accumulator<double>() +
                 minmax_accumulator<double>();

    // Sample data
    std::vector<double> data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};

    // Single-pass processing
    for (double x : data) {
        stats += x;
    }

    // Extract results
    auto sum = stats.get_first().eval();
    auto welford = stats.get_second();
    auto minmax = welford.get_second();

    std::cout << "=== Statistics ===" << std::endl;
    std::cout << "Sum:      " << sum << std::endl;
    std::cout << "Mean:     " << welford.mean() << std::endl;
    std::cout << "Variance: " << welford.sample_variance() << std::endl;
    std::cout << "Std Dev:  " << welford.sample_std_dev() << std::endl;
    std::cout << "Min:      " << minmax.min() << std::endl;
    std::cout << "Max:      " << minmax.max() << std::endl;
    std::cout << "Count:    " << welford.count() << std::endl;

    return 0;
}

Output:

=== Statistics ===
Sum:      55
Mean:     5.5
Variance: 9.16667
Std Dev:  3.02765
Min:      1
Max:      10
Count:    10

Example 2: Financial Analysis

Track multiple metrics for financial data streams.

#include "accumux/accumulators/kbn_sum.hpp"
#include "accumux/accumulators/welford.hpp"
#include "accumux/accumulators/minmax.hpp"
#include "accumux/core/composition.hpp"
#include <iostream>
#include <vector>

using namespace accumux;

int main() {
    auto financial_stats = kbn_sum<double>() +
                           welford_accumulator<double>() +
                           minmax_accumulator<double>();

    // Daily returns (as percentages)
    std::vector<double> returns = {0.05, -0.02, 0.03, 0.01, -0.01, 0.04,
                                   -0.03, 0.02, 0.01, -0.02};

    for (double ret : returns) {
        financial_stats += ret;
    }

    // Extract metrics
    auto total_return = financial_stats.get_first().eval();
    auto welford = financial_stats.get_second();
    auto minmax = welford.get_second();

    std::cout << "=== Portfolio Analysis ===" << std::endl;
    std::cout << "Total Return:  " << (total_return * 100) << "%" << std::endl;
    std::cout << "Mean Return:   " << (welford.mean() * 100) << "%" << std::endl;
    std::cout << "Volatility:    " << (welford.sample_std_dev() * 100) << "%" << std::endl;
    std::cout << "Worst Day:     " << (minmax.min() * 100) << "%" << std::endl;
    std::cout << "Best Day:      " << (minmax.max() * 100) << "%" << std::endl;
    std::cout << "Trading Days:  " << welford.count() << std::endl;

    // Sharpe-like ratio (simplified)
    double risk_free_rate = 0.001;  // 0.1% per day
    double sharpe = (welford.mean() - risk_free_rate) / welford.sample_std_dev();
    std::cout << "Sharpe Ratio:  " << sharpe << std::endl;

    return 0;
}

Example 3: Numerical Stability Comparison

Demonstrate the importance of stable summation.

#include "accumux/accumulators/kbn_sum.hpp"
#include <iostream>
#include <cmath>

using namespace accumux;

int main() {
    const size_t N = 1000000;

    // Create data that exposes numerical instability
    // Sum of 1/n for n = 1 to N
    double naive_sum = 0.0;
    kbn_sum<double> stable_sum;

    for (size_t i = 1; i <= N; ++i) {
        double value = 1.0 / static_cast<double>(i);
        naive_sum += value;
        stable_sum += value;
    }

    // Reference value (computed with higher precision)
    // Euler-Mascheroni constant approximation
    double reference = std::log(N) + 0.5772156649;

    std::cout << "Harmonic sum (n=1 to " << N << "):" << std::endl;
    std::cout << "Naive sum:      " << naive_sum << std::endl;
    std::cout << "KBN sum:        " << stable_sum.eval() << std::endl;
    std::cout << "Reference:      " << reference << std::endl;
    std::cout << std::endl;
    std::cout << "Naive error:    " << std::abs(naive_sum - reference) << std::endl;
    std::cout << "KBN error:      " << std::abs(stable_sum.eval() - reference) << std::endl;

    return 0;
}

Example 4: Parallel Processing

Process data in parallel and combine results.

#include "accumux/accumulators/kbn_sum.hpp"
#include "accumux/accumulators/welford.hpp"
#include "accumux/core/composition.hpp"
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>

using namespace accumux;

int main() {
    // Generate large dataset
    const size_t N = 1000000;
    std::vector<double> data(N);
    for (size_t i = 0; i < N; ++i) {
        data[i] = static_cast<double>(i + 1);
    }

    // Process in 4 chunks
    const size_t num_threads = 4;
    const size_t chunk_size = N / num_threads;

    using StatsType = decltype(kbn_sum<double>() + welford_accumulator<double>());
    std::vector<StatsType> thread_stats(num_threads);

    std::vector<std::thread> threads;
    for (size_t t = 0; t < num_threads; ++t) {
        threads.emplace_back([&, t]() {
            size_t start = t * chunk_size;
            size_t end = (t == num_threads - 1) ? N : (t + 1) * chunk_size;

            thread_stats[t] = kbn_sum<double>() + welford_accumulator<double>();
            for (size_t i = start; i < end; ++i) {
                thread_stats[t] += data[i];
            }
        });
    }

    for (auto& t : threads) {
        t.join();
    }

    // Combine all thread results
    auto combined = thread_stats[0];
    for (size_t t = 1; t < num_threads; ++t) {
        combined += thread_stats[t];
    }

    std::cout << "Parallel processing of " << N << " elements:" << std::endl;
    std::cout << "Sum:  " << combined.get_first().eval() << std::endl;
    std::cout << "Mean: " << combined.get_second().mean() << std::endl;

    // Verify: sum of 1 to N = N*(N+1)/2
    double expected_sum = N * (N + 1.0) / 2.0;
    std::cout << "Expected sum: " << expected_sum << std::endl;

    return 0;
}

Example 5: Scientific Data Analysis

Analyze sensor data with real-time anomaly detection.

#include "accumux/accumulators/welford.hpp"
#include "accumux/accumulators/minmax.hpp"
#include "accumux/core/composition.hpp"
#include <iostream>
#include <vector>
#include <random>

using namespace accumux;

int main() {
    // Simulate sensor readings with occasional anomalies
    std::mt19937 gen(42);
    std::normal_distribution<> normal(100.0, 5.0);  // Normal readings
    std::uniform_real_distribution<> uniform(0.0, 1.0);

    auto sensor_stats = welford_accumulator<double>() + minmax_accumulator<double>();

    std::cout << "=== Real-Time Sensor Analysis ===" << std::endl;

    for (int i = 0; i < 100; ++i) {
        double reading;
        if (uniform(gen) < 0.05) {
            // 5% chance of anomaly
            reading = normal(gen) + (uniform(gen) > 0.5 ? 50.0 : -50.0);
        } else {
            reading = normal(gen);
        }

        sensor_stats += reading;

        // Check for anomalies after warm-up period
        auto stats = sensor_stats.get_first();
        if (stats.count() > 10) {
            double z_score = std::abs(reading - stats.mean()) / stats.sample_std_dev();

            if (z_score > 3.0) {
                std::cout << "ANOMALY at reading " << i
                          << ": value=" << reading
                          << ", z-score=" << z_score << std::endl;
            }
        }
    }

    auto final_stats = sensor_stats.get_first();
    auto minmax = sensor_stats.get_second();

    std::cout << std::endl << "=== Final Statistics ===" << std::endl;
    std::cout << "Readings:  " << final_stats.count() << std::endl;
    std::cout << "Mean:      " << final_stats.mean() << std::endl;
    std::cout << "Std Dev:   " << final_stats.sample_std_dev() << std::endl;
    std::cout << "Range:     [" << minmax.min() << ", " << minmax.max() << "]" << std::endl;

    return 0;
}

Example 6: Custom Accumulator

Create a custom accumulator that satisfies the Accumulator concept.

#include "accumux/core/concept.hpp"
#include "accumux/core/composition.hpp"
#include <iostream>

using namespace accumux;

// Custom accumulator for computing sum of squares
template<typename T>
class sum_of_squares {
public:
    using value_type = T;

    sum_of_squares() : sum_sq_(0) {}

    sum_of_squares& operator+=(T value) {
        sum_sq_ += value * value;
        return *this;
    }

    sum_of_squares& operator+=(const sum_of_squares& other) {
        sum_sq_ += other.sum_sq_;
        return *this;
    }

    T eval() const { return sum_sq_; }

private:
    T sum_sq_;
};

// Verify it satisfies the Accumulator concept
static_assert(Accumulator<sum_of_squares<double>>,
              "sum_of_squares must satisfy Accumulator concept");

int main() {
    // Use custom accumulator in composition
    auto stats = kbn_sum<double>() + sum_of_squares<double>();

    std::vector<double> data = {1.0, 2.0, 3.0, 4.0, 5.0};
    for (double x : data) {
        stats += x;
    }

    double sum = stats.get_first().eval();
    double sum_sq = stats.get_second().eval();

    std::cout << "Sum: " << sum << std::endl;           // 15
    std::cout << "Sum of squares: " << sum_sq << std::endl;  // 55

    // Compute variance using sum and sum of squares
    double n = 5.0;
    double mean = sum / n;
    double variance = (sum_sq / n) - (mean * mean);
    std::cout << "Variance (from sums): " << variance << std::endl;

    return 0;
}

More Examples

For additional examples including:

  • Benchmark comparisons
  • Integration with other libraries
  • Complex multi-stage pipelines

See the examples directory on GitHub.