2016-01-09 2 views
0

Je travaille avec des générateurs en Python, et je reçois un comportement étrange. Je ne suis pas entièrement comment formuler la question ...Odd Python zip() comportement

Mon code effectue une recherche de motif sur une fonction d'objectif. Le problème que je vois apparaît quand je zip les résultats de mon générateur patternSearch avec un xrange pour obtenir seulement les 12 premiers résultats. Il semble que le composant xmin du tuple retourné par mon générateur soit répété sur toute la longueur du zip. Ce qui est particulièrement bizarre, le composant ymin du même tuple n'est pas répété. Lorsque j'initialise un objet générateur ps et appelez ps.next() à plusieurs reprises, les résultats sont corrects.

Quel pourrait être le problème? Merci!

code

#!/usr/bin/env python2.7 

def obj(x): 
    x1,x2 = x 
    return 100*(x2 - x1**2)**2 + (1 - x1)**2 

# fobj: objective function of vector x 
# x0: initial point 
# h: initial step size 
# r: reduction parameter 
def patternSearch(fobj,x0,h,r): 
    n = len(x0) # get dimensionality 
    dims = range(0,n) 
    # initialize given x0 
    xmin = list(x0) 
    ymin = fobj(xmin) 

    yield (xmin,ymin) # send back the initial condition first 

    while True: 
     focus = True 
     for i in dims: 
     x = xmin # start from the last best point 
     x[i] += h 
     y = fobj(x) # eval 
     if y < ymin: 
      ymin = y 
      xmin = x 
      focus = False 
      continue 
     # else, y > ymin 
     x[i] -= 2*h # go in the opposite direction 
     y = fobj(x) # eval 
     if y < ymin: 
      ymin = y 
      xmin = x 
      focus = False 
      continue 
     # else, no update to this dim 
     if focus: 
     h *= r 
     yield (xmin,ymin) 

def main(): 
    x0 = (3,5) 
    imax = 12 
    print 'Initial condition: ', x0 
    print 'Stop condition: i == ', imax 
    print 'Iteration |  x1  |  x2  |  y  ' 
    for (x,y), i in zip(patternSearch(obj,x0,h=0.5,r=0.5), xrange(imax)): 
     print "{:>9} | {:<10} | {:<10} | {:<11}".format(i,x[0],x[1],y) 

    print 'Generator output test:' 
    g = patternSearch(obj,x0,0.5,0.5) 
    for i in xrange(imax): 
     g.next() 

Sortie

Initial condition: (3, 5) 
Stop condition: i == 12 
Iteration |  x1  |  x2  |  y  
     0 | 2.0  | 4.03125 | 1604  
     1 | 2.0  | 4.03125 | 58.5  
     2 | 2.0  | 4.03125 | 58.5  
     3 | 2.0  | 4.03125 | 1.953125 
     4 | 2.0  | 4.03125 | 1.953125 
     5 | 2.0  | 4.03125 | 1.2900390625 
     6 | 2.0  | 4.03125 | 1.2900390625 
     7 | 2.0  | 4.03125 | 1.13043212891 
     8 | 2.0  | 4.03125 | 1.13043212891 
     9 | 2.0  | 4.03125 | 1.06357192993 
     10 | 2.0  | 4.03125 | 1.06357192993 
     11 | 2.0  | 4.03125 | 1.03150010109 
Generator output test: 
([3, 5], 1604) 
([2.5, 5.5], 58.5) 
([2.0, 5.0], 58.5) 
([2.25, 4.75], 1.953125) 
([2.0, 4.5], 1.953125) 
([2.125, 4.375], 1.2900390625) 
([2.0, 4.25], 1.2900390625) 
([2.0625, 4.1875], 1.13043212890625) 
([2.0, 4.125], 1.13043212890625) 
([2.03125, 4.09375], 1.0635719299316406) 
([2.0, 4.0625], 1.0635719299316406) 
([2.015625, 4.046875], 1.0315001010894775) 
+0

"*' zip' les résultats de mon 'générateur de patternSearch' avec un' xrange' *" - pas d'amour pour' enumerate'? –

+0

Je pensais que c'était un moyen plus facile de se terminer que 'si i> imax: break' – abatea

Répondre

1

Vous réutilisez la liste xmax et de modifier leurs éléments, mais il est toujours la même liste, la liste zippé se compose de 12 fois la même liste. Le générateur semble fonctionner, car la liste est imprimée pour chaque étape.

Remplacer la ligne

x = xmin 

avec

x = list(xmin) 
+0

Sauf que le générateur fonctionne bien seul. Regardez la sortie. – abatea

+0

@abatea: réponse étendue – Daniel

+0

Très bien, merci pour le pointeur! J'ai changé ma ligne de rendement en 'yield (list (xmin), ymin)', et cela a résolu le problème. Donc avant, chaque élément dans le zip pointait vers le même objet de liste. – abatea