Кто-нибудь может предоставить какой-нибудь псевдокод для функции выбора рулетки? Как бы это реализовать: я действительно не понимаю, как читать эту математическую запись. Я хочу, чтобы для этого был общий алгоритм.
беззнаковое целое число = :: rand ()% 37;





Для этого есть 2 шага: Сначала создайте массив со всеми значениями на колесе. Это может быть двухмерный массив с цветом и числом, или вы можете добавить 100 к красным числам.
Затем просто сгенерируйте случайное число между 0 или 1 (в зависимости от того, начинает ли ваш язык нумеровать индексы массива с 0 или 1) и последним элементом в вашем массиве.
Большинство языков имеют встроенные функции случайных чисел. В VB и VBScript функция - RND(). В Javascript это Math.random()
Получите значение из этой позиции в массиве, и у вас будет случайный номер рулетки.
Заключительное примечание: не забудьте заполнить генератор случайных чисел, иначе вы будете получать одну и ту же последовательность розыгрышей при каждом запуске программы.
Псевдокод генератора случайных чисел
Используйте цифры случайного числа, чтобы создать случайные числа от 1 до 38 (или 37 европейских) для рулетки.
Я думаю, что случайные числа решались на всех языках программирования, и этот процесс больше не нужно выполнять вручную. Почему вы не упомянули о подключении всех полусумматоров, пока вы это делаете?
Что ж, для колеса американской рулетки вам нужно будет сгенерировать случайное целое число от 1 до 38. Есть 36 чисел, 0 и 00.
Тем не менее, одна из важных вещей, которые следует учитывать, заключается в том, что в американской рулетке можно делать множество различных ставок. Одиночная ставка может покрывать 1, 2, 3, 4, 5, 6, две разные 12 или 18. Вы можете создать список списков, в котором каждое число имеет дополнительные флажки, чтобы упростить это, или сделать все это в программе. .
Если бы я реализовал его на Python, я бы просто создал кортеж от 0, 00 и от 1 до 36 и использовал random.choice () для каждого вращения.
Другие ответы, похоже, предполагают, что вы пытаетесь реализовать игру в рулетку. Думаю, вы спрашиваете о выборе колеса рулетки в эволюционных алгоритмах.
Вот код Java, реализующий выбор колеса рулетки.
Предположим, у вас есть 10 элементов на выбор, и вы выбираете, генерируя случайное число от 0 до 1. Вы делите диапазон от 0 до 1 на десять неперекрывающихся сегментов, каждый из которых пропорционален пригодности одного из десяти элементов. Например, это может выглядеть так:
0 - 0.3 is item 1
0.3 - 0.4 is item 2
0.4 - 0.5 is item 3
0.5 - 0.57 is item 4
0.57 - 0.63 is item 5
0.63 - 0.68 is item 6
0.68 - 0.8 is item 7
0.8 - 0.85 is item 8
0.85 - 0.98 is item 9
0.98 - 1 is item 10
Это ваше колесо рулетки. Ваше случайное число от 0 до 1 - это ваше вращение. Если случайное число 0,46, то выбран элемент 3. Если это 0,92, то это элемент 9.
Это самый быстрый из тех, с которыми я когда-либо сталкивался. Очень хорошо.
Никто не говорит о замене выделенного элемента, чтобы выбранный элемент больше не выделялся. Любое решение для этого?
@AnikIslamAbhi, насколько я понимаю, выбор колеса рулетки предполагает, что каждый элемент можно выбрать более одного раза. Если вы рандомизируете N раз (где N - количество популяции), вы бы взяли точно такую же популяцию после отбора.
Сначала сгенерируйте массив назначенных вами процентов, скажем, p[1..n].
и предположим, что общая сумма является суммой всех процентов.
Затем получите случайное число от 1 до всего, скажем, r.
Теперь алгоритм на lua:
local c = 0
for i = 1,n do
c = c + p[i]
if r <= c then
return i
end
end
Это предполагает некоторый класс «Классификатор», который имеет только условие String, сообщение String и двойную силу. Просто следуйте логике.
-- Павел
public static List<Classifier> rouletteSelection(int classifiers) {
List<Classifier> classifierList = new LinkedList<Classifier>();
double strengthSum = 0.0;
double probabilitySum = 0.0;
// add up the strengths of the map
Set<String> keySet = ClassifierMap.CLASSIFIER_MAP.keySet();
for (String key : keySet) {
/* used for debug to make sure wheel is working.
if (strengthSum == 0.0) {
ClassifierMap.CLASSIFIER_MAP.get(key).setStrength(8000.0);
}
*/
Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
double strength = classifier.getStrength();
strengthSum = strengthSum + strength;
}
System.out.println("strengthSum: " + strengthSum);
// compute the total probability. this will be 1.00 or close to it.
for (String key : keySet) {
Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
double probability = (classifier.getStrength() / strengthSum);
probabilitySum = probabilitySum + probability;
}
System.out.println("probabilitySum: " + probabilitySum);
while (classifierList.size() < classifiers) {
boolean winnerFound = false;
double rouletteRandom = random.nextDouble();
double rouletteSum = 0.0;
for (String key : keySet) {
Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
double probability = (classifier.getStrength() / strengthSum);
rouletteSum = rouletteSum + probability;
if (rouletteSum > rouletteRandom && (winnerFound == false)) {
System.out.println("Winner found: " + probability);
classifierList.add(classifier);
winnerFound = true;
}
}
}
return classifierList;
}
Вот немного кода на Python:
def roulette_select(population, fitnesses, num):
""" Roulette selection, implemented according to:
<http://stackoverflow.com/questions/177271/roulette
-selection-in-genetic-algorithms/177278#177278>
"""
total_fitness = float(sum(fitnesses))
rel_fitness = [f/total_fitness for f in fitnesses]
# Generate probability intervals for each individual
probs = [sum(rel_fitness[:i+1]) for i in range(len(rel_fitness))]
# Draw new population
new_population = []
for n in xrange(num):
r = rand()
for (i, individual) in enumerate(population):
if r <= probs[i]:
new_population.append(individual)
break
return new_population
будет ли это работать, даже если некоторые из значений пригодности отрицательны?
Нет, не будет. Но вы должны задаться вопросом: поскольку приспособленность соответствует вероятности получения этой выборки, не существует такой вещи, как отрицательная вероятность получения выборки, поэтому какого поведения вы можете ожидать?
Я хочу сказать, что у меня есть фитнес-функция, которая дает отрицательные значения. Предположим, я решаю задачу, в которой пригодность является «ошибочной», т.е. отличие целевого значения от значения, полученного ГА. В этом случае фитнес-функция будет генерировать отрицательные значения. Как мне сформулировать это в виде колеса Routtle?
Как я уже сказал, вы должны подумать о том, что вы хотите делать с этими отрицательными значениями! Колесо рулетки не принимает значения фитнес в качестве входных данных, но (ненормализованное) вероятности. Вы должны найти способ превратить эти, возможно, отрицательные значения ошибок в вероятности. Вы делаете что-то странное, если у вас могут быть отрицательные значения ошибка, но, возможно, вы можете просто отрицать их (error = -error), тогда то, что я обычно делаю, - это fitness = 1/(1+error).
Выбор колеса рулетки не работает с отрицательными значениями пригодности. Попробуйте отбор турниров.
вы не заменили выбранного человека. Разве это не открыло путь для того, чтобы тот же самый элемент был снова выбран в популяции?
Вы можете использовать такую структуру данных:
Map<A, B> roulette_wheel_schema = new LinkedHashMap<A, B>()
где A - целое число, представляющее карман колеса рулетки, а B - индекс, который идентифицирует хромосому в популяции. Количество карманов пропорционально приспособленности каждой хромосомы:
количество карманов = (соответствие пригодности) · (коэффициент масштабирования)
Затем мы генерируем случайное число от 0 до размера схемы выбора и с помощью этого случайного числа получаем индекс хромосомы из рулетки.
Мы вычисляем относительную ошибку между пропорциональной приспособленностью каждой хромосомы и вероятностью быть выбранной схемой отбора.
Метод getRouletteWheel возвращает схему выбора на основе предыдущей структуры данных.
private Map<Integer, Integer> getRouletteWheel(
ArrayList<Chromosome_fitnessProportionate> chromosomes,
int precision) {
/*
* The number of pockets on the wheel
*
* number of pockets in roulette_wheel_schema = probability ·
* (10^precision)
*/
Map<Integer, Integer> roulette_wheel_schema = new LinkedHashMap<Integer, Integer>();
double fitness_proportionate = 0.0D;
double pockets = 0.0D;
int key_counter = -1;
double scale_factor = Math
.pow(new Double(10.0D), new Double(precision));
for (int index_cromosome = 0; index_cromosome < chromosomes.size(); index_cromosome++){
Chromosome_fitnessProportionate chromosome = chromosomes
.get(index_cromosome);
fitness_proportionate = chromosome.getFitness_proportionate();
fitness_proportionate *= scale_factor;
pockets = Math.rint(fitness_proportionate);
System.out.println("... " + index_cromosome + " : " + pockets);
for (int j = 0; j < pockets; j++) {
roulette_wheel_schema.put(Integer.valueOf(++key_counter),
Integer.valueOf(index_cromosome));
}
}
return roulette_wheel_schema;
}
Я хотел того же и поэтому создал этот автономный класс Roulette. Вы даете ему серию весов (в форме двойного массива), и он просто возвращает индекс из этого массива в соответствии с взвешенным случайным выбором.
Я создал класс, потому что вы можете значительно ускориться, выполнив накопительные дополнения только один раз через конструктор. Это код C#, но наслаждайтесь скоростью и простотой C!
class Roulette
{
double[] c;
double total;
Random random;
public Roulette(double[] n) {
random = new Random();
total = 0;
c = new double[n.Length+1];
c[0] = 0;
// Create cumulative values for later:
for (int i = 0; i < n.Length; i++) {
c[i+1] = c[i] + n[i];
total += n[i];
}
}
public int spin() {
double r = random.NextDouble() * total; // Create a random number between 0 and 1 and times by the total we calculated earlier.
//int j; for (j = 0; j < c.Length; j++) if (c[j] > r) break; return j-1; // Don't use this - it's slower than the binary search below.
//// Binary search for efficiency. Objective is to find index of the number just above r:
int a = 0;
int b = c.Length - 1;
while (b - a > 1) {
int mid = (a + b) / 2;
if (c[mid] > r) b = mid;
else a = mid;
}
return a;
}
}
Начальный вес зависит от вас. Может быть, это может быть пригодность каждого члена или значение, обратно пропорциональное положению члена в «50 лучших». Например: 1-е место = 1,0 взвешивания, 2-е место = 0,5, 3-е место = 0,333, 4-е место = 0,25 взвешивания и т. д.
Вот действительно быстрый способ сделать это с помощью выбора потока в Java. Он выбирает индексы массива, используя значения в качестве весов. Никаких кумулятивных весов не требуется из-за математические свойства.
static int selectRandomWeighted(double[] wts, Random rnd) {
int selected = 0;
double total = wts[0];
for( int i = 1; i < wts.length; i++ ) {
total += wts[i];
if ( rnd.nextDouble() <= (wts[i] / total)) selected = i;
}
return selected;
}
Это можно было бы дополнительно улучшить, используя Суммирование Кахана или чтение двойников как итерацию, если массив был слишком большим для одновременной инициализации.
Это выглядит интересным решением. Я также дал ответ в тот же час, что и вы, несмотря на то, что вопрос был лет (возможно, вы видели мой пост). В любом случае, мне нравится ваш, потому что он такой короткий, но я думаю, что мой может быть более эффективным из-за эффективности O (log2 n) вместо вашего O (n).
Я думаю, что вы наткнулись на вопрос, заставив меня опубликовать свой ответ. Во всяком случае, ваша начальная совокупная сумма по-прежнему занимает O(n). Я думаю, что это определенно нижняя граница, несмотря ни на что :)
Только впервые в конструкторе. В реальном мире вы будете делать много «вращений рулетки» (то есть искать много разных родительских пар). Здесь вступает в игру O (log2 n), поскольку после этого вызывается только метод spin ().
Это верно, если вы хотите многократно рисовать из одного и того же дистрибутива. Но я думаю, что на практике и по моему опыту такого не происходит; например, в генетических алгоритмах веса приспособленности всегда меняются. Кроме того, если вы собираетесь взять огромную выборку из такого распределения, вам вообще не нужно действительно рандомизировать, поскольку дробь сходится к нормализованным весам.
Возможно, предоставлено для GA, как вы говорите. Для случая, когда мне это было нужно (имитация миллионов или миллиардов ставок для проверки риска / прибыли), мой код ответа O (log2 n) является улучшением. Я уверен, что будут и другие случаи.
Боюсь, что любой, кто использует встроенный генератор случайных чисел на всех языках программирования, должен знать, что сгенерированное число не является на 100% случайным, поэтому следует использовать его с осторожностью.
Спасибо за ценную информацию.
Я разработал код Java, похожий на код Дэна Дайера (упоминавшийся ранее). Однако мое колесо рулетки выбирает один элемент на основе вектора вероятности (входных данных) и возвращает индекс выбранного элемента. Сказав это, следующий код более подходит, если размер выборки является унитарным и если вы не предполагаете, как рассчитываются вероятности, и допускается нулевое значение вероятности. Код является самодостаточным и включает тест с 20 вращениями колеса (на запуск).
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Roulette-wheel Test version.
* Features a probability vector input with possibly null probability values.
* Appropriate for adaptive operator selection such as Probability Matching
* or Adaptive Pursuit, (Dynamic) Multi-armed Bandit.
* @version October 2015.
* @author Hakim Mitiche
*/
public class RouletteWheel {
/**
* Selects an element probabilistically.
* @param wheelProbabilities elements probability vector.
* @param rng random generator object
* @return selected element index
* @throws java.lang.Exception
*/
public int select(List<Double> wheelProbabilities, Random rng)
throws Exception{
double[] cumulativeProba = new double[wheelProbabilities.size()];
cumulativeProba[0] = wheelProbabilities.get(0);
for (int i = 1; i < wheelProbabilities.size(); i++)
{
double proba = wheelProbabilities.get(i);
cumulativeProba[i] = cumulativeProba[i - 1] + proba;
}
int last = wheelProbabilities.size()-1;
if (cumulativeProba[last] != 1.0)
{
throw new Exception("The probabilities does not sum up to one ("
+ "sum = "+cumulativeProba[last]);
}
double r = rng.nextDouble();
int selected = Arrays.binarySearch(cumulativeProba, r);
if (selected < 0)
{
/* Convert negative insertion point to array index.
to find the correct cumulative proba range index.
*/
selected = Math.abs(selected + 1);
}
/* skip indexes of elements with Zero probability,
go backward to matching index*/
int i = selected;
while (wheelProbabilities.get(i) == 0.0){
System.out.print(i+" selected, correction");
i--;
if (i<0) i=last;
}
selected = i;
return selected;
}
public static void main(String[] args){
RouletteWheel rw = new RouletteWheel();
int rept = 20;
List<Double> P = new ArrayList<>(4);
P.add(0.2);
P.add(0.1);
P.add(0.6);
P.add(0.1);
Random rng = new Random();
for (int i = 0 ; i < rept; i++){
try {
int s = rw.select(P, rng);
System.out.println("Element selected "+s+ ", P(s) = "+P.get(s));
} catch (Exception ex) {
Logger.getLogger(RouletteWheel.class.getName()).log(Level.SEVERE, null, ex);
}
}
P.clear();
P.add(0.2);
P.add(0.0);
P.add(0.5);
P.add(0.0);
P.add(0.1);
P.add(0.2);
//rng = new Random();
for (int i = 0 ; i < rept; i++){
try {
int s = rw.select(P, rng);
System.out.println("Element selected "+s+ ", P(s) = "+P.get(s));
} catch (Exception ex) {
Logger.getLogger(RouletteWheel.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* {@inheritDoc}
* @return
*/
@Override
public String toString()
{
return "Roulette Wheel Selection";
}
}
Ниже пример выполнения для вектора вероятности P = [0.2,0.1,0.6,0.1], WheelElements = [0,1,2,3]:
Выбран элемент 3, P (s) = 0,1
Выбран элемент 2, P (s) = 0,6
Выбран элемент 3, P (s) = 0,1
Выбран элемент 2, P (s) = 0,6
Выбран элемент 1, P (s) = 0,1
Выбран элемент 2, P (s) = 0,6
Выбран элемент 3, P (s) = 0,1
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 3, P (s) = 0,1
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 0, P (s) = 0,2
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Выбран элемент 2, P (s) = 0,6
Код также проверяет колесо рулетки с нулевой вероятностью.
Отредактировал теги. Кто-то удалил "генетический" тег из первой редакции этого вопроса, что сделало менее ясным, о чем спрашивали.