探讨:分析python的几种最优化算法_Python

二分法


函数详见rres,此代码使该算法运行了两次:

def asdf(x):
   rres=8*x**3-2*x**2-7*x+3
   return rres

i=2
left=0
right=1
while i>0 :
   i = i-1
   ans = 0.1
   mid1 = (left + right + ans) / 2
   mid2 = (left + right - ans) / 2
   a=asdf(mid1)
   c=asdf(mid2)
   if a > c :
       right = mid1
   else :
       left = mid2
b=(left+right) / 2
print("左极限=%s,右极限=%s,极小值x=%s"%(left,right,b))
左极限=0.45,右极限=0.775,极小值x=0.6125

学习完该算法以后,逻辑框架基本上就有了,剩下需要明确的就是对应的python的语言。


于是我就开始了查找“如何定义函数”,“循环体”和“if条件语句”的格式,“数学符号”,以及print的使用。


def是python中指定义,一般用来定义函数,如果需要深度学习搭建网络可用来定义网络。值得注意的一点是:


return必须要加在函数后面另起一行。


如果没有加的话,那个函数公式就是一个花瓶,就像一个结果输不出去。


问题:为什么要加return?


return的意思是输出这个def里面任意一个变量值作为结果显示。

一般情况而言,是输出函数的关系式的命名,这样当你调用这个函数的时候,变量对应的函数值才能显示出来,否则只运行没有结果,不会有效果。



格点法——三点等分法


import numpy as np
def qwer(x):
   third = np.exp(x) - 5*x
   return third

left = 1
right = 2
mid1 =float(left+right) / 2
mid2 = (left+mid1) / 2
mid3 = (mid1+right) /2
a = qwer(mid1)
b = qwer(mid2)
c = qwer(mid3)
i = 5
while i > 0:
   i=i-1
   if a > b:
       if c > b :
           #b
           right = mid1
           mid1 = mid2
           a=b
           mid2 = (left + mid1) / 2
           mid3 = (mid1 + right) / 2
           b = qwer(mid2)
           c = qwer(mid3)
       else:#b>c
           #c
           left = mid1
           mid1 = mid3
           a = c
           mid2 = (left + mid1) / 2
           mid3 = (mid1 + right) / 2
           b = qwer(mid2)
           c = qwer(mid3)
   else:#b>a
           if a > c:
               #C
               left = mid1
               mid1 = mid3
               a = c
               mid2 = (left + mid1) / 2
               mid3 = (mid1 + right) / 2
               b = qwer(mid2)
               c = qwer(mid3)
           else:#b>a&c>a
               # a
               left = mid2
               right = mid3
               mid2 = (left + mid1) / 2
               mid3 = (mid1 + right) / 2
               b = qwer(mid2)
               c = qwer(mid3)

print("最小值=%s"%mid1)
print("函数值=%s"%a)
最小值=1.609375
函数值=-3.047189552275773

关于python中数据变量。


第一遍运行结果出现很明显不对,于是我采用了debug。


结果发现,mid1处一直为1而不是1.5,于是就开始了解数据变量。


起初我猜测python默认所有变量为整型,但是根据二分法的结果我意识到此猜测不对,所以要改整个file的变量格式没有必要。


所以我就在mid1式子前面加了一个float,结果就显示为1.5了。


但是如果我将整个式子用()括起来,前面加float,结果还是1。


不过我知道了python的数据格式是根据输入量决定的,也就是说你的输入量如果是整型,那么与其直接相关的计算输出结果一定是整型,而且还是不采用进位的整型。


在我没有采用+float/+.0这两种方法之前,mid1~3全部是整型。


left = 1.0
right = 2.0
mid1 =(left+right) / 2

或者不再mid1前面加float,直接将输入量后面点个点就行。



Fibonacci法


def fibonacci(n):
   i=0
   a = 0
   b = 1
   for i in range(n):
       i=i+1
       c = a+b
       a = b
       b = c
   return c
def bn(x):
   ert = x**2 - 6*x + 2
   return ert
z = 2
p = 0
left = 0.00000
right = 10.00000
L1 = right - left
while z < 100:
   m = fibonacci(z)
   l = L1/m
   k = 1.000/m
   if k < 0.03:
       print("n=%s,Fn=%s"%(z,m))
       L2 = l*fibonacci(z-1)
       t = left + L2
       r = right -L2
       while p < 3:
           p = p + 1
           l3 = t - r
           e= bn(t)
           o = bn(r)
           if e>o :
               right = t
               t = r
               r = left + l3
           else:#o>e
               left = r
               r = t
               t = right - l3
       break
   else:
       z = z + 1

okk=(left+right)/2
okky=bn(okk)
print(left)
print(right)
print("极小值x=",okk)
print("极小值y=",okky)

不要问我掌握了什么,要问我现在写完这个代码后有多么的爱python的精度表示。
fibonacci函数定义,每次debug后我的手都是抖的。



黄金分割法


def gold(x):
   gg= x**2 - 6*x + 9
   return gg

left = 1
right = 7
ans = 0.4
a = left + 0.618 * (right - left)
b = left + 0.382*(right - left)
gga = gold(a)
ggb = gold(b)
i = 0
while i < 7:
   print("i=%s" % i)
   print("left=%s,right=%s" % (left, right))
   print("x左=%s,x右=%s" % (a, b))
   print("y左=%s,y右=%s" % (ggb, gga))
   c = right - left
   if c > 0.4:
       i = i + 1
       if gga > ggb:
           right = a
           a = b
           b = left + 0.382*(right - left)
           gga = ggb
           ggb = gold(b)
       else:#gga<ggb
           left = b
           b = a
           a = left + 0.618 * (right - left)
           ggb = gga
           gga = gold(a)
   else:
       break

前四个除了费波纳茨,都很简单。


间接法——二次插值法


def yy(x):
   y=x**4-4*x**3-6*x**2-16*x+4
   return y

def xing(xm1,xm2,xm3,fm1,fm2,fm3):
   yxxx=0.5000*((xm2**2-xm3**2)*fm1+(xm3**2-xm1**2)*fm2+(xm1**2-xm2**2)*fm3)/((xm2-xm3)*fm1+(xm3-xm1)*fm2+(xm1-xm2)*fm3)
   return yxxx

x1 = -1.0000
f1 = yy(x1)
x3 = 6
f3 = yy(x3)
x2 = 0.50000*(x1+x3)
f2 = yy(x2)
xp = xing(x1,x2,x3,f1,f2,f3)
fp = yy(xp)
a = abs(xp-x2)
while abs(xp-x2) > 0.05000:
   a = abs(xp - x2)
   if xp > x2:
       if fp > f2:
           x3=xp
           f3=fp
           xp = xing(x1, x2, x3, f1, f2, f3)
           fp = yy(xp)
           print("ans=%s" % a)
           print("left=%s,right=%s" % (x1, x3))
           print("x*=%s,fp*=%s" % (xp, fp))
           print("x2=%s,f2=%s" % (x2, f2))
           print("******************")
       else:#f2>fp
           x1 = x2
           f1 = f2
           x2 = xp
           f2 = fp
           xp = xing(x1, x2, x3, f1, f2, f3)
           fp = yy(xp)
           print("ans=%s" % a)
           print("left=%s,right=%s" % (x1, x3))
           print("x*=%s,fp*=%s" % (xp, fp))
           print("x2=%s,f2=%s" % (x2, f2))
           print("******************")
   else:#xp<x2
       if fp > f2:
           x1 = xp
           f1 = fp
           xp = xing(x1, x2, x3, f1, f2, f3)
           fp = yy(xp)
           print("ans=%s" % a)
           print("left=%s,right=%s" % (x1, x3))
           print("x*=%s,fp*=%s" % (xp, fp))
           print("x2=%s,f2=%s" % (x2, f2))
           print("******************")
       else:
           x3 = x2
           f3 = f2
           x2 = xp
           f2 = fp
           xp = xing(x1, x2, x3, f1, f2, f3)
           fp = yy(xp)
           print("ans=%s" % a)
           print("left=%s,right=%s" % (x1, x3))
           print("x*=%s,fp*=%s" % (xp, fp))
           print("x2=%s,f2=%s" % (x2, f2))
           print("******************")

这个公式看起来很麻烦,便写的时候更要谨慎。


我上回把那个2搁在了分号下面,结果很大,所以还是换算成0.5更好。


虽然代码很长,但是主要是因为print太多。

本打算在开头print,最后结果会漏掉最后一部分。



探讨:分析python的几种最优化算法_Python

间接法——牛顿法


def fd(x):
   y = 4*x**3-12*x**2-12*x-16
   return y
def fdd(x):
   ys = 12*x**2-24*x-12
   return ys

i = 1
x0 = 3.00000
ans = 0.001
while i < 7:
   fd0 = fd(x0)
   fdd0 = fdd(x0)
   if abs(fd0) > ans:
       x1 = x0 - (fd0/fdd0)
       x0 = x1
       print("次数:%s,所得的值x:%s"%(i,x1))
       i = i + 1
   else:#fd0<0.001
       print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
       print("Bingo!顺利通关!祝您开学愉快!")
       print("Boss  X=%s"%x0)
       break

一开始while里面<写成了>,导致run不出来。继而,debug也没法用。在网上一查才知道  “没联网”+“没选断点”。


最后想尝试将else里面的内容输出来,结果发现run以后被刷屏了。


于是改成i<7以后还是不行,于是想着加一个break跳出循环,结果成效了。


然后刚刚由debug了一下,才知道原来是i+1在if里面,因为没有办法+1,所以i=6一直存在,就不断循环。


因为加break也好,i+1也好,都可以。