# This is an adaptation of the numerical recipes routines 'amotry' and 'amoeba'

from Numeric import *
import sys
from header import *

TINY = 1.e-10
NMAX = 700

def swap(a,b):
    tmp=a
    a=b
    b=tmp
    

def get_sum(p, ps):
    ndim = shape(p)[1]
    mpts = shape(p)[0]
    for j in range(ndim):
        sum = 0.
        for i in range(mpts):
            sum += p[i][j]
            
        ps[j] = sum
        
    

def nrerror(error_text):
	print "run-time error...\n"
	print error_text, "\n"
	print "...now exiting to system...\n"
# 	sys.exit()
        Quit

        

def amotry(p, y, psum, func, ihi, fac):     # check index range
    ndim = size(y)-1
    ptry = zeros(ndim,Float)
    fac1 = (1.-fac)/ndim
    fac2 = fac1-fac
    for j in range(ndim):                   # use array methods
        ptry[j] = psum[j]*fac1-p[ihi][j]*fac2
        
    ytry = func(ptry)
    if(ytry<y[ihi]):
        y[ihi] = ytry;
        for j in range(ndim):               # use array methods
            psum[j] += ptry[j]-p[ihi][j]
            p[ihi][j] = ptry[j]
            
    
    del ptry
    return ytry
    

def amoeba(p, y, ftol, func, nfunk):        # check index ranges
    ndim = size(y)-1
    mpts = ndim + 1
    psum = zeros(ndim,Float)
    nfunk = 0
    get_sum(p, psum)
    const = 1
    while(const < 2):
        ilo = 0
        if(y[1]>y[2]): [ihi,inhi] = [1,2]
        else: [ihi,inhi] = [2,1]
        
        for i in range(mpts):
            if (y[i] <= y[ilo]): ilo=i
            
            if (y[i] > y[ihi]): [inhi,ihi] = [ihi,i]
            elif ((y[i]>y[inhi]) & (i != ihi)): inhi = i
        
        
        rtol = 2.*abs(y[ihi]-y[ilo])/(abs(y[ihi])+abs(y[ilo])+TINY)
        if (rtol < ftol): 
            swap(y[0],y[ilo])
            for i in range(ndim): swap(p[0][i],p[ilo][i])
            
            print "\n", nfunk, " function calls.\n"
            break
        
        if (nfunk >= NMAX): 
            print "\nNMAX exceeded\n"
            break
        
        nfunk += 2
        ytry=amotry(p,y,psum,func,ihi,-1.0)
        if (ytry <= y[ilo]):
            ytry=amotry(p,y,psum,func,ihi,2.0)
        elif (ytry >= y[inhi]):
            ysave=y[ihi]
            ytry=amotry(p,y,psum,func,ihi,0.5)
            if (ytry >= ysave):
                for i in range(mpts):
                    if (i != ilo):
                        for j in range(ndim):
                            p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j])
                            
                        y[i]=func(psum)
                    
                
                nfunk += ndim
                get_sum(p,psum)
            
        else: nfunk -= 1
    
    del psum
    return p[ihi]