C++ pentru software matematic

În continuarea discuției de la:

E adevărat că acum parcă și Java are SIMD, dar în C++ cu ajutorul templates (și cum funcționează ele, pentru că funcționează diferit față de generics din Java/C#) se pot face mai multe optimizări non-triviale, așa cum se explică și aici. De acolo:

auto A1 = Matrix<N, N>{ /* ... */ };
auto A2 = Matrix<N, N>{ /* ... */ };
/* ... */
auto An = Matrix<N, N>{ /* ... */ };

auto sum = A1 + A2 + ... + An; // nu va apărea niciun temporar
// Nu calculează rezultatul direct, ci convertește expresia lazily la un fel de arbore de operații, ceva de genul:
Glue<Glue<...Glue<Glue<A1, A2, op_plus>, A3, op_plus>..., An, op_plus>;

// Iarăși pentru înmulțire:
auto A = Matrix<60, 5>{ /* ... */ };
auto B = Matrix<5, 30>{ /* ... */ };
auto C = Matrix<30, 10> { /* ... */ };

auto product = A * B * C;
// Un algoritm naiv va efectua 27.000 de operații: (A * B) * C
// Cu template expressions se poate decide la compile-time care e ordinea înmulțirii mai eficientă (înmulțirea matricilor fiind asociativă)
// A * (B * C) ar însemna doar 4.000 de operații
// Și nici 4000 nu cred că efectuează, am impresia că optimizează și mai mult algoritmul de înmulțire pe matrici

Optimizările de genul sunt la un nivel mai înalt decât SIMD, iar în Java/C# e mult mai greu spre imposibil să ajungi la asta (adică să fie atât de easily-readable dar în același timp cu aceste optimizări). C++ o fi nașpa, dar dacă se potrivește la ceva, se potrivește la software matematic (IMO). Nici în Rust (care are const generics acum) nu cred că se poate ajunge la nivelul ăsta de template expressions, poate doar cu macros care nu prea au cum să facă codul atât de readable.

3 Likes

Eu folosesc Eigen cand am de ales, face cam aceleasi lucruri.

M-am uitat si peste Armadillo si am incercat-o, dar din ceva motive nu mi-a placut atat de mult.

2 Likes
  1. Ma bate link-ul
    image

  2. Alt thread, sper ca in context
    DotNet Core Benchmarks Consistently Beat JVM

Armadillo și Eigen cred că sunt cele mai consacrate, mai există și:

  • Boost.uBLAS
  • Blaze - care e mai nou, ei zicând că aduce ceva performanță în plus
  • xtensor - care ar trebui să fie un fel de numpy pentru C++

Iti dai seama ca stiu si de altele, de fapt am avut ocazia sa folosesc direct si lapack & blas & gsl.

Am ales Eigen pentru proiectele open source pentru ca e expresiva, nu neaparat pentru performanta (desi e buna si aia).

2 Likes

Ca tot e topic despre calcule & performanta:

879 GB/s Parallel Reductions in C++ & CUDA - Unum | Unifying CS and HPC for the future of AGI

2 Likes

Și ceva related la acel thread cu benchmark-uri: CppCon 2015: Bryce Adelstein-Lelbach “Benchmarking C++ Code" - YouTube.

E un talk în care povestește cum ar trebui făcute benchmark-urile astfel încât să nu fie inutile, intră în puțină statistică.

Ah vad ca prefix sum inca e la putere :smiley:

Nu stiu daca s-au mai gasit modalitati mai bune de a face asta, dar imi amintesc de o implementare faina cu arbori de la Nvidia.

Pentru un array cu cateva miliarde de valori, rezultatul era de vreo 10x mai rapid pe GPU versus la vremea aia pe un Xeon.

Presupun ca e cel mai important algoritm momentan, deoarece se aplica la integrale samd. Problema cea mai mare era ca pierdea din acuratete destul de mult fara sa te joci putin cu pierderile, chiar sunt curios daca s-a rezolvat problema asta.

1 Like