Поэлементное вектор-векторное умножение в BLAS?

Есть ли способ поэлементного умножения вектор-вектор с помощью BLAS, GSL или любой другой высокопроизводительной библиотеки?


person Tarek    schedule 01.10.2011    source источник


Ответы (4)


(буквально воспринимая название вопроса...)

Да, это можно сделать только с помощью BLAS (хотя это, вероятно, не самый эффективный способ).

Хитрость заключается в том, чтобы рассматривать один из входных векторов как диагональную матрицу:

⎡a    ⎤ ⎡x⎤    ⎡ax⎤
⎢  b  ⎥ ⎢y⎥ =  ⎢by⎥
⎣    c⎦ ⎣z⎦    ⎣cz⎦

Затем вы можете использовать одну из функций умножения матрицы на вектор, которая может принимать диагональную матрицу в качестве входных данных без заполнения, например. SBMV

Пример:

void ebeMultiply(const int n, const double *a, const double *x, double *y)
{
    extern void dsbmv_(const char *uplo,
                       const int *n,
                       const int *k,
                       const double *alpha,
                       const double *a,
                       const int *lda,
                       const double *x,
                       const int *incx,
                       const double *beta,
                       double *y,
                       const int *incy);

    static const int k = 0; // Just the diagonal; 0 super-diagonal bands
    static const double alpha = 1.0;
    static const int lda = 1;
    static const int incx = 1;
    static const double beta = 0.0;
    static const int incy = 1;

    dsbmv_("L", &n, &k, &alpha, a, &lda, x, &incx, &beta, y, &incy);
}

// Test
#define N 3
static const double a[N] = {1,3,5};
static const double b[N] = {1,10,100};
static double c[N];

int main(int argc, char **argv)
{
    ebeMultiply(N, a, b, c);
    printf("Result: [%f %f %f]\n", c[0], c[1], c[2]);
    return 0;
}

Result: [1.000000 30.000000 500.000000]

person finnw    schedule 17.11.2012
comment
Я знаю, что это довольно поздно, но я просто хочу сказать, что, хотя этот ответ finnw является действительным, я, вероятно, не рекомендую его использовать. В моих практических случаях просто писать циклы самому было намного быстрее (в 2-3 раза). Я не знаю, насколько мой компилятор оптимизирует, но обычно переход на blas дает хорошее ускорение (например, в 2-3 раза в другом направлении) вместо замедления. Конечно, это зависит от нескольких факторов, но просто как предупреждение о времени расчетов. - person oli; 31.08.2017
comment
Я могу подтвердить выводы @oli. Для меня ssbmv с N = 300 был примерно в 20 раз медленнее, чем два вложенных цикла for. Я использую Intel Xeon X7560, OpenBLAS и GCC 8.3.0 с параметрами -O2 -fPIC -fstack-protector-strong. Я предполагаю, что ?sbmv слишком общий и не может оптимально использовать векторизованные инструкции. - person Witiko; 20.08.2020

Я обнаружил, что MKL имеет целый набор математических операций над вектором в своей библиотеке векторных математических функций (VML), включая v?Mul, который делает то, что я хочу. Он работает с массивами c++, поэтому мне удобнее, чем GSL.

person Tarek    schedule 03.10.2011

Всегда существует std::valarray1, который определяет поэлементные операции, которые часто (Intel C++ /Quse-intel-optimized-headers, G++) компилируются в инструкции SIMD, если цель их поддерживает.

Оба этих компилятора также будут выполнять автоматическую векторизацию.

В этом случае вы можете просто написать

#define N 10000 

float a[N], b[N], c[N]; 

void f1() { 
  for (int i = 1; i < N; i++) 
  c[i] = a[i] + b[i]; 
} 

и посмотрите, как он компилируется в векторизованный код (например, с использованием SSE4)

1 Да, они архаичны и часто считаются устаревшими, но на практике они оба стандартны и очень хорошо подходят для этой задачи.

person sehe    schedule 03.10.2011
comment
Кажется, что ваша первая ссылка мертва. - person Bracula; 18.01.2019

В GSL gsl_vector_mul делает свое дело.

person jmbr    schedule 01.10.2011