// File: louisabraham[P]cage/example.cpp
// Function: main
int main()
{
    srand(time(NULL));

    const int n = 1000;
    const int dim = 2;

    vector<vector<float_t>> X(n);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < dim; j++)
            X[i].push_back(drand());

    using elem_t = vector<float_t>;

    const function<elem_t()> init = []() {
        elem_t ans;
        for (int i = 0; i < dim + 1; i++)
            ans.push_back(drand());
        return ans;
    };

    const function<float_t(elem_t, elem_t)> eval = [&](elem_t coefs, elem_t x) {
        float_t ans = coefs[dim];
        for (int i = 0; i < dim; i++)
            ans += coefs[i] * x[i];
        return ans;
    };

    vector<float_t> y(n);
    auto true_coefs = init();
    cout << "real coeffs ";
    for (auto c : true_coefs)
        cout << setprecision(3) << c << ' ';
    cout << endl;
    for (int i = 0; i < n; i++)
        y[i] = eval(true_coefs, X[i]);

    float mean = 0;
    for (int i = 0; i < n; i++)
        mean += y[i];
    mean /= n;
    float var = 0;
    for (int i = 0; i < n; i++)
    {
        float tmp = y[i] - mean;
        var += tmp * tmp;
    }
    var /= n;

    cout << "std " << sqrt(var) << endl;

    const function<float_t(const elem_t &)> score = [&](const elem_t &coefs) {
        float_t error = 0;
        for (int i = 0; i < n; i++)
        {
            float_t e = eval(coefs, X[i]) - y[i];
            error += e * e;
        }
        error /= n;
        if (error != error)
            return (float)1e6;
        return error;
    };

    const function<void(elem_t &)> mutate = [&](elem_t &coefs) {
        float_t &x = coefs[rand() % (dim + 1)];
        auto ptr = reinterpret_cast<uint32_t *>(&x);
        *ptr ^= (1 << (rand() % 32));
    };

    auto ans = genetic_algorithm(
        init,   // generate a new item
        score,  // score function
        true,   // minimize or maximize
        mutate, // in-place mutation function
        10,     // population size
        100000, // number of optimization steps
        50      // if not -1, use optimal Las Vegas restarts
    );

    cout << "solution coeffs ";
    for (auto c : ans.second)
        cout << setprecision(3) << c << ' ';
    cout << endl;

    cout << "rmse " << sqrt(ans.first) << endl;
}

// Assembly:
subq $0x2d8, %rsp            # imm = 0x2D8
movl $0x0, 0x2d4(%rsp)
xorl %eax, %eax
movl %eax, %edi
callq 0x10d0
movl %eax, %edi
callq 0x10e0
movl $0x3e8, 0x2d0(%rsp) # imm = 0x3E8
movl $0x2, 0x2cc(%rsp)
leaq 0x2af(%rsp), %rdi
movq %rdi, 0x90(%rsp)
callq 0x3010
movq 0x90(%rsp), %rdx
leaq 0x2b0(%rsp), %rdi
movl $0x3e8, %esi            # imm = 0x3E8
callq 0x3020
jmp 0x13e9
leaq 0x2af(%rsp), %rdi
callq 0x30a0
movl $0x0, 0x298(%rsp)
cmpl $0x3e8, 0x298(%rsp) # imm = 0x3E8
jge 0x14ed
movl $0x0, 0x294(%rsp)
cmpl $0x2, 0x294(%rsp)
jge 0x14d5
movslq 0x298(%rsp), %rsi
leaq 0x2b0(%rsp), %rdi
callq 0x30b0
movq %rax, 0x80(%rsp)
callq 0x1d70
movss %xmm0, 0x8c(%rsp)
jmp 0x1458
movq 0x80(%rsp), %rdi
movss 0x8c(%rsp), %xmm0
movss %xmm0, 0x290(%rsp)
leaq 0x290(%rsp), %rsi
callq 0x30d0
jmp 0x1481
jmp 0x1483
movl 0x294(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x294(%rsp)
jmp 0x141d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
leaq 0x2af(%rsp), %rdi
callq 0x30a0
jmp 0x1d60
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x1d53
jmp 0x14d7
movl 0x298(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x298(%rsp)
jmp 0x1401
leaq 0x270(%rsp), %rdi
leaq 0x26f(%rsp), %rsi
callq 0x1d90
leaq 0x248(%rsp), %rdi
leaq 0x247(%rsp), %rsi
callq 0x1e20
leaq 0x227(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x3100
movq 0x78(%rsp), %rdx
leaq 0x228(%rsp), %rdi
movl $0x3e8, %esi            # imm = 0x3E8
callq 0x3110
jmp 0x1542
leaq 0x227(%rsp), %rdi
callq 0x3190
leaq 0x208(%rsp), %rdi
leaq 0x270(%rsp), %rsi
callq 0x31a0
jmp 0x1566
movq 0x9a6b(%rip), %rdi      # 0xafd8
leaq 0x5b0c(%rip), %rsi      # 0x7080
callq 0x10f0
jmp 0x157b
leaq 0x208(%rsp), %rax
movq %rax, 0x200(%rsp)
movq 0x200(%rsp), %rdi
callq 0x31f0
movq %rax, 0x1f8(%rsp)
movq 0x200(%rsp), %rdi
callq 0x3220
movq %rax, 0x1f0(%rsp)
leaq 0x1f8(%rsp), %rdi
leaq 0x1f0(%rsp), %rsi
callq 0x3250
testb $0x1, %al
jne 0x15d3
jmp 0x16b9
leaq 0x1f8(%rsp), %rdi
callq 0x3290
movss (%rax), %xmm0
movss %xmm0, 0x1ec(%rsp)
movl $0x3, %edi
callq 0x32a0
movl %eax, 0x74(%rsp)
jmp 0x15fd
movl 0x74(%rsp), %eax
movl %eax, 0x1e8(%rsp)
movl 0x1e8(%rsp), %esi
movq 0x99c2(%rip), %rdi      # 0xafd8
callq 0x1160
movq %rax, 0x68(%rsp)
jmp 0x1622
movq 0x68(%rsp), %rdi
movss 0x1ec(%rsp), %xmm0
callq 0x10a0
movq %rax, 0x60(%rsp)
jmp 0x163c
movq 0x60(%rsp), %rdi
movl $0x20, %esi
callq 0x1130
jmp 0x164d
jmp 0x164f
leaq 0x1f8(%rsp), %rdi
callq 0x32c0
jmp 0x15b5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
leaq 0x227(%rsp), %rdi
callq 0x3190
jmp 0x1d39
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x1d2c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x1d1f
movq 0x9918(%rip), %rdi      # 0xafd8
movq 0x9901(%rip), %rsi      # 0xafc8
callq 0x1120
jmp 0x16ce
movl $0x0, 0x1e4(%rsp)
cmpl $0x3e8, 0x1e4(%rsp) # imm = 0x3E8
jge 0x17e5
leaq 0x1c8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
callq 0x3340
jmp 0x1701
movslq 0x1e4(%rsp), %rsi
leaq 0x2b0(%rsp), %rdi
callq 0x30b0
movq %rax, %rsi
leaq 0x1b0(%rsp), %rdi
callq 0x3340
jmp 0x1728
leaq 0x248(%rsp), %rdi
leaq 0x1c8(%rsp), %rsi
leaq 0x1b0(%rsp), %rdx
callq 0x32e0
movss %xmm0, 0x5c(%rsp)
jmp 0x174d
movslq 0x1e4(%rsp), %rsi
leaq 0x228(%rsp), %rdi
callq 0x3440
movss 0x5c(%rsp), %xmm0
movss %xmm0, (%rax)
leaq 0x1b0(%rsp), %rdi
callq 0x3460
leaq 0x1c8(%rsp), %rdi
callq 0x3460
movl 0x1e4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1e4(%rsp)
jmp 0x16d9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x17d3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
leaq 0x1b0(%rsp), %rdi
callq 0x3460
leaq 0x1c8(%rsp), %rdi
callq 0x3460
jmp 0x1d1f
xorps %xmm0, %xmm0
movss %xmm0, 0x1ac(%rsp)
movl $0x0, 0x1a8(%rsp)
cmpl $0x3e8, 0x1a8(%rsp) # imm = 0x3E8
jge 0x1847
movslq 0x1a8(%rsp), %rsi
leaq 0x228(%rsp), %rdi
callq 0x3440
movss (%rax), %xmm0
addss 0x1ac(%rsp), %xmm0
movss %xmm0, 0x1ac(%rsp)
movl 0x1a8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1a8(%rsp)
jmp 0x17fc
movss 0x1ac(%rsp), %xmm0
movss 0x57ac(%rip), %xmm1     # 0x7004
divss %xmm1, %xmm0
movss %xmm0, 0x1ac(%rsp)
xorps %xmm0, %xmm0
movss %xmm0, 0x1a4(%rsp)
movl $0x0, 0x1a0(%rsp)
cmpl $0x3e8, 0x1a0(%rsp) # imm = 0x3E8
jge 0x18f3
movslq 0x1a0(%rsp), %rsi
leaq 0x228(%rsp), %rdi
callq 0x3440
movss (%rax), %xmm0
subss 0x1ac(%rsp), %xmm0
movss %xmm0, 0x19c(%rsp)
movss 0x19c(%rsp), %xmm0
movss 0x19c(%rsp), %xmm2
movss 0x1a4(%rsp), %xmm1
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
movss %xmm0, 0x1a4(%rsp)
movl 0x1a0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1a0(%rsp)
jmp 0x187c
movss 0x1a4(%rsp), %xmm0
movss 0x5700(%rip), %xmm1     # 0x7004
divss %xmm1, %xmm0
movss %xmm0, 0x1a4(%rsp)
movq 0x96c0(%rip), %rdi      # 0xafd8
leaq 0x576e(%rip), %rsi      # 0x708d
callq 0x10f0
movq %rax, 0x50(%rsp)
jmp 0x192b
movss 0x1a4(%rsp), %xmm0
callq 0x34c0
movss %xmm0, 0x4c(%rsp)
jmp 0x1941
movss 0x4c(%rsp), %xmm0
movq 0x50(%rsp), %rdi
callq 0x10a0
movq %rax, 0x40(%rsp)
jmp 0x1958
movq 0x40(%rsp), %rdi
movq 0x9664(%rip), %rsi      # 0xafc8
callq 0x1120
jmp 0x196b
leaq 0x248(%rsp), %rax
movq %rax, 0x160(%rsp)
leaq 0x2b0(%rsp), %rax
movq %rax, 0x168(%rsp)
leaq 0x228(%rsp), %rax
movq %rax, 0x170(%rsp)
leaq 0x178(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0x1eb0
jmp 0x19b2
leaq 0x140(%rsp), %rdi
leaq 0x13f(%rsp), %rsi
callq 0x1f60
leaq 0xf8(%rsp), %rdi
leaq 0x270(%rsp), %rsi
callq 0x3910
jmp 0x19de
leaq 0xd8(%rsp), %rdi
leaq 0x178(%rsp), %rsi
callq 0x39c0
jmp 0x19f5
leaq 0xb8(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x3a70
jmp 0x1a0c
movq %rsp, %rax
movl $0x32, 0x8(%rax)
movl $0x186a0, (%rax)        # imm = 0x186A0
leaq 0x118(%rsp), %rdi
leaq 0xf8(%rsp), %rsi
leaq 0xd8(%rsp), %rdx
movl $0x1, %ecx
leaq 0xb8(%rsp), %r8
movl $0xa, %r9d
callq 0x34e0
jmp 0x1a4e
leaq 0xb8(%rsp), %rdi
callq 0x3b20
leaq 0xd8(%rsp), %rdi
callq 0x3b30
leaq 0xf8(%rsp), %rdi
callq 0x3b40
movq 0x955c(%rip), %rdi      # 0xafd8
leaq 0x560f(%rip), %rsi      # 0x7092
callq 0x10f0
jmp 0x1a8a
leaq 0x118(%rsp), %rax
addq $0x8, %rax
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rdi
callq 0x31f0
movq %rax, 0xa8(%rsp)
movq 0xb0(%rsp), %rdi
callq 0x3220
movq %rax, 0xa0(%rsp)
leaq 0xa8(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x3250
testb $0x1, %al
jne 0x1ae6
jmp 0x1c1f
leaq 0xa8(%rsp), %rdi
callq 0x3290
movss (%rax), %xmm0
movss %xmm0, 0x9c(%rsp)
movl $0x3, %edi
callq 0x32a0
movl %eax, 0x3c(%rsp)
jmp 0x1b10
movl 0x3c(%rsp), %eax
movl %eax, 0x98(%rsp)
movl 0x98(%rsp), %esi
movq 0x94af(%rip), %rdi      # 0xafd8
callq 0x1160
movq %rax, 0x30(%rsp)
jmp 0x1b35
movq 0x30(%rsp), %rdi
movss 0x9c(%rsp), %xmm0
callq 0x10a0
movq %rax, 0x28(%rsp)
jmp 0x1b4f
movq 0x28(%rsp), %rdi
movl $0x20, %esi
callq 0x1130
jmp 0x1b60
jmp 0x1b62
leaq 0xa8(%rsp), %rdi
callq 0x32c0
jmp 0x1ac8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x1d05
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x1be7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
jmp 0x1bda
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
leaq 0xb8(%rsp), %rdi
callq 0x3b20
leaq 0xd8(%rsp), %rdi
callq 0x3b30
leaq 0xf8(%rsp), %rdi
callq 0x3b40
jmp 0x1d05
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2a0(%rsp)
movl %eax, 0x29c(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x3b50
jmp 0x1d05
movq 0x93b2(%rip), %rdi      # 0xafd8
movq 0x939b(%rip), %rsi      # 0xafc8
callq 0x1120
jmp 0x1c34
movq 0x939d(%rip), %rdi      # 0xafd8
leaq 0x5461(%rip), %rsi      # 0x70a3
callq 0x10f0
movq %rax, 0x20(%rsp)
jmp 0x1c4e
movss 0x118(%rsp), %xmm0
callq 0x34c0
movss %xmm0, 0x1c(%rsp)
jmp 0x1c64
movss 0x1c(%rsp), %xmm0
movq 0x20(%rsp), %rdi
callq 0x10a0
movq %rax, 0x10(%rsp)
jmp 0x1c7b
movq 0x10(%rsp), %rdi
movq 0x9341(%rip), %rsi      # 0xafc8
callq 0x1120
jmp 0x1c8e
leaq 0x118(%rsp), %rdi
callq 0x3b50
leaq 0x140(%rsp), %rdi
callq 0x3b20
leaq 0x178(%rsp), %rdi
callq 0x3b30
leaq 0x208(%rsp), %rdi
callq 0x3460
leaq 0x228(%rsp), %rdi
callq 0x3460
leaq 0x248(%rsp), %rdi
callq 0x3b70
leaq 0x270(%rsp), %rdi
callq 0x3b40
leaq 0x2b0(%rsp), %rdi
callq 0x3b80
movl 0x2d4(%rsp), %eax
addq $0x2d8, %rsp            # imm = 0x2D8
retq
leaq 0x140(%rsp), %rdi
callq 0x3b20
leaq 0x178(%rsp), %rdi
callq 0x3b30
leaq 0x208(%rsp), %rdi
callq 0x3460
leaq 0x228(%rsp), %rdi
callq 0x3460
leaq 0x248(%rsp), %rdi
callq 0x3b70
leaq 0x270(%rsp), %rdi
callq 0x3b40
leaq 0x2b0(%rsp), %rdi
callq 0x3b80
movq 0x2a0(%rsp), %rdi
callq 0x1190
nopl (%rax)