Как подойти к алгоритму игры с угадайкой чисел (с изюминкой)? - PullRequest
52 голосов
/ 08 октября 2011

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

Вот как будет работать игра:

Пользователи получат предметы со значением. Например,

Apple = 1
Pears = 2
Oranges  = 3

Затем они получат возможность выбрать любую понравившуюся им комбинацию (то есть 100 яблок, 20 груш и один апельсин). Единственный вывод, который получает компьютер - это общая стоимость (в данном примере это в настоящее время 143 доллара). Компьютер попытается угадать, что у них есть. Который, очевидно, не сможет правильно пройти первый ход.

         Value    quantity(day1)    value(day1)
Apple      1        100                100
Pears      2         20                 40
Orange     3          1                  3
Total               121                143

В следующий ход пользователь может изменить свои цифры, но не более 5% от общего количества (или какой-то другой процент, который мы можем выбрать. Я буду использовать 5%, например.). Цены на фрукты могут изменяться (случайным образом), поэтому общая стоимость также может изменяться в зависимости от этого (для простоты в этом примере я не изменяю цены на фрукты). Используя приведенный выше пример, во второй день игры пользователь возвращает значение $ 152 и $ 164 в третий день. Вот пример:

Quantity (day2)   %change (day2)    Value (day2)   Quantity (day3)   %change (day3)   Value(day3)
 104                                 104            106                                106
  21                                  42             23                                 46
   2                                   6              4                                 12
 127               4.96%             152            133               4.72%            164

* (Надеюсь, таблицы отображаются правильно, мне пришлось их вручную расставлять, поэтому надеюсь, что это не просто сделать это на моем экране, если это не сработает, дайте мне знать, и я попытаюсь загрузить скриншот.)

Я пытаюсь выяснить, смогу ли я выяснить, каковы количества со временем (при условии, что у пользователя будет терпение продолжать вводить числа). Я знаю, что сейчас мое единственное ограничение - это общее значение не может превышать 5%, поэтому я не могу быть с точностью до 5%, поэтому пользователь будет вводить его всегда.

Что я сделал до сих пор

Вот мое решение (пока не очень). По сути, я беру все значения и выясняю все возможные их комбинации (я сделал эту часть). Затем я беру все возможные комбинации и помещаю их в базу данных в виде словаря (так, например, за $ 143 может быть запись в словаре {apple: 143, Pears: 0, Oranges: 0} .. вплоть до {apple) : 0, груши: 1, апельсины: 47}. Я делаю это каждый раз, когда получаю новый номер, поэтому у меня есть список всех возможностей.

Вот где я застрял. Используя приведенные выше правила, как я могу найти наилучшее из возможных решений? Я думаю, что мне понадобится фитнес-функция, которая автоматически сравнивает данные за два дня и удаляет любые возможности, которые имеют отклонение более чем на 5% от данных за предыдущие дни.

Вопросы:

Итак, мой вопрос о том, как пользователь изменил общее значение, и у меня есть список всех вероятностей, как мне подойти к этому? Что мне нужно учить? Существуют ли какие-либо алгоритмы или теории, которые я могу использовать, которые применимы? Или, чтобы помочь мне понять мою ошибку, вы можете предложить, какие правила я могу добавить, чтобы сделать эту цель достижимой (если она не находится в ее текущем состоянии. Я думал добавить больше фруктов и сказать, что они должны выбрать как минимум 3 и т. Д.) ? Кроме того, у меня есть только смутное понимание генетических алгоритмов, но я подумал, что смогу использовать их здесь, если есть что-то, что я могу использовать?

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

ОБНОВЛЕНИЕ: Получение обратной связи, что это трудно решить. Поэтому я решил добавить в игру еще одно условие, которое не будет мешать тому, что делает игрок (игра для них остается неизменной), но каждый день стоимость фруктов меняет цену (случайным образом). Это облегчит решение? Потому что в пределах 5% -ого движения и определенных изменений стоимости фруктов возможны лишь несколько комбинаций с течением времени.

День 1 любойЭто возможно, и получить достаточно близкий диапазон почти невозможно, но, поскольку цены на фрукты меняются, и пользователь может выбрать только 5% -ое изменение, тогда (со временем) диапазон не должен быть узким и узким.В приведенном выше примере, если цены достаточно изменчивы, я думаю, что я мог бы грубо заставить решение, которое дало мне диапазон, чтобы угадать, но я пытаюсь выяснить, есть ли более изящное решение или другие решения, чтобы продолжать сужать этот диапазон сверхвремя.

ОБНОВЛЕНИЕ 2: После прочтения и расспросов, я полагаю, что это скрытая проблема Маркова / Витерби, которая отслеживает изменения цен на фрукты, а также общую сумму (взвешивая последнюю точку данных наиболее тяжело).Я не уверен, как применить отношения, хотя.Я думаю, что это так и может быть неправильно, но, по крайней мере, я начинаю подозревать, что это своего рода проблема машинного обучения.

Обновление 3: я создал контрольный пример (с меньшими числами)и генератор, помогающий автоматизировать сгенерированные пользователем данные, и я пытаюсь создать из них график, чтобы увидеть, что является более вероятным.

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

#!/usr/bin/env python
import itertools

# Fruit price data
fruitPriceDay1 = {'Apple':1, 'Pears':2, 'Oranges':3}
fruitPriceDay2 = {'Apple':2, 'Pears':3, 'Oranges':4}
fruitPriceDay3 = {'Apple':2, 'Pears':4, 'Oranges':5}

# Generate possibilities for testing (warning...will not scale with large numbers)
def possibilityGenerator(target_sum, apple, pears, oranges):
    allDayPossible = {}
    counter = 1
    apple_range = range(0, target_sum + 1, apple)
    pears_range = range(0, target_sum + 1, pears)
    oranges_range = range(0, target_sum + 1, oranges)
    for i, j, k in itertools.product(apple_range, pears_range, oranges_range):
        if i + j + k == target_sum:
            currentPossible = {}

            #print counter
            #print 'Apple', ':', i/apple, ',', 'Pears', ':', j/pears, ',', 'Oranges', ':', k/oranges
            currentPossible['apple'] = i/apple
            currentPossible['pears'] = j/pears
            currentPossible['oranges'] = k/oranges

            #print currentPossible
            allDayPossible[counter] = currentPossible
            counter = counter +1
    return allDayPossible

# Total sum being returned by user for value of fruits
totalSumDay1=26 # Computer does not know this but users quantities are apple: 20, pears 3, oranges 0 at the current prices of the day
totalSumDay2=51 # Computer does not know this but users quantities are apple: 21, pears 3, oranges 0 at the current prices of the day
totalSumDay3=61 # Computer does not know this but users quantities are apple: 20, pears 4, oranges 1 at the current prices of the day
graph = {}
graph['day1'] = possibilityGenerator(totalSumDay1, fruitPriceDay1['Apple'], fruitPriceDay1['Pears'], fruitPriceDay1['Oranges'] )
graph['day2'] = possibilityGenerator(totalSumDay2, fruitPriceDay2['Apple'], fruitPriceDay2['Pears'], fruitPriceDay2['Oranges'] )
graph['day3'] = possibilityGenerator(totalSumDay3, fruitPriceDay3['Apple'], fruitPriceDay3['Pears'], fruitPriceDay3['Oranges'] )

# Sample of dict = 1 : {'oranges': 0, 'apple': 0, 'pears': 0}..70 : {'oranges': 8, 'apple': 26, 'pears': 13}
print graph

Ответы [ 5 ]

12 голосов
/ 08 октября 2011

Мы объединим теорию графов и вероятность:

В 1-й день создайте набор всех возможных решений. Обозначим решения, заданные как A1 = {a1 (1), a1 (2), ..., a1 (n)}.

На второй день вы снова можете построить набор решений A2.

Теперь для каждого элемента в A2 вам нужно проверить, можно ли его достичь из каждого элемента A1 (с учетом x% допуска). Если это так - подключите A2 (n) к A1 (m). Если это не может быть достигнуто с любого узла в A1 (m) - вы можете удалить этот узел.

В основном мы строим связный ориентированный ациклический граф.

Все пути на графике одинаково вероятны. Точное решение можно найти только при наличии одного ребра от Am до Am + 1 (от узла в Am до узла в Am + 1).

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

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

Также взгляните на линейных дифантовых уравнений с неотрицательными значениями - Вопрос, который я задал некоторое время назад. Принятый ответ - отличный способ перечислить все комбинации на каждом шаге.

7 голосов
/ 08 октября 2011

Эту проблему невозможно решить.

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

У пользователя естьN плодов и у вас есть D дней угадывания.

В каждый день вы получаете N новых переменных, а затем у вас есть в общей сложности D * N переменных.

Для каждого дня вы можете сгенерировать только два уравнения,Одно уравнение представляет собой сумму n_item * цена, а другое основано на известном соотношении.Всего у вас есть не более 2 * D уравнений, если они все независимы.

2 * D 2

6 голосов
/ 10 октября 2011

Отказ от ответственности: я резко изменил свой ответ после того, как временно удалил свой ответ и внимательно перечитал вопрос, поскольку неправильно прочитал некоторые важные части вопроса. Все еще ссылаясь на похожие темы и алгоритмы, ответ был значительно улучшен после того, как я попытался решить некоторые проблемы в C # самостоятельно.

Голливудская версия

  • Проблема - Задача удовлетворения динамических ограничений (DCSP), вариант Проблемы удовлетворения ограничений (CSP.)
  • Используйте Монте-Карло , чтобы найти потенциальные решения для данного дня, если значения и диапазоны количеств не являются крошечными. В противном случае используйте грубую силу, чтобы найти все возможные решения.
  • Используйте Запись ограничений (относится к DCSP), применяемая каскадно к предыдущим дням, чтобы ограничить потенциальный набор решений.
  • Скрестите пальцы, прицельтесь и стреляйте (Угадайте), основываясь на вероятности.
  • (Необязательно) Победит Брюс Уиллис.

Оригинальная версия

Во-первых, я хотел бы заявить о двух основных проблемах:

  1. Огромное количество возможных решений. Зная только количество предметов и общую стоимость, скажем, например, 3 и 143, мы получим много возможных решений. Плюс, нелегко иметь алгоритм, выбирающий правильное решение без неизбежной попытки неверных решений (всего не равно 143).

  2. Если для данного дня найдены возможные решения D i , необходимо найти способ устранения потенциальных решений с помощью дополнительной информации, предоставленной {D i + 1 .. D i + n }.

Давайте заложим некоторые основы для следующих примеров:

  • Позволяет сохранить одинаковые значения предметов, всю игру. Он может быть произвольным или выбранным пользователем.
  • Возможные значения элемента привязаны к очень ограниченному диапазону [1-10], где никакие два элемента не могут иметь одинаковое значение.
  • Количество предметов не может превышать 100. Это означает: [0-100].

Чтобы решить эту проблему проще Я позволил себе сменить одно ограничение , что заставляет алгоритм сходиться быстрее:

  • Правило «общее количество» переопределяется этим правилом: вы можете добавлять или удалять любое количество элементов в диапазоне [1–10], всего за один день. Однако вы не можете добавлять или удалять одинаковое количество элементов, всего более двух раз. Это также дает игре максимальный жизненный цикл 20 дней.

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

По моему скромному мнению, это правило не является сущностью игры, а лишь посредником, позволяющим компьютеру решить проблему.

Проблема 1: Поиск потенциальных решений

Для начала, задача 1. может быть решена с использованием алгоритма Монте-Карло , чтобы найти набор потенциальных решений. Техника проста: генерировать случайные числа для значений и количеств товара (в пределах их допустимого диапазона). Повторите процесс для необходимого количества предметов. Проверьте, является ли решение приемлемым. Это означает проверку, имеют ли предметы разные значения, и сумма равна нашему целевому итогу (скажем, 143).

Хотя этот метод имеет преимущество в простоте реализации, он имеет некоторые недостатки:

  • Решение пользователя не гарантируется в наших результатах.
  • Много "промахов". Например, требуется более 3 000 000 попыток найти 1000 потенциальных решений с учетом наших ограничений.
  • Это занимает много времени: от 4 до 5 секунд на моем ленивом ноутбуке.

Как обойти эти недостатки? Ну ...

  • Ограничить диапазон меньшими значениями и
  • Найдите достаточное количество потенциальных решений, поэтому есть большая вероятность, что пользовательское решение появится в вашем наборе решений.
  • Используйте эвристику, чтобы легче находить решения (подробнее об этом позже).

Обратите внимание, что чем больше вы ограничиваете диапазоны, тем менее полезным будет алгоритм Монте-Карло, поскольку будет достаточное количество действительных решений для их повторения в разумные сроки.Для ограничений {3, [1-10], [0-100]} существует около 741 000 000 действительных решений (не ограниченных целевым общим значением.) Монте-Карло можно использовать там.Для {3, [1-5], [0-10]} есть только около 80 000.Не нужно использовать Монте-Карло;петли грубой силы for прекрасно подойдут.

Я полагаю, что проблема 1 - это то, что вы бы назвали проблемой удовлетворения ограничений (или CSP.)

Задача 2: Ограничить набор потенциальных решений

Учитывая тот факт, что задача 1 является CSP, я бы назвал задачу 2 ,и проблема в целом, Динамический CSP (или DCSP.)

[DCSP] полезны, когда первоначальная формулировка проблемы каким-либо образом изменяется, обычно потому, чтоНабор ограничений для рассмотрения развивается из-за окружающей среды.DCSP рассматриваются как последовательность статических CSP, каждый из которых является преобразованием предыдущего, в котором переменные и ограничения могут быть добавлены (ограничение) или удалены (релаксация).

Один метод, используемый с CSP, которыйможет быть полезно для этой проблемы называется Запись ограничений :

  • С каждым изменением среды (введенные пользователем значения для D i + 1 ), найтиинформация о новом ограничении: Каковы, возможно, «используемые» количества для ограничения добавления-удаления.
  • Примените ограничение к каждому предыдущему дню в каскаде.Волнообразные эффекты могут значительно сократить возможные решения.

Чтобы это работало, вам необходимо ежедневно получать новый набор возможных решений;Используйте грубую силу или Монте-Карло.Затем сравните решения D i с D i-1 и оставьте только те решения, которые могут преуспеть в решениях предыдущих дней без нарушения ограничений.

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

Существует множество других шагов, которые можно предпринять для дальнейшего улучшения вашего решения.Вот некоторые идеи:

  • Запишите ограничения для комбинаций предмет-значение, найденные в решениях предыдущих дней.Немедленно отклоните другие решения (так как значения элементов не должны изменяться.) Вы могли бы даже найти меньшие наборы решений для каждого существующего решения, используя ограничения для конкретного решения, чтобы отклонить недействительные решения ранее.
  • Создать некоторый «мутант», полныйистория, решения каждый день для того, чтобы «починить» случай, когда набор решений D 1 не содержит решения пользователя.Вы можете использовать генетический алгоритм для поиска популяции мутантов на основе существующего набора решений.)
  • Используйте эвристику, чтобы легко находить решения (например, когда найдено правильное решение, попробуйте найти варианты этого решения, подставив подстановкуколичества вокруг.)
  • Использование поведенческой эвристики для прогнозирования некоторых действий пользователя (например, одинаковое количество для каждого элемента, экстремальные шаблоны и т. д.)
  • Продолжайте делать некоторые вычисления, пока пользователь вводит новыйколичества.

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

3 голосов
/ 14 октября 2011

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

Я подошел к этому с точки зрения машинного обучения и рассмотрел проблему как скрытую марковскую модель, где общая цена была наблюдением. Мое решение состоит в том, чтобы использовать фильтр частиц. Это решение написано на Python 2.7 с использованием NumPy и SciPy.

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

Каждая итерация выводит текущие истинные величины и предположение. Я просто передаю вывод в файл, чтобы можно было легко просмотреть его. Интересным расширением будет вывод графика на графике 2D (для 2 фруктов) или 3D (для 3 фруктов). Тогда вы сможете увидеть фильтр частиц, заточенный на раствор.

Обновление:

Изменен код для включения обновленных параметров после настройки. Включено построение звонков с использованием matplotlib (через pylab). Сюжет работает на Linux-Gnome, ваш пробег может отличаться. По умолчанию NUM_FRUITS равен 2 для поддержки графиков. Просто закомментируйте все вызовы pylab для удаления графиков и сможете изменить NUM_FRUITS на что угодно.

Хорошо справляется с оценкой текущего значения fxn, представленного UnknownQuantities X Prices = TotalPrice. В 2D (2 фрукта) это линия, в 3D (3 фрукта) это будет плоскость. Кажется, слишком мало данных для фильтра частиц, чтобы надежно отточить правильные количества. Нужно немного больше умов поверх фильтра частиц, чтобы действительно собрать историческую информацию. Вы можете попробовать преобразовать фильтр частиц в 2-й или 3-й порядок.

Обновление 2:

Я много играл с моим кодом, очень много. Я перепробовал кучу вещей и теперь представляю финальную программу, которую я буду делать (начиная с этой идеи).

Изменения:

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

Графики показывают истинные величины в виде зеленого квадрата и текущее предположение в виде красного квадрата. В настоящее время считается, что частицы показаны в виде синих точек (в зависимости от того, насколько мы им верим). Это позволяет легко увидеть, насколько хорошо работает алгоритм. (Графики также проверены и работают на Win 7 64-bit).

Добавлены параметры для выключения / изменения количества и цены. Конечно, оба «выкл» не интересно.

Это чертовски хорошая работа, но, как было отмечено, это действительно сложная проблема, поэтому получить точный ответ сложно. Отключение CHANGE_QUANTITIES приводит к простейшему случаю. Вы можете оценить сложность проблемы, запустив 2 плода с выключенным CHANGE_QUANTITIES. Посмотрите, как быстро он оттачивает правильный ответ, а затем посмотрите, насколько труднее вы увеличиваете количество фруктов.

Вы также можете получить представление о сложности, оставив CHANGE_QUANTITIES включенным, но изменив MAX_QUANTITY_CHANGE с очень маленьких значений (.001) на «большие» значения (.05).

Одна из ситуаций, в которой он борется, это если размер (одно количество фруктов) приближается к нулю. Потому что он использует среднее число частиц, чтобы догадаться, что он всегда будет отклоняться от жесткой границы, как ноль.

В общем, это хороший учебник по фильтру частиц.


from __future__ import division
import random
import numpy
import scipy.stats
import pylab

# Assume Guesser knows prices and total
# Guesser must determine the quantities

# All of pylab is just for graphing, comment out if undesired
#   Graphing only graphs first 2 FRUITS (first 2 dimensions)

NUM_FRUITS = 3
MAX_QUANTITY_CHANGE = .01 # Maximum percentage change that total quantity of fruit can change per iteration
MAX_QUANTITY = 100 # Bound for the sake of instantiating variables
MIN_QUANTITY_TOTAL = 10 # Prevent degenerate conditions where quantities all hit 0
MAX_FRUIT_PRICE = 1000 # Bound for the sake of instantiating variables
NUM_PARTICLES = 5000
NEW_PARTICLES = 500 # Num new particles to introduce each iteration after guessing
NUM_ITERATIONS = 20 # Max iterations to run
CHANGE_QUANTITIES = True
CHANGE_PRICES = True

'''
  Change individual fruit quantities for a random amount of time
  Never exceed changing fruit quantity by more than MAX_QUANTITY_CHANGE
'''
def updateQuantities(quantities):
  old_total = max(sum(quantities), MIN_QUANTITY_TOTAL)
  new_total = old_total
  max_change = int(old_total * MAX_QUANTITY_CHANGE)

  while random.random() > .005: # Stop Randomly    
    change_index = random.randint(0, len(quantities)-1)
    change_val = random.randint(-1*max_change,max_change)

    if quantities[change_index] + change_val >= 0: # Prevent negative quantities
      quantities[change_index] += change_val
      new_total += change_val

      if abs((new_total / old_total) - 1) > MAX_QUANTITY_CHANGE:
        quantities[change_index] -= change_val # Reverse the change

def totalPrice(prices, quantities):
  return sum(prices*quantities)

def sampleParticleSet(particles, fruit_prices, current_total, num_to_sample):
  # Assign weight to each particle using observation (observation is current_total)
  # Weight is the probability of that particle (guess) given the current observation
  # Determined by looking up the distance from the hyperplane (line, plane, hyperplane) in a
  #   probability density fxn for a normal distribution centered at 0 
  variance = 2
  distances_to_current_hyperplane = [abs(numpy.dot(particle, fruit_prices)-current_total)/numpy.linalg.norm(fruit_prices) for particle in particles]
  weights = numpy.array([scipy.stats.norm.pdf(distances_to_current_hyperplane[p], 0, variance) for p in range(0,NUM_PARTICLES)])

  weight_sum = sum(weights) # No need to normalize, as relative weights are fine, so just sample un-normalized

  # Create new particle set weighted by weights
  belief_particles = []
  belief_weights = []
  for p in range(0, num_to_sample):
    sample = random.uniform(0, weight_sum)
    # sum across weights until we exceed our sample, the weight we just summed is the index of the particle we'll use
    p_sum = 0
    p_i = -1
    while p_sum < sample:
      p_i += 1
      p_sum += weights[p_i]
    belief_particles.append(particles[p_i])
    belief_weights.append(weights[p_i])

  return belief_particles, numpy.array(belief_weights)

'''
  Generates new particles around the equation of the current prices and total (better particle generation than uniformly random)
'''
def generateNewParticles(current_total, fruit_prices, num_to_generate):
  new_particles = []
  max_values = [int(current_total/fruit_prices[n]) for n in range(0,NUM_FRUITS)]
  for p in range(0, num_to_generate):
    new_particle = numpy.array([random.uniform(1,max_values[n]) for n in range(0,NUM_FRUITS)])
    new_particle[-1] = (current_total - sum([new_particle[i]*fruit_prices[i] for i in range(0, NUM_FRUITS-1)])) / fruit_prices[-1]
    new_particles.append(new_particle)
  return new_particles


# Initialize our data structures:
# Represents users first round of quantity selection
fruit_prices = numpy.array([random.randint(1,MAX_FRUIT_PRICE) for n in range(0,NUM_FRUITS)])
fruit_quantities = numpy.array([random.randint(1,MAX_QUANTITY) for n in range(0,NUM_FRUITS)])
current_total = totalPrice(fruit_prices, fruit_quantities)
success = False

particles = generateNewParticles(current_total, fruit_prices, NUM_PARTICLES) #[numpy.array([random.randint(1,MAX_QUANTITY) for n in range(0,NUM_FRUITS)]) for p in range(0,NUM_PARTICLES)]
guess = numpy.average(particles, axis=0)
guess = numpy.array([int(round(guess[n])) for n in range(0,NUM_FRUITS)])

print "Truth:", str(fruit_quantities)
print "Guess:", str(guess)

pylab.ion()
pylab.draw()
pylab.scatter([p[0] for p in particles], [p[1] for p in particles])
pylab.scatter([fruit_quantities[0]], [fruit_quantities[1]], s=150, c='g', marker='s')
pylab.scatter([guess[0]], [guess[1]], s=150, c='r', marker='s')
pylab.xlim(0, MAX_QUANTITY)
pylab.ylim(0, MAX_QUANTITY)
pylab.draw()

if not (guess == fruit_quantities).all():
  for i in range(0,NUM_ITERATIONS):
    print "------------------------", i

    if CHANGE_PRICES:
      fruit_prices = numpy.array([random.randint(1,MAX_FRUIT_PRICE) for n in range(0,NUM_FRUITS)])

    if CHANGE_QUANTITIES:
      updateQuantities(fruit_quantities)
      map(updateQuantities, particles) # Particle Filter Prediction

    print "Truth:", str(fruit_quantities)
    current_total = totalPrice(fruit_prices, fruit_quantities)

    # Guesser's Turn - Particle Filter:
    # Prediction done above if CHANGE_QUANTITIES is True

    # Update
    belief_particles, belief_weights = sampleParticleSet(particles, fruit_prices, current_total, NUM_PARTICLES-NEW_PARTICLES)
    new_particles = generateNewParticles(current_total, fruit_prices, NEW_PARTICLES)

    # Make a guess:
    guess = numpy.average(belief_particles, axis=0, weights=belief_weights) # Could optimize here by removing outliers or try using median
    guess = numpy.array([int(round(guess[n])) for n in range(0,NUM_FRUITS)]) # convert to integers
    print "Guess:", str(guess)

    pylab.cla()
    #pylab.scatter([p[0] for p in new_particles], [p[1] for p in new_particles], c='y') # Plot new particles
    pylab.scatter([p[0] for p in belief_particles], [p[1] for p in belief_particles], s=belief_weights*50) # Plot current particles
    pylab.scatter([fruit_quantities[0]], [fruit_quantities[1]], s=150, c='g', marker='s') # Plot truth
    pylab.scatter([guess[0]], [guess[1]], s=150, c='r', marker='s') # Plot current guess
    pylab.xlim(0, MAX_QUANTITY)
    pylab.ylim(0, MAX_QUANTITY)
    pylab.draw()

    if (guess == fruit_quantities).all():
      success = True
      break

    # Attach new particles to existing particles for next run:
    belief_particles.extend(new_particles)
    particles = belief_particles
else:
  success = True

if success:
  print "Correct Quantities guessed"
else:
  print "Unable to get correct answer within", NUM_ITERATIONS, "iterations"

pylab.ioff()
pylab.show()
1 голос
/ 13 октября 2011

Для ваших начальных правил:

Со школьных лет я бы сказал, что если мы сделаем абстракцию 5% -ых изменений, у нас будет ежедневное уравнение с тремя неизвестными значениями (извините, я не знаю математический словарь на английском языке), которые одинаковы значения, как в предыдущий день. На третий день у вас есть три уравнения, три неизвестных значения, и решение должно быть прямым.

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

Для ваших адаптированных правил:

Слишком много неизвестных - и меняющихся - значений в этом случае, поэтому я не знаю прямого решения. Я бы поверил Лиору в этом; его подход выглядит хорошо! (Если у вас ограниченный диапазон цен и количества.)

...