#include <array>
#include <cmath>
#include <iostream>

struct Example {
    std::array<double, 2> input;
    double target;
};

int main() {
    const std::array<Example, 4> training{{
        {{{0.0, 0.0}}, 0.5},
        {{{1.0, 0.0}}, 2.5},
        {{{0.0, 1.0}}, -0.5},
        {{{1.0, 1.0}}, 1.5}
    }};
    std::array<double, 2> weights{{0.0, 0.0}};
    double bias = 0.0;
    const double rate = 0.05;

    auto predict = [&](const std::array<double, 2>& input) {
        return weights[0] * input[0] + weights[1] * input[1] + bias;
    };

    for (int epoch = 0; epoch < 2000; ++epoch) {
        for (const auto& example : training) {
            const double error = example.target - predict(example.input);
            for (std::size_t j = 0; j < weights.size(); ++j) {
                weights[j] += rate * error * example.input[j];
            }
            bias += rate * error;
        }
    }

    double mse = 0.0;
    for (const auto& example : training) {
        const double error = example.target - predict(example.input);
        mse += error * error;
    }
    mse /= training.size();
    const std::array<double, 2> unseen{{0.25, 0.75}};
    const double expected = 0.25;
    std::cout << "Weights: " << weights[0] << ", " << weights[1]
              << " Bias: " << bias << " MSE: " << mse << '\n';
    std::cout << "Unseen input prediction: " << predict(unseen) << '\n';
    return mse < 1e-8 && std::abs(predict(unseen) - expected) < 1e-4 ? 0 : 1;
}
