In [10]:
from math import exp
from scipy import optimize
from scipy.optimize import minimize
from concurrent.futures import ThreadPoolExecutor
import matplotlib.pyplot as plt
import time
import numpy
import itertools

In [11]:
# f(x) = x / (1+x^2), x* = -1
def objfun1(x, xprev, lamb):
    return x / (1+x**2) + lamb * abs(x - xprev)**2
    
# f(x) = -x / e^x, x* = 1
def objfun2(x, xprev, lamb):
    return -x / exp(x) + lamb * abs(x - xprev)**2

# f(x) = (x-2)^4 + (x-2)^3 + (x-2)^2 + 1, x* = 2
def objfun3(x, xprev, lamb):
    return (x-2)**4 + (x-2)**3 + (x-2)**2 + 1 + lamb * abs(x - xprev)**2
    
# ff(x) = (x-1)^2 * (x-3)^2 * (x-5)^2 + 1, x1 = 1, x2 = 3 e x3 = 5
def objfun4(x, xprev, lamb):
    return (x-1)**2 * (x-3)**2 * (x-5)**2 + 1 + lamb * abs(xprev-x)**2

# f(x) = ((x-1)*(x+1)*(x-2)*(x+2))^2 - 2, x1 = -1, x2 = 1, x3 = -2, x4 = 2
def objfun5(x, xprev, lamb):
    return ((x-1)*(x+1)*(x-2)*(x+2))**2 - 2 + lamb * abs(x - xprev)**2

In [70]:
# x, x0, iterações, erro, tempo
XK, X0, IT, ERR, TIME = [], [], [], [], []
    
def minimalg_single(str_func, it, lambda_str, tolerance, optimum, low, high):
    #optimum = float(input("Optimum: "))
    #optimum = 2
    #tests = int(input("Number of tests: "))
    tests = 100
    #max_iter = int(input("Max iterations: "))
    max_iter = 300

    #low = float(input("x0 interval (lower): "))
    #high = float(input("x0 interval (upper): "))

    objfun = globals()[str_func]

    sum_iter = 0
    sum_time = 0
    sum_x = 0
    sum_y = 0

    for i in range(1, tests + 1):
        x0 = numpy.random.uniform(low, high)
        xprev = x0
        start_time = time.time()

        for k in range(1, max_iter + 1):
            lamb = eval(lambda_str[it])

            res = minimize(objfun, x0, args=(xprev, lamb), method='BFGS', tol=tolerance[it], options={'disp': False, 'maxiter': 100})
            error = abs(xprev-res.x[0])
            xprev = res.x[0]

            if (error <= tolerance[it]):
                break         

        end_time = time.time() - start_time     

        XK.append(xprev)
        X0.append(x0)
        IT.append(k)
        ERR.append(error)
        TIME.append(end_time)

        sum_iter = sum_iter + k
        sum_time = sum_time + end_time
        sum_x = sum_x + res.x[0]
        sum_y = sum_y + res.fun
        
    print('%d & %.5f & $%s$ & %.2f & %.10f & %.10f & %.10f \\\\ [1ex]' % (it+1, tolerance[it], lambda_str[it], sum_iter/tests, sum_time/tests, sum_x/tests, abs((sum_x/tests)-optimum)));

In [38]:
lambda_str = ['3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k']
tolerance = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10]

# f(x) = x / (1+x^2)
for it in range(0, 10):
    minimalg_single("objfun1", it, lambda_str, tolerance, -1, -1, 0.5)


1 & 0.10000 & $3+(-1)**k$ & 2.29 & 0.0009506679 & -0.5334452684 & 0.46655473157864590927 \\ [1ex]
2 & 0.01000 & $3+(-1)**k$ & 11.74 & 0.0044731832 & -0.8942241755 & 0.10577582452102307631 \\ [1ex]
3 & 0.00100 & $3+(-1)**k$ & 33.65 & 0.0139601088 & -0.9859991351 & 0.01400086485775875467 \\ [1ex]
4 & 0.00010 & $3+(-1)**k$ & 59.48 & 0.0270091867 & -0.9985340914 & 0.00146590855738426562 \\ [1ex]
5 & 0.00001 & $3+(-1)**k$ & 85.78 & 0.0407291198 & -0.9998544086 & 0.00014559136557190655 \\ [1ex]
6 & 0.00000 & $3+(-1)**k$ & 110.12 & 0.0538582683 & -0.9999852950 & 0.00001470499862710195 \\ [1ex]
7 & 0.00000 & $3+(-1)**k$ & 135.16 & 0.0693292761 & -0.9999986321 & 0.00000136785759341507 \\ [1ex]
8 & 0.00000 & $3+(-1)**k$ & 164.17 & 0.1171832800 & -0.9999999560 & 0.00000004398226505220 \\ [1ex]
9 & 0.00000 & $3+(-1)**k$ & 180.95 & 0.2139520478 & -1.0000000438 & 0.00000004383897622695 \\ [1ex]
10 & 0.00000 & $3+(-1)**k$ & 219.86 & 0.2869639492 & -1.0000000551 & 0.00000005511787470880 \\ [1ex]

In [68]:
plt.xlabel('Tolerância')
plt.ylabel('Erro')

er = [0.46655473157864590927, 0.10577582452102307631, 0.01400086485775875467, 0.00146590855738426562, 0.00014559136557190655, 0.00001470499862710195, 0.00000136785759341507, 0.00000004398226505220, 0.00000004383897622695, 0.00000005511787470880]
ite = [2.05, 12.21, 33.40, 57.64, 85.30, 110.36, 136.18, 164.72, 180.23, 217.51]
t = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10]

plt.gca().set_xscale('log')
x, y = zip(*sorted(zip(er, t)))
plt.plot(y, x, lw=1.5)
plt.show()



In [40]:
lambda_str = ['1+1/k', '1+1/k', '1+1/k', '1/k', '1/k', '1/k', '1', '1', '1', '2-1/k', '2-1/k', '2-1/k', '3+(-1)**k', '3+(-1)**k', '3+(-1)**k']
tolerance = [1e-3, 1e-4, 1e-5, 1e-3, 1e-4, 1e-5, 1e-3, 1e-4, 1e-5, 1e-3, 1e-4, 1e-5, 1e-3, 1e-4, 1e-5]

# f(x) = x / (1+x^2)
for it in range(0, 15):
    minimalg_single("objfun1", it, lambda_str, tolerance, -1, -1, 0.5)


1 & 0.00100 & $1+1/k$ & 22.33 & 0.0097268891 & -0.9964550521 & 0.00354494788355519397 \\ [1ex]
2 & 0.00010 & $1+1/k$ & 32.63 & 0.0168619943 & -0.9996350070 & 0.00036499295776593055 \\ [1ex]
3 & 0.00001 & $1+1/k$ & 43.45 & 0.0224959898 & -0.9999632451 & 0.00003675493970112242 \\ [1ex]
4 & 0.00100 & $1/k$ & 9.14 & 0.0040830684 & -0.9996927357 & 0.00030726425288318815 \\ [1ex]
5 & 0.00010 & $1/k$ & 11.34 & 0.0056137514 & -0.9999656415 & 0.00003435851388045030 \\ [1ex]
6 & 0.00001 & $1/k$ & 12.89 & 0.0069049120 & -0.9999980837 & 0.00000191633808055425 \\ [1ex]
7 & 0.00100 & $1$ & 19.87 & 0.0081059384 & -0.9965467562 & 0.00345324378418865319 \\ [1ex]
8 & 0.00010 & $1$ & 30.15 & 0.0138498425 & -0.9996567413 & 0.00034325872483720321 \\ [1ex]
9 & 0.00001 & $1$ & 40.66 & 0.0194436622 & -0.9999645867 & 0.00003541327894429624 \\ [1ex]
10 & 0.00100 & $2-1/k$ & 28.82 & 0.0126289725 & -0.9929174372 & 0.00708256284478170350 \\ [1ex]
11 & 0.00010 & $2-1/k$ & 47.62 & 0.0221757603 & -0.9992565032 & 0.00074349683498764474 \\ [1ex]
12 & 0.00001 & $2-1/k$ & 67.07 & 0.0314221668 & -0.9999260223 & 0.00007397770614081534 \\ [1ex]
13 & 0.00100 & $3+(-1)**k$ & 33.94 & 0.0144602656 & -0.9858908733 & 0.01410912671468067536 \\ [1ex]
14 & 0.00010 & $3+(-1)**k$ & 57.52 & 0.0258085489 & -0.9985350097 & 0.00146499026759994155 \\ [1ex]
15 & 0.00001 & $3+(-1)**k$ & 85.46 & 0.0399583292 & -0.9998561196 & 0.00014388038388868374 \\ [1ex]

In [71]:
# f(x) = -x / e^x
for it in range(0, 15):
    minimalg_single("objfun2", it, lambda_str, tolerance, 1, 1, 3)


1 & 0.00100 & $1+1/k$ & 39.54 & 0.0147391129 & 1.0054561798 & 0.0054561798 \\ [1ex]
2 & 0.00010 & $1+1/k$ & 56.29 & 0.0245152712 & 1.0005311419 & 0.0005311419 \\ [1ex]
3 & 0.00001 & $1+1/k$ & 67.60 & 0.0338211274 & 1.0000501158 & 0.0000501158 \\ [1ex]
4 & 0.00100 & $1/k$ & 12.07 & 0.0053561139 & 1.0006011480 & 0.0006011480 \\ [1ex]
5 & 0.00010 & $1/k$ & 13.68 & 0.0064319849 & 1.0000470621 & 0.0000470621 \\ [1ex]
6 & 0.00001 & $1/k$ & 15.87 & 0.0080986309 & 1.0000034568 & 0.0000034568 \\ [1ex]
7 & 0.00100 & $1$ & 37.43 & 0.0158728194 & 1.0051425972 & 0.0051425972 \\ [1ex]
8 & 0.00010 & $1$ & 49.96 & 0.0233298469 & 1.0005108309 & 0.0005108309 \\ [1ex]
9 & 0.00001 & $1$ & 65.55 & 0.0300751972 & 1.0000490117 & 0.0000490117 \\ [1ex]
10 & 0.00100 & $2-1/k$ & 60.31 & 0.0227115870 & 1.0104120161 & 0.0104120161 \\ [1ex]
11 & 0.00010 & $2-1/k$ & 83.70 & 0.0339471507 & 1.0010403909 & 0.0010403909 \\ [1ex]
12 & 0.00001 & $2-1/k$ & 112.98 & 0.0493660355 & 1.0001060289 & 0.0001060289 \\ [1ex]
13 & 0.00100 & $3+(-1)**k$ & 70.28 & 0.0258462286 & 1.0207090269 & 0.0207090269 \\ [1ex]
14 & 0.00010 & $3+(-1)**k$ & 109.84 & 0.0454991341 & 1.0020542956 & 0.0020542956 \\ [1ex]
15 & 0.00001 & $3+(-1)**k$ & 138.86 & 0.0612455297 & 1.0002056361 & 0.0002056361 \\ [1ex]

In [72]:
# f(x) = (x-2)^4 + (x-2)^3 + (x-2)^2 + 1, x* = 2
for it in range(0, 15):
    minimalg_single("objfun3", it, lambda_str, tolerance, 2, -10, 12)


1 & 0.00100 & $1+1/k$ & 12.77 & 0.0155383277 & 1.9998870878 & 0.0001129122 \\ [1ex]
2 & 0.00010 & $1+1/k$ & 16.33 & 0.0205769658 & 2.0000006092 & 0.0000006092 \\ [1ex]
3 & 0.00001 & $1+1/k$ & 19.98 & 0.0260537243 & 1.9999983445 & 0.0000016555 \\ [1ex]
4 & 0.00100 & $1/k$ & 6.82 & 0.0083272767 & 1.9999313711 & 0.0000686289 \\ [1ex]
5 & 0.00010 & $1/k$ & 8.17 & 0.0114696145 & 1.9999979519 & 0.0000020481 \\ [1ex]
6 & 0.00001 & $1/k$ & 9.21 & 0.0151207972 & 2.0000004529 & 0.0000004529 \\ [1ex]
7 & 0.00100 & $1$ & 11.64 & 0.0150487661 & 1.9998661842 & 0.0001338158 \\ [1ex]
8 & 0.00010 & $1$ & 14.77 & 0.0190531445 & 1.9999886244 & 0.0000113756 \\ [1ex]
9 & 0.00001 & $1$ & 17.83 & 0.0242376137 & 1.9999988578 & 0.0000011422 \\ [1ex]
10 & 0.00100 & $2-1/k$ & 15.38 & 0.0182235932 & 1.9998100032 & 0.0001899968 \\ [1ex]
11 & 0.00010 & $2-1/k$ & 21.50 & 0.0279188633 & 1.9999645410 & 0.0000354590 \\ [1ex]
12 & 0.00001 & $2-1/k$ & 26.91 & 0.0356755161 & 1.9999971947 & 0.0000028053 \\ [1ex]
13 & 0.00100 & $3+(-1)**k$ & 19.46 & 0.0223808455 & 1.9998446880 & 0.0001553120 \\ [1ex]
14 & 0.00010 & $3+(-1)**k$ & 27.48 & 0.0341912603 & 1.9999045584 & 0.0000954416 \\ [1ex]
15 & 0.00001 & $3+(-1)**k$ & 34.48 & 0.0410525322 & 1.9999981353 & 0.0000018647 \\ [1ex]

In [122]:
def minimalg_multiple(str_func, lambda_str, it):
    optimum = 2
    x0 = 5
    max_iter = 200
    objfun = globals()[str_func]
    tolerance = 1e-5
    
    xprev = x0
    #lambda_str = input("Lambda function: ")
    start_time = time.time()

    for k in range(1, max_iter + 1):
        lamb = eval(lambda_str[it])

        res = minimize(objfun, x0, args=(xprev, lamb), method='BFGS', tol=1e-5, options={'disp': False, 'maxiter': 100})
        error = abs(xprev-res.x[0])
        xprev = res.x[0]

        if (error <= tolerance):
            break;

    end_time = time.time() - start_time        
    print('%d & %d & %.1f & $%s$ & %d & %.10f & %.10f & %.10f \\\\ [1ex]' % (it+1, optimum, x0, lambda_str[it], k, end_time, xprev, abs(xprev-optimum)))

In [110]:
lamb = ['1+1/k', '1/k', '1', '2-1/k', '3+(-1)**k']
for i in range(0, 5):
    minimalg_multiple("objfun4", lamb, i)


1 & 5 & 6 & $1+1/k$ & 5 & 0.0060024261 & 4.9999999969 & 0.0000000031 \\ [1ex]
2 & 5 & 6 & $1/k$ & 4 & 0.0040032864 & 4.9999999947 & 0.0000000053 \\ [1ex]
3 & 5 & 6 & $1$ & 4 & 0.0060029030 & 5.0000000466 & 0.0000000466 \\ [1ex]
4 & 5 & 6 & $2-1/k$ & 4 & 0.0060043335 & 5.0000002223 & 0.0000002223 \\ [1ex]
5 & 5 & 6 & $3+(-1)**k$ & 5 & 0.0090060234 & 5.0000000824 & 0.0000000824 \\ [1ex]

In [123]:
lamb = ['1+1/k', '1/k', '1', '2-1/k', '3+(-1)**k']
for i in range(0, 5):
    minimalg_multiple("objfun5", lamb, i)


1 & 2 & 5.0 & $1+1/k$ & 4 & 0.0100049973 & 2.0000000209 & 0.0000000209 \\ [1ex]
2 & 2 & 5.0 & $1/k$ & 4 & 0.0110077858 & 1.9999999929 & 0.0000000071 \\ [1ex]
3 & 2 & 5.0 & $1$ & 4 & 0.0160121918 & 1.9999999987 & 0.0000000013 \\ [1ex]
4 & 2 & 5.0 & $2-1/k$ & 4 & 0.0150275230 & 2.0000000193 & 0.0000000193 \\ [1ex]
5 & 2 & 5.0 & $3+(-1)**k$ & 5 & 0.0100069046 & 1.9999999973 & 0.0000000027 \\ [1ex]

In [ ]: