Melih Kara Melih Kara - 23 days ago 6
Python Question

How to find which input value in a loop yielded the output min?

I am trying to solve a min value problem, I could obtain the min values from two loops but, what I really need is also the exact values that correspended to output min.

from __future__ import division
from numpy import*
b1=0.9917949
b2=0.01911
b3=0.000840
b4=0.10175
b5=0.000763
mu=1.66057*10**(-24) #gram
c=3.0*10**8

Mler=open("olasiM.txt","w+")
data=zeros(0,'float')
for A in range(1,25):
M2=zeros(0,'float')
print 'A=',A
for Z in range(1,A+1):
SEMF=mu*c**2*(b1*A+b2*A**(2./3.)-b3*Z+b4*A*((1./2.)-(Z/A))**2+(b5*Z**2)/(A**(1./3.)))
SEMF=array(SEMF)
M2=hstack((M2,SEMF))
minm2=min(M2)
data=hstack((data,minm2))
data=hstack((data,A))
datalist = data.tolist()

for i in range (len(datalist)):
Mler.write(str(datalist[i])+'\n')
Mler.close()


Here, what I want is to see the min value of the
SEMF
and, corresponding
A
,
Z
values, For example, it has to be
A=1
,
Z=1
and
SEMF= some#

I also don't know how to write these,
A
and
Z
values to the document

Answer

The big advantage of numpy over using python lists is vectorized operations. Unfortunately your code fails completely in using them. For example the whole inner loop that has Z as index can easily be vectorized. You instead are computing the single elements using python floats and then stacking them one by one in the numpy array M2.

So I'd refactor that part of the code by:

import numpy as np
# ...

Zs = np.arange(1, A+1, dtype=float)
SEMF = mu*c**2 * (b1*A + b2*A**(2./3.) - b3*Zs + b4*A*((1./2.) - (Zs/A))**2 + (b5*Zs**2)/(A**(1./3.))) 

Here the SEMF array should be exactly what you'd obtain as the final M2 array. Now you can find the minimum and stack that value into your data array:

min_val = SEMF.min()    
data = hstack((data,minm2))
data = hstack((data,A))

If you also what to keep track for which value of Z you got the minimum you can use the argmin method:

min_val, min_pos = SEMF.min(), SEMF.argmin()  
data = hstack((data,np.array([min_val, min_pos, A])))

The final code should look like:

from __future__ import division
import numpy as np

b1 = 0.9917949
b2 = 0.01911
b3 = 0.000840
b4 = 0.10175
b5 = 0.000763
mu = 1.66057*10**(-24) #gram
c = 3.0*10**8

data=zeros(0,'float')
for A in range(1,25):
    Zs = np.arange(1, A+1, dtype=float)
    SEMF = mu*c**2 * (b1*A + b2*A**(2./3.) - b3*Zs + b4*A*((1./2.) - (Zs/A))**2 + (b5*Zs**2)/(A**(1./3.)))  

    min_val, min_pos = SEMF.min(), SEMF.argmin()  
    data = hstack((data,np.array([min_val, min_pos, A])))

datalist = data.tolist()

with open("olasiM.txt","w+") as mler:
    for i in range (len(datalist)):
        mler.write(str(datalist[i])+'\n')

Note that numpy provides some functions to save/load array to/from files, like savetxt so I suggest that instead of manually saving the values there to use these functions.


Probably some numpy expert could vectorize also the operations for the As. Unfortunately my numpy knowledge isn't that advanced and I don't know how the handle the fact that we'd have a variable number of dimensions due to the range(1, A+1) thing...