2016-02-21 3 views
0

Мне нужно пробовать огромную случайную матрицу, размер которой 499 x 15500, т. Е. 7734500 элементов. По этой причине я хотел бы, чтобы процедура отбора проб была максимально эффективной. На данный момент в файле CPP я это делаю:Эффективная выборка однородной случайной матрицы

std::random_device rd; // seed generator 

std::mt19937_64 generator{rd()}; // generator initialized with seed from rd 


std::uniform_int_distribution<> initialize(unsigned long long int modulus) 
{ 
    std::uniform_int_distribution<> unifDist{0, (int)(modulus-1)}; 
    return unifDist; 
} 


Matrix<unsigned int> uniformRandomMatrix 
    (unsigned int rows, unsigned int columns, unsigned long long int modulus) 
{ 
    std::uniform_int_distribution<> dist = initialize(modulus); 

    // Declare and allocate the matrix 
    Matrix<unsigned int> matrix(rows, columns); 
    // this constructor just does a resize on a std::vector 

    // Fill the matrix with random elements 
    for(unsigned int i = 0; i < rows; ++i) 
    { 
     for(unsigned int j = 0; j < columns; ++j) 
     { 
      matrix.setElementAt(i, j, dist(generator)); 
      // setElementAt just does matrix[somePosition] = newElement 
     } 
    } 

    return matrix; 
} 

Обратите внимание, что Matrix реализуется как 1D std::vector для эффективности.

Могу ли я сделать это лучше? Прямо сейчас, выборка этой огромной матрицы занимает приблизительно 0,16 секунды.

EDIT с помощью std::vector::data

Новый подход заключается в следующем: я добавил к Matrix класса метод

inline std::vector<T> exposeVector() 
{ 
    return matrix; // 'matrix' is the name of the private std::vector 
} 

Затем образец равномерная Matrix

Matrix<unsigned int> uniformRandomMatrix 
    (unsigned int rows, unsigned int columns, unsigned long long int modulus) 
{ 
    std::uniform_int_distribution<> dist = initialize(modulus); 

    // Declare and allocate the matrix 
    Matrix<unsigned int> matrix(rows, columns); 

    std::vector<unsigned int> v = matrix.exposeVector(); 
    unsigned int* p = v.data(); 

    for(unsigned int i = 0 ; i < rows*columns ; ++i) 
    { 
     *p = dist(generator); 
     ++p; 
    } 

    return matrix; 
} 

Все, кажется, работайте отлично, но я не получил ничего хорошего.

+0

Другие двигатели могут быть быстрее, чем mersenne twister. Вы можете разбить матрицу ('std :: vector') на блоки и заполнить их параллельно. Убедитесь, что 'Matrix' имеет конструктор перемещения (потому что вы возвращаете его, и копия можно было бы избежать). – Aleph

+0

@Aleph Спасибо за ваши предложения! На самом деле я не думал об изменении движка: я попробую. Я также понимаю, что распараллеливание алгоритма сделает вещи быстрее, но я не понимаю, что вы сказали о конструкторах перемещения ... Я не думаю, что у меня есть один прямо сейчас – minomic

+0

В моих тестах в моей системе версия '64bit' твистер несколько медленнее, чем обычная версия «32bit». Я вижу, что вы допускаете большой диапазон для модуля в параметре функции, но ваш дистрибутив создается с помощью 'int' по умолчанию. В противном случае вы можете получить некоторую выгоду от установки функции back-door в вашей матрице, обеспечивающей доступ к плоскому вектору. – Galik

ответ

0

Это довольно широкий вопрос, на мой взгляд, но я постараюсь дать вам несколько указателей:

  • Во-первых, и, вероятно, самая очевидная вещь будет делать это в несколько потоков std::thred
  • Если ваша матрица является производным классом, а ваш setElementAt является виртуальным, это действительно дорого из-за решения vtable. Избавьтесь от этого (см. Следующую строку)
  • Обычно компилятор уже выполняет множество оптимизаций, но вы все же можете попытаться минимизировать вызовы функций/методов, подвергая vector::data и итерации как один массив for(int i = 0; i < rows*cols; i++); data[i] = random или попробуйте std::generate.
+0

Фактически 'Matrix' не является производным классом: он просто обертывает' std :: vector' и предоставляет некоторые операции (например, сложение, умножение и т. Д.). В любом случае, я думаю, мне придется перейти к параллельной реализации и использовать 'std :: thread'. Что касается 'setElementAt', он просто выполняет' matrix [row * numColumns + column] = elem; ', но, возможно, я могу попытаться вызывать его реже – minomic

+0

В этом случае использование только однопоточного доступа через vector :: data может предоставить любой увеличение производительности, в противном случае потоки ... –

+0

См. редактирование исходного сообщения: я попытался использовать 'std :: vector :: data' (надеюсь, правильно), но ничего не получил. Кажется, что нить - это путь ... – minomic

Смежные вопросы