0

I wanna define a structure with python3.x. this structure is the initial population, but I don't know, why in this loop, random numbers are the same?

import numpy as np
from numpy.lib.shape_base import _dstack_dispatcher
from numpy.random import default_rng

Xmin=-30;Xmax=30;n=2;MaxIter=200;nP=50 
Fc=0.7
nC=2*round(Fc*nP/2)#;print(nC)
Fm=0.1
nM=round(Fm*nP)#;print(nM)
Pi_M=0.02

empty_ind={'X':[],'Cost':[],'rank':[],'CD':[]}
pop=np.tile(empty_ind,(nP,1))
for i in range(nP):
    pop[i,0]['X']=np.random.uniform(Xmin,Xmax,[1,n])
    def MOP5(a):
        #n=np.size(x)
        x=a[0,0]
        y=a[0,1]
        
        f1=0.5*(x**2+y**2)+np.sin(x**2+y**2)
        f2=(3*x-2*y+4)**2/8 + (x-y+1)**2/27 +15
        f3=1/(x**2+y**2+1)- 1.1*np.exp(-x**2-y**2)
        aa=[f1,f2,f3]
        z=np.reshape(aa,(3,1))
        return z

    pop[i,0]['Cost']=MOP5(pop[i,0]['X'])
print(pop)

and this is my result :

[{'X': array([[ 11.65978708, -17.46716958]]), 'Cost': array([[2.21468705e+02],
       [7.31520444e+02],
       [2.26217399e-03]]), 'rank': [], 'CD': []}]
 [{'X': array([[ 11.65978708, -17.46716958]]), 'Cost': array([[2.21468705e+02],
       [7.31520444e+02],
       [2.26217399e-03]]), 'rank': [], 'CD': []}]
 

please let me know, why the results are the same?

Hamed HSNY
  • 11
  • 2
  • I suspect that `np.tile` actually tiles the same dict object. So when you assign something to `pop[i,0]['X']`, it actually modifies all the dicts at the same time (because the dicts are the same). – j1-lee Dec 08 '21 at 20:16
  • You're right @j1-lee - `id(pop[2,0])`, `id(pop[12,0])`, `id(pop[49,0])`, etc. all return the same number. –  Dec 08 '21 at 20:18
  • The exact function (`tile` vs `list.__mul__`) is different, but the diagnosis and solution are exactly the same. Also, don't bother with numpy arrays when storing python objects. It gives you almost no advantage to do that. – Mad Physicist Dec 08 '21 at 20:30

1 Answers1

0

I suspect that np.tile actually tiles the same dict object (in this case empty_ind). So when you assign something to pop[i, 0]['X'], you modify the all the dicts at the same time (because those dict are indeed the same object).

Try something like:

pop = [{'X':[],'Cost':[],'rank':[],'CD':[]} for _ in range(nP)] # make a new object {...} at each for iteration

for i in range(nP):
    pop[i]['X']=np.random.uniform(Xmin,Xmax,[1,n])
    def MOP5(a):
        #n=np.size(x)
        x=a[0,0]
        y=a[0,1]
        
        f1=0.5*(x**2+y**2)+np.sin(x**2+y**2)
        f2=(3*x-2*y+4)**2/8 + (x-y+1)**2/27 +15
        f3=1/(x**2+y**2+1)- 1.1*np.exp(-x**2-y**2)
        aa=[f1,f2,f3]
        z=np.reshape(aa,(3,1))
        return z

    pop[i]['Cost']=MOP5(pop[i]['X'])
print(pop)

Here I chose to use list instead of np.array for pop; having a numpy array of dicts does not make much sense to me anyways.

j1-lee
  • 13,764
  • 3
  • 14
  • 26
  • Specifically, numpy arrays store a reference to a python object, so `np.tile(empty_ind,(nP,1))` works exactly the same as if you had a list and did `nP * [empty_ind]`. – Mad Physicist Dec 08 '21 at 20:29