Comment aborder un jeu de devinette de nombre (avec une torsion) algorithme?

j'apprends la programmation (Python et algorithmes) et j'essayais de travailler sur un projet que je trouve intéressant. J'ai créé quelques scripts Python de base, mais je ne suis pas sûr de savoir comment aborder une solution à un jeu que j'essaie de construire.

Voici comment le jeu fonctionnera:

les utilisateurs recevront des articles avec une valeur. Par exemple,

Apple = 1
Pears = 2
Oranges  = 3

ils auront alors la chance de choisir n'importe quel combo d'eux qu'ils aiment (c'est à dire 100 pommes, 20 poires, et un orange). La seule sortie que l'ordinateur obtient est la valeur totale (dans cet exemple, c'est actuellement $143). L'ordinateur va essayer de deviner ce qu'ils ont. Qui, évidemment, il ne sera pas en mesure d'obtenir correctement le premier tour.

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

le tour suivant l'utilisateur peut modifier leurs nombres mais pas plus de 5% de la quantité totale (ou un autre pour cent que nous pouvons choisir. J'utiliserai 5% par exemple.). Les prix des fruits peuvent changer(à (pour simplifier, Je ne change pas les prix des fruits dans cet exemple). En utilisant l'exemple ci-dessus, le jour 2 du jeu, l'utilisateur retourne une valeur de 152 $et $164 sur les 3 jours. Voici un exemple:

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

*(j'espère que les tables apparaissent correctement, j'ai dû les espacer manuellement, donc j'espère que ce n'est pas juste le faire sur mon écran, si ça ne marche pas, faites-le moi savoir et j'essaierai de télécharger une capture d'écran.)

je suis essayer de voir si je peux comprendre ce que les quantités sont au fil du temps (en supposant que l'utilisateur aura la patience de continuer à entrer des nombres). Je sais maintenant que ma seule restriction est la valeur totale ne peut pas être plus de 5% donc je ne peux pas être à moins de 5% de la précision en ce moment donc l'utilisateur va entrer pour toujours.

Ce que j'ai fait jusqu'à présent

voici ma solution jusqu'à présent (pas beaucoup). En gros, je prends toutes les valeurs et de comprendre tous les combinaisons possibles d'eux (je suis fait cette partie). Puis je prends tous les combos possibles et les mets dans une base de données comme un dictionnaire (ainsi par exemple pour $143, Il pourrait y avoir une entrée de dictionnaire {pomme:143, poires:0, Oranges :0}..jusqu'à {pomme:0, poires:1, Oranges :47}. Je fais cela chaque fois que j'obtiens un nouveau numéro donc j'ai une liste de toutes les possibilités.

voilà où je suis coincé. En utilisant les règles ci-dessus, comment puis-je trouver la meilleure solution possible? Je pense que je vais avoir besoin d'un fonction de fitness qui compare automatiquement les données de deux jours et élimine toutes les possibilités qui ont une variance de plus de 5% des données des jours précédents.

Questions:

donc ma question avec l'utilisateur changeant le total et moi ayant une liste de toutes les probabilités, Comment dois-je aborder cela? Que dois-je apprendre? Est-il des algorithmes, ou des théories que je peux utiliser, qui sont applicables? Ou, pour m'aider à comprendre mon erreur, pouvez-vous suggérer quelles règles je peux ajouter pour rendre cet objectif réalisable (si ce n'est pas dans son état actuel. Je pensais ajouter plus de fruits et dire qu'ils doivent en cueillir au moins 3, etc..)? En outre, je n'ai qu'une vague compréhension des algorithmes génétiques, mais j'ai pensé que je pourrais les utiliser ici, s'il y a quelque chose que je peux utiliser?

je suis très impatient d'apprendre de sorte que tout conseil ou conseils seraient grandement appréciés (s'il vous plaît ne me dites pas que ce jeu est impossible).

mise à JOUR: Obtenir de la rétroaction que c'est dur à résoudre. Donc j'ai pensé que je voudrais ajouter une autre condition au jeu qui ne va pas interférer avec ce que le joueur est en train de faire (le jeu reste le même pour eux) mais tous les jours la valeur des fruits changer le prix (au hasard). Peut-être plus facile à résoudre? Parce que dans un mouvement de 5% et certains changements de la valeur du fruit, seulement quelques combinaisons sont probables dans le temps.

jour 1, tout est possible et obtenir une portée assez proche est presque impossible, mais comme les prix des fruits changent et que l'utilisateur ne peut choisir un changement de 5%, alors ne devrait pas (au fil du temps) la gamme est étroite et étroite. Dans l'exemple ci-dessus, si les prix sont assez volatiles je pense que je pourrais forcer une solution qui m'a donné une gamme à deviner, mais j'essaye de comprendre s'il y a une solution plus élégante ou d'autres solutions pour continuer à réduire cette gamme avec le temps.

UPDATE2: après avoir lu et demandé autour, je crois que c'est un secret Markov / Viterbi problème qui suit les changements dans les prix des fruits ainsi que la somme totale (en pondérant le dernier point de données le plus lourd). Je ne sais pas comment appliquer la relation. Je pense que c'est le cas et pourrait être faux, mais au moins je commence à soupçonner qu'il s'agit d'un problème d'apprentissage automatique.

mise à jour 3: j'ai créé un cas de test (avec des nombres plus petits) et un générateur pour aider à automatiser les données générées par l'utilisateur et j'essaie de créer un graphique à partir de celui-ci pour voir ce qui est plus probable.

voici le code, ainsi que les valeurs totales et les commentaires sur ce que les utilisateurs sont réellement des quantités de fruits.

#!/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
50
demandé sur Peter Mortensen 2011-10-08 09:20:52

5 réponses

nous allons combiner la théorie des graphes et la probabilité:

le 1er jour, construire un ensemble de toutes les solutions possibles. Permet de définir les solutions comme A1={a1(1), a1 (2),..., a1 (n)}.

le deuxième jour, vous pouvez à nouveau construire les solutions ensemble A2.

maintenant, pour chaque élément de A2, vous devrez vérifier s'il peut être atteint à partir de chaque élément de A1 (compte tenu de la tolérance de x%). Dans ce cas, connectez A2(n) À A1(m). Si il ne peut pas être atteint à partir de n'importe quel nœud A1(m) - vous pouvez supprimer ce nœud.

Fondamentalement, nous construisons un graphe acyclique dirigé connecté.

toutes les trajectoires du graphique sont également probables. Vous pouvez trouver une solution exacte seulement quand il y a un seul bord de Am à Am+1 (d'un noeud dans Am à un noeud dans Am+1).

bien sûr, certains noeuds apparaissent dans plus de chemins que d'autres noeuds. La probabilité pour chaque noeud peut être déduite directement basée sur le nombre de chemins qui contient ce nœud.

en assignant un poids à chaque noeud, qui est égal au nombre de chemins qui mènent à ce noeud, il n'est pas nécessaire de garder toute l'histoire, mais seulement la veille.

Aussi, jetez un oeil à non-négative-valeurs linéaire diphantine équations - Une question que j'ai posée tout à l'heure. La réponse acceptée est un excellent moyen d'énumérer tous les combos dans chaque étape.

11
répondu Lior Kogan 2017-05-23 12:07:16

Ce problème est impossible à résoudre.

disons que vous savez exactement pour quel ratio le nombre d'articles a été augmenté, pas seulement ce qui est le ratio maximum pour cela.

un utilisateur A N fruits et vous avez D jours de deviner.

dans chaque jour vous obtenez N nouvelles variables et puis vous avez dans Total D*N variables.

Pour chaque jour, vous pouvez générer que deux équations. Une équation est la somme de n_item*le prix et les autres est basé sur un taux. Au total, vous avez au maximum 2 * d équations si elles sont toutes indépendantes.

2*D < N*D pour tous N >2

7
répondu Luka Rahne 2018-04-29 17:31:38

avertissement: j'ai changé ma réponse de façon dramatique après avoir temporairement supprimé ma réponse et relu la question attentivement car j'ai mal lu certaines parties critiques de la question. Tout en faisant référence à des sujets et des algorithmes similaires, la réponse a été grandement améliorée après que j'ai essayé de résoudre certains du problème dans C# moi-même.

Hollywood version

  • le problème est une contrainte dynamique problème de satisfaction (DCSP), une variation de problèmes de satisfaction contrainte (CSP.)
  • utiliser Monte Carlo pour trouver des solutions possibles pour un jour donné si les valeurs et les plages de quantité ne sont pas infimes. Sinon, utilisez la force brute pour trouver toutes les solutions possibles.
  • Utiliser Contrainte d'Enregistrement (liées à la DCSP), appliqué en cascade aux jours précédents pour restreindre l' ensemble de solutions possibles.
  • croiser les doigts, le but et les tirer (Devinez), fondée sur des probabilités.
  • (optionnel) Bruce Willis gagne.

version originale

tout d'abord, je voudrais dire ce que je vois deux problèmes principaux ici:

  1. le simple nombre de solutions possibles. Sachant seulement le nombre de les éléments et la valeur totale, disons 3 et 143 par exemple, donnera beaucoup des solutions possibles. De plus, il n'est pas facile d'avoir un algorithme qui choisit une solution valide sans nécessairement essayer des solutions invalides (total non égal à 143.)

  2. lorsque des solutions possibles sont trouvées pour un jour donné D i , il faut trouver un moyen d'éliminer les solutions potentielles avec les informations supplémentaires fournies par { D i+1 .. D i+n }.

posons quelques bases pour les exemples à venir:

  • permet de garder les mêmes valeurs d'article, l'ensemble du jeu. Il peut soit être aléatoire ou choisi par l'utilisateur.
  • les valeurs possibles des articles sont liées à la gamme très limitée de [1-10], où deux articles ne peuvent pas avoir la même valeur.
  • aucun article ne peut avoir une quantité supérieure à 100. Cela signifie que: [0-100].

afin de résoudre ce plus facilement j'ai pris la liberté de changer une contrainte , ce qui rend l'algorithme converge plus rapide:

  • la règle de la "quantité totale" est annulée par cette règle: vous pouvez ajouter ou supprimer n'importe quel nombre d'articles dans l'intervalle [1-10], total, en une journée. Cependant, vous ne pouvez pas ajouter ou supprimer le même nombre d'éléments, au total, plus de à deux reprises. Cela donne aussi au jeu un cycle de vie maximum de 20 jours.

cette règle nous permet d'écarter des solutions plus facilement. Et, avec des plages non-minuscules, rend " backtracking algorithms toujours inutile, tout comme votre problème original et les règles.

À mon humble avis, cette règle n'est pas la essence du jeu, mais seulement un facilitateur, permettant à l'ordinateur de résoudre le problème.

Problème 1: trouver des solutions potentielles

pour commencer, problème 1. peut être résolu en utilisant un algorithme de Monte Carlo pour trouver un ensemble de solutions potentielles. La technique est simple: générer des nombres aléatoires pour des valeurs et des quantités d'items (dans leur plage respective acceptée). Répétez le processus pour le nombre requis de points. Vérifier si la solution est acceptable. Cela signifie que vérifier si les éléments ont des valeurs distinctes et le total est égal à notre total cible (disons, 143.)

bien que cette technique ait l'avantage d'être facile à mettre en œuvre, elle présente certains inconvénients:

  • la solution de l'utilisateur n'est pas garantie d'apparaître dans nos résultats.
  • Il y a beaucoup de "manque". Par exemple, il faut plus ou moins 3.000.000 tente de trouver 1.000 solutions potentielles compte tenu de nos contraintes.
  • cela prend beaucoup de temps: environ 4 à 5 secondes sur mon ordinateur portable paresseux.

comment contourner cet inconvénient? Bien...

  • Limiter la plage pour les plus petits, les valeurs et les 1519130920"
  • trouver un nombre adéquat de solutions potentielles de sorte qu'il ya une bonne chance de la solution de l'utilisateur apparaît dans votre ensemble de solutions.
  • utilisez l'heuristique pour trouver des solutions plus facilement (plus sur cela plus tard.)

notez que plus vous limitez les plages, moins l'algorithme de Monte Carlo sera utile, car il y aura peu de solutions valides pour les itérer toutes dans un délai raisonnable. Pour les contraintes { 3, [1-10], [0-100] } il y a environ 741.000.000 de solutions valables (non limitées à une valeur cible totale.) Monte Carlo y est utilisable. Pour { 3, [1-5], [0-10] }, il n'y en a qu'environ 80 000. Pas besoin D'utiliser Monte Carlo; brute force for boucles fera juste fin.

je crois que le "151920920 problème de" 1 est ce que l'on pourrait appeler un Constraint satisfaction problem (ou CSP.)

problème 2: restreindre l'ensemble des solutions possibles

étant donné que problème 1 est un CSP, je vais de l'avant et appeler problème 2 , et le problème en général, un CSP dynamique (ou DCSP.)

[DCSPs] sont utiles lorsque la formulation originale d'un problème est modifié d'une certaine façon, généralement parce que l'ensemble de les contraintes à considérer évoluent en raison de l'environnement. DCSPs sont considérés comme une séquence d'EFPC statiques, chacun une transformation de la précédente dans laquelle des variables et des contraintes peuvent être ajoutées (restriction) ou enlevé (relaxation).

une technique utilisée avec CSPs qui pourrait être utile à ce problème est appelé enregistrement de contrainte :

  • à chaque changement d'environnement (valeurs saisies par l'utilisateur pour D i+1 ), trouver des informations sur la nouvelle contrainte: quelles sont les quantités éventuellement" utilisées " pour la contrainte add-remove.
  • appliquer la contrainte à chaque jour précédent en cascade. Les effets d'ondulation pourraient réduire considérablement les solutions possibles.

pour que cela fonctionne, vous devez obtenir un nouvel ensemble de solutions possibles chaque jour; utilisez soit la force brute ou Monte Carlo. Ensuite, comparez les solutions de D i à d i-1 et conservez seulement les solutions qui peuvent réussir aux solutions des jours précédents sans violer les contraintes.

vous aurez probablement à garder une histoire de ce que les solutions conduisent à ce que d'autres solutions (probablement dans un graphique dirigé.) Contrainte l'enregistrement vous permet de se rappeler possible Ajouter-Supprimer des quantités et rejette des solutions basées sur cela.

Il y a beaucoup d'autres mesures qui pourraient être prises pour améliorer davantage votre solution. Voici quelques idées:

  • Enregistrement de contraintes pour le point-combinaisons de valeurs trouvées dans les jours précédents solutions. Rejeter d'autres solutions immédiatement (comme les valeurs de l'article ne doit pas changer.) Vous pourriez même trouver une solution plus petite ensembles pour chaque solution existante utilisant des contraintes spécifiques à la solution pour rejeter plus tôt les solutions invalides.
  • générez des solutions "mutantes", historique complet, chaque jour afin de "réparer" le cas où le d 1 ensemble de solution ne contient pas la solution de l'utilisateur. Vous pouvez utiliser un algorithme génétique pour trouver une population mutante basée sur une solution existante.)
  • utiliser l'heuristique pour trouver facilement des solutions (par exemple quand un solution est trouvée, essayer de trouver des variations de cette solution en remplaçant les quantités autour.)
  • utiliser des heuristiques comportementales afin de prédire certaines actions de l'utilisateur (par exemple, la même quantité pour chaque élément, les modèles extrêmes, etc.)
  • continuez à faire quelques calculs pendant que l'utilisateur entre de nouvelles quantités.

compte tenu de tout cela, essayer de comprendre un système de classement basé sur l'occurrence de solutions et heuristiques à déterminer une solution possible.

6
répondu Bryan Menard 2011-10-13 20:26:57

j'ai écrit un programme pour jouer au jeu. Bien sûr, j'ai dû automatiser le côté humain, mais je crois que j'ai fait tout cela de telle manière que je ne devrais pas invalider mon approche lorsque joué contre un vrai humain.

j'ai abordé cela d'une perspective d'apprentissage machine et traité le problème comme un modèle de markov caché où le prix total était l'observation. Ma solution est d'utiliser un filtre à particules. Cette solution est écrite en Python 2.7 en utilisant NumPy et SciPy.

j'ai énoncé toute hypothèse que j'ai faite soit explicitement dans les commentaires ou implicitement dans le code. J'ai aussi établi des contraintes supplémentaires pour obtenir du code à exécuter de façon automatisée. Il n'est pas particulièrement optimisé car j'ai essayé d'errer sur la compréhensibilité côté plutôt que la vitesse.

chaque itération produit les quantités réelles courantes et les conjectures. Je ne fais que transférer la sortie dans un fichier pour pouvoir l'examiner facilement. Une intéressante extension serait de tracer la sortie sur un graphique soit 2D (pour 2 fruits) ou 3D (pour 3 fruits). Ensuite, vous pourrez voir le filtre à particules dans la solution.

mise à jour:

a modifié le code pour y inclure des paramètres mis à jour après modification. Inclus les appels de pointage à l'aide de matplotlib (via pylab). Traquer fonctionne sur Linux-Gnome, votre kilométrage peut varier. NUM_FRUITS par défaut à 2 pour le support de pointage. Il suffit de commenter tous les appels de pylab à supprimer le pointage et être en mesure de changer NUM_FRUITS à n'importe quoi.

fait un bon travail en estimant le fxn actuel représenté par les quantités inconnues X Prix = Prix Total. En 2D (2 Fruits) c'est une ligne, en 3D (3 Fruits) ce serait un plan. Semble être trop peu de données pour le filtre à particules de manière fiable focaliser sur les quantités correctes. Besoin d'un peu plus de smarts sur le dessus du filtre à particules pour vraiment rassembler les informations historiques. Vous pouvez essayer de convertir le filtre à particules de 2e ou 3e ordre.

Maj 2:

j'ai beaucoup joué avec mon code. J'ai essayé un tas de choses et maintenant présenter le programme final que je vais faire (en commençant à brûler sur cette idée).

changements:

les particules utilisent maintenant des points flottants plutôt que des entiers. Vous ne savez pas si cela a eu un effet significatif, mais c'est une solution générale. L'arrondissement aux entiers est fait seulement quand on fait une supposition.

Le graphique

montre les quantités réelles comme carré vert et le courant deviner comme carré rouge. Actuellement estimé particules montré que les points bleus (de la taille de combien nous les croire). Cela le rend vraiment facile de voir comment l'algorithme fonctionne. (Traçage également testé et travaillant sur Win 7 64-bit).

ajout de paramètres pour désactiver/modifier la quantité et changer le prix. Bien sûr, les deux " off " n'est pas intéressant.

il fait un bon travail assez dang, mais, comme il a été noté, c'est un problème vraiment difficile, donc obtenir la réponse exacte est difficile. Désactiver CHANGE_QUANTITIES produit le cas le plus simple. Vous pouvez obtenir une appréciation de la difficulté du problème en exécutant avec 2 fruits avec CHANGE_QUANTITIES off. Voir la rapidité avec laquelle il s'adapte à la bonne réponse, puis voir comment il est plus difficile que vous augmentez le nombre de fruits.

vous pouvez également obtenir une perspective sur le difficulté à maintenir CHANGE_QUANTITIES sur, mais en ajustant le MAX_QUANTITY_CHANGE à partir de très petites valeurs (.001) à des valeurs "grandes" (.05).

une situation où il lutte est si sur la dimension (une quantité de fruit) se rapproche de zéro. Parce qu'il utilise une moyenne de particules pour deviner qu'il s'éloignera toujours d'une frontière dure comme zéro.

en général, cela fait un grand tutoriel sur le filtre à particules.


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()
3
répondu Kyle 2011-10-14 22:57:32

pour vos règles initiales:

de mes années scolaires, je dirais que si nous faisons une abstraction des 5% de changements, nous avons tous les jours une équation avec trois valeurs inconnues (désolé Je ne sais pas le vocabulaire mathématiques en anglais), qui sont les mêmes valeurs que la veille. Au jour 3, vous avez trois équations, trois valeurs inconnues, et la solution devrait être directe.

je suppose que le changement de 5% chaque jour peut être oublié si les valeurs des trois éléments sont suffisamment différentes, parce que, comme vous l'avez dit, Nous allons utiliser des approximations et arrondir les nombres.

pour vos règles adaptées:

trop de valeurs inconnues - et changeantes dans ce cas, il n'y a donc pas de solution directe que je connaisse. Je ferais confiance à Lior sur ce point; son approche semble très bien! (Si vous avez une gamme limitée de prix et de quantités.)

1
répondu Fouteier 2018-04-29 17:33:17