#  -*- coding: utf-8 -*-
# Задача 2: глобальная оптимизация
#
#     1.Теперь попробуем применить к той же функции f(x) метод глобальной оптимизации - дифференциальную эволюцию.
#     2.Изучите документацию и примеры использования функции scipy.optimize.differential_evolution.
#     3.Обратите внимание, что границы значений аргументов функции представляют собой список кортежей
#       (list, в который помещены объекты типа tuple). Даже если у вас функция одного аргумента, возьмите
#       границы его значений в квадратные скобки, чтобы передавать в этом параметре список из одного кортежа,
#       т.к. в реализации scipy.optimize.differential_evolution длина
#       этого списка используется чтобы определить количество аргументов функции.
#     4.Запустите поиск минимума функции f(x) с помощью дифференциальной эволюции на промежутке [1, 30].
#       Полученное значение функции в точке минимума - ответ в задаче 2.
#       Запишите его с точностью до второго знака после запятой. В этой задаче ответ - только одно число.
#     5.Заметьте, дифференциальная эволюция справилась с задачей поиска глобального минимума
#       на отрезке, т.к. по своему устройству она предполагает борьбу с попаданием в локальные минимумы.
#     6.Сравните количество итераций, потребовавшихся BFGS для нахождения минимума при
#       хорошем начальном приближении, с количеством итераций, потребовавшихся дифференциальной эволюции.
#       При повторных запусках дифференциальной эволюции количество итераций будет меняться,
#       но в этом примере, скорее всего, оно всегда будет сравнимым с количеством итераций BFGS.
#       Однако в дифференциальной эволюции за одну итерацию требуется выполнить гораздо больше действий,
#       чем в BFGS. Например, можно обратить внимание на количество вычислений значения функции (nfev)
#       и увидеть, что у BFGS оно значительно меньше. Кроме того, время работы дифференциальной эволюции
#       очень быстро растет с увеличением числа аргументов функции.



import numpy as np
import matplotlib.pylab as plt
from scipy.optimize import differential_evolution

# f(x) = sin(x / 5) * exp(x / 10) + 5 * exp(-x / 2)
def functQuiz(x):
    f = np.sin(x / 5.) * np.exp(x /10.) + 5 * np.exp(-x /2.)
    return f

xPoints = np.arange(1, 30, 0.1)
fx = functQuiz
yPoints = map(fx, xPoints)
plt.plot(xPoints, yPoints)

result = differential_evolution(fx, [(1,30)])

 #     fun: array([-11.89889467])
 #     jac: array([ 0.])
 # message: 'Optimization terminated successfully.'
 #    nfev: 83
 #     nit: 4
 # success: True
 #       x: array([ 25.88019319])

print result

plt.show()