тасование и сохранение ограничений NRooks - PullRequest
7 голосов
/ 23 июня 2011

Я внедряю raytracer, и я занимаюсь реализацией сэмплеров. Сэмплер - это генератор случайных точек над квадратом x = 0: 1, y = 0: 1. Каждый сэмплер содержит несколько наборов «случайных» сэмплов, и каждый набор содержит заданное количество сэмплов.

Теперь, один из семплеров - NRooks. Он делит поверхность на блоки n x n, выбирает блоки по диагонали, в каждом диагональном блоке выделяет случайную точку и, наконец, перетасовывает сначала x между собой, затем y.

enter image description here

Это все красиво и чисто. Однако, когда пришло время извлечь точки, книга, за которой я следую, предлагает эти дополнительные требования, чтобы нарушить корреляции между последующими пикселями и выборками. Первое требование заключается в том, что каждый раз, когда набор исчерпан, новый набор выборок выбирается случайным образом. Код, реализованный для достижения этой цели, следующий:

 Point2D Sampler::sample_unit_square(void) { 
    if (count % num_samples == 0) jump = (rand_int() % num_sets) * num_samples;
    return (samples[jump + count++ % num_samples]
 }

, где samples - это вектор Point2D размером num_samples*num_sets (линеаризован). Каждый раз, когда делается один пиксель (число делится на num_samples), новый переход извлекается и используется для указания линейного массива для начала нового набора.

Поскольку я использую python, моя стратегия использует итераторы:

def __iter__(self):

    while True:
        for sample_set in random.choice(self._samples_sets):
            for sample in sample_set:
                yield sample

Это тривиально, и работает нормально.

Вторая необходимость - перетасовать индексы, и вот где мой вопрос. Книга пересматривает код следующим образом

 Point2D Sampler::sample_unit_square(void) { 
    if (count % num_samples == 0) jump = (rand_int() % num_sets) * num_samples;
    return (samples[jump + shuffled_indices[ jump + count++ % num_samples]]
 }

где перетасованные индексы - это массив, вычисляемый следующим образом

 void Sampler::setup_shuffled_indices(void) {
     shuffled_indices.reserve(num_samples*num_sets);
     vector<int> indices;

     for (int j=0; j<num_samples; j++) indices.push_back(j);

     for (int p=0; p<num_sets; p++) {
          random_shuffle(indices.begin(), indices.end());
          for (int j=0; j<num_samples; j++) {
              shuffled_indices.push_back(indices[j]);
          }
     }
 }

, который является очень C ++ способом взять список чисел от 1 до n и перемешать их. Я хотел реализовать следующий код в Python

def __iter__(self):

    while True:
        sample_set = random.choice(self._samples_sets):
        shuffled_set = sample_set[:]
        random.shuffle(shuffled_set)
        for sample in shuffled_set:
            yield sample

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

... Еще одна возможность [удалить корреляцию] состоит в том, чтобы использовать конечный случайный порядок на выборках каждого набора, но это разрушает условие n-rooks [...]. Лучшим способом является случайное перемешивание индексов, используемых в sample_unit_square, для каждого набора, но при этом гарантируется, что используются все образцы.

Что я не понимаю, так это: почему это говорит о том, что окончательное перемешивание на сэмплах каждого набора разбивает n-ладьи? Дело в том, что он использует косвенное индексирование в массив точек. Этот косвенный индекс создается путем перестановки всех индексов от 1 до количества наборов, но это эквивалентно перемешиванию на всех выборках в каждом наборе. Будучи ИМХО эквивалентным, я не понимаю, почему первая формулировка должна сломать n-ладьи, а вторая - нет.

Книга, для протокола: «Трассировка луча с нуля», Кевин Сафферн.

1 Ответ

1 голос
/ 23 июня 2011

Это выглядит как

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

предлагает перетасовать каждый набор независимо после того, как наборы перемешаны.

def __iter__(self):

    while True:
        for sample_set in random.choice(self._samples_sets):
            for sample in random.choice(sample_set):
                yield sample

Вот так. Я не эксперт по Python, поэтому прости любую ошибку в коде Это сломало бы n-ладьи, хотя это может быть просто плохой идеей. Это зависит от того, что вы собираетесь.

...