генерация случайного массива в c ++ 11 - PullRequest
0 голосов
/ 01 сентября 2018

Я хочу создать массив MxN (M частиц в N размерном пространстве), заполненный случайными числами в пределах верхней и нижней границ. У меня есть рабочий код Python, который выглядит примерно так:

# upper_bound/lower_bound are arrays of shape (dim,)
positions = np.random.rand(num_particle,dim)*(upper_bound-lower_bound)+lower_bound

Каждая строка представляет частицу, а каждый столбец представляет измерение в проблемном пространстве. Таким образом, upper_bound и lower_bound применяются к каждому столбцу. Теперь я хочу перевести приведенный выше код на c ++, и у меня есть что-то вроде этого:

#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
#include <ctime>

typedef std::vector<double> vect1d;

std::vector<vect1d> positions;

for (int i=0; i<num_particle; i++){
    std::mt19937_64 generator(static_cast<std::mt19937::result_type>(time(0)));
    std::uniform_real_distribution<double> distribution(0,1);
    vect1d pos(dimension);
    std::generate(pos.begin(),pos.end(),distribution(generator));
    positions[i] = pos;
    }

Мои проблемы:

  1. Выдает ошибку относительно генератора, поэтому я не уверен, правильно ли я его установил. Я также не уверен, как использовать std::generator. Я пробую это, как я смотрел на другие подобные посты, и кажется, что это позволяет мне генерировать более одного случайного числа за раз, поэтому мне не нужно запускать его MxN раз для каждого элемента. Это правда и как правильно его использовать?

  2. В Python я могу просто векторизовать и транслировать, чтобы манипулировать массивом numpy. Какой самый «векторизованный» способ сделать это в C ++?

  3. Приведенный выше (неправильный) код создает только случайное число от 0 до 1, но как включить lower_bound и upper_bound, как в версии Python? Я понимаю, что я могу изменить значения внутри distribution(0,1), но проблема в том, что пределы могут быть разными для каждого измерения (поэтому каждый столбец может иметь различный допустимый диапазон), так каков наиболее эффективный способ генерации случайного числа с учетом диапазон для каждого измерения?

Спасибо

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Прежде всего, вы делаете больше работы, чем вам нужно с вашей версией Python, просто используйте:

np.random.uniform(lower_bound, upper_bound, size=(num_particle, dim))

В вашей попытке C ++ строка

std::generate(pos.begin(),pos.end(),distribution(generator));

Неправильно, поскольку третий аргумент должен быть функцией, а не значением. Разумный эквивалент C ++ будет:

using RandomVector = std::vector<double>;
using RandomMatrix = std::vector<RandomVector>;

template <typename Generator=std::mt19937_64>
RandomMatrix&
fill_uniform(const double low, const double high, RandomMatrix& result)
{
    Generator gen {static_cast<typename Generator::result_type>(time(0))};
    std::uniform_real_distribution<double> dist {low, high};
    for (auto& col : result) {
        std::generate(std::begin(col), std::end(col), [&] () { return dist(gen); });
    }
    return result;
}

template <typename Generator=std::mt19937_64>
RandomMatrix
generate_uniform(const double low, const double high,
                 const std::size_t ncols, const std::size_t nrows)
{
    RandomMatrix result(ncols, RandomVector(nrows));
    return fill_uniform<Generator>(low, high, result);
}

int main()
{
    auto m = generate_uniform(2, 11, 2, 3);
    for (const auto& col : m) {
        for (const auto& v : col) {
            std::cout << v << " ";
        }
        std::cout << '\n';
    }
}

Вы можете обобщить это для генерации тензоров произвольной размерности (например, версии NumPy) без особой работы.

0 голосов
/ 01 сентября 2018

Я буду обращаться к ним в случайном порядке:

  • 3. У вас есть несколько вариантов - использование одного генератора на строку, созданного как distribution(row_lower_limit, row_upper_limit). Должно быть достаточно дешево, чтобы не вызывать проблем. Если вы хотите повторно использовать тот же генератор, просто сделайте что-то вроде row_lower_limit + distribution(generator) * (row_upper_limit - row_lower_limit). Распределение в обоих случаях U[row_lower_limit, row_upper_limit].
  • 2.Векторизация была получена из библиотеки numpy, а не из самого Python. Это обеспечило хороший UX максимум. C ++ не имеет библиотеки, эквивалентной numpy (хотя для нее также есть много библиотек - просто ничего более универсального). Вы не ошибетесь, если сделаете два вложенных for. Возможно, вам лучше будет просто объявить массив NxM, а не vector, например здесь .
  • 1.Не уверен, как помочь с проблемой, так как мы не знаем ошибку. Ссылка cplusplus.com содержит пример того, как инициализировать это со ссылкой на random_device.
...