Skip to content

Commit

Permalink
Рабочая начальная версия mco (#179)
Browse files Browse the repository at this point in the history
* mco test problem & optim task

* mco test problem & optim task 2

* added mco_process, fixed convolution and added to mco to solverFactory

* mco test problem & optim task 3

* reverted optim task. shouldn't have touched in first place

* fixed bug

* mco test problem & optim task 4

* mco test problem & optim task 5

* mco test problem & optim task 6

* new problem&test, update method

* working ver

* mb work

* delete comment, add task, evolvent for init lambdas, other refac

* delete comment, add start_lambdas&is_scaling, add init_lambdas

* fix with comments

* fix with comments 1

---------

Co-authored-by: MADZEROPIE <[email protected]>
  • Loading branch information
YaniKolt and MADZEROPIE committed Feb 20, 2024
1 parent d897935 commit f0ffb22
Show file tree
Hide file tree
Showing 24 changed files with 1,920 additions and 53 deletions.
46 changes: 46 additions & 0 deletions examples/MCO_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from problems.grishagin_mco import Grishagin_mco
from iOpt.solver import Solver
from iOpt.solver_parametrs import SolverParameters
from iOpt.output_system.listeners.console_outputers import ConsoleOutputListener
import matplotlib.pyplot as plt

if __name__ == "__main__":
"""
"""

# создание объекта задачи
problem = Grishagin_mco(2, [3, 2])

# Формируем параметры решателя
params = SolverParameters(r=2.5, eps=0.01, iters_limit=16000, number_of_lambdas=50, start_lambdas=[[0, 1]], is_scaling=False)

# Создаем решатель
solver = Solver(problem=problem, parameters=params)

# Добавляем вывод результатов в консоль
cfol = ConsoleOutputListener(mode='full')
solver.add_listener(cfol)

# Решение задачи
sol = solver.solve()

# вывод множества Парето (координаты - значения функций)
var = [trial.point.float_variables for trial in sol.best_trials]
val = [[trial.function_values[i].value for i in range(2)]for trial in sol.best_trials ]
print("size pareto set: ", len(var))
for fvar, fval in zip(var, val):
print(fvar, fval)

# Точки для постороения графика множества Парето x[0]-x[1]
x1 = [trial.point.float_variables[0] for trial in sol.best_trials]
x2 = [trial.point.float_variables[1] for trial in sol.best_trials]

plt.plot(x1, x2, 'ro')
plt.show()

# Точки для постороения графика множества Парето y[0]-y[1]
fv1 = [trial.function_values[0].value for trial in sol.best_trials]
fv2 = [trial.function_values[1].value for trial in sol.best_trials]

plt.plot(fv1, fv2, 'ro')
plt.show()
147 changes: 147 additions & 0 deletions iOpt/method/mco_process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from typing import List
from datetime import datetime

import traceback

from iOpt.evolvent.evolvent import Evolvent
from iOpt.method.listener import Listener
from iOpt.method.method import Method
from iOpt.method.multi_objective_optim_task import MultiObjectiveOptimizationTask
from iOpt.method.search_data import SearchData
from iOpt.solution import Solution
from iOpt.solver_parametrs import SolverParameters
from iOpt.method.process import Process


class MCOProcess(Process):
"""
Класс MCOProcess скрывает внутреннюю имплементацию класса Solver.
"""

def __init__(self,
parameters: SolverParameters,
task: MultiObjectiveOptimizationTask,
evolvent: Evolvent,
search_data: SearchData,
method: Method,
listeners: List[Listener],
lambdas=[]
):

super().__init__(parameters, task, evolvent, search_data, method, listeners)

self.number_of_lambdas = parameters.number_of_lambdas
if lambdas:
self.start_lambdas = lambdas
elif parameters.start_lambdas:
self.start_lambdas = parameters.start_lambdas
else:
self.start_lambdas = []

self.current_num_lambda = 0
self.lambdas_list = [] # список всех рассматриваемых
self.iterations_list = []

self.convolution = task.convolution
self.task = task

self.init_lambdas()

def solve(self) -> Solution:
"""
Метод позволяет решить задачу оптимизации. Остановка поиска выполняется согласно критерию,
заданному при создании класса Solver.
:return: Текущая оценка решения задачи оптимизации
"""

start_time = datetime.now()

try:
for i in range(self.number_of_lambdas):
while not self.method.check_stop_condition():
self.do_global_iteration()
self.change_lambdas()

except Exception:
print('Exception was thrown')
print(traceback.format_exc())

if self.parameters.refine_solution:
self.do_local_refinement(self.parameters.local_method_iteration_count)

result = self.get_results()
result.solving_time = (datetime.now() - start_time).total_seconds()

for listener in self._listeners:
status = self.method.check_stop_condition()
listener.on_method_stop(self.search_data, self.get_results(), status)

return result

def change_lambdas(self) -> None:
self.method.set_min_delta(1)
self.current_num_lambda += 1
if self.current_num_lambda < self.number_of_lambdas:
self.current_lambdas = self.lambdas_list[self.current_num_lambda]
self.task.convolution.lambda_param = self.current_lambdas

self.iterations_list.append(self.method.iterations_count) # здесь будет накапливаться сумма итераций
max_iter_for_convolution = int((self.parameters.global_method_iteration_count /
self.number_of_lambdas) * (self.current_num_lambda + 1))
self.method.set_max_iter_for_convolution(max_iter_for_convolution)

def init_lambdas(self) -> None:
if self.task.problem.number_of_objectives == 2: # двумерный случай
if self.number_of_lambdas > 1:
h = 1.0/(self.number_of_lambdas-1)
else:
h = 1
if not self.start_lambdas:
for i in range(self.number_of_lambdas):
lambda_0 = i * h
if lambda_0 > 1:
lambda_0 = lambda_0 - 1
lambda_1 = 1 - lambda_0
lambdas = [lambda_0, lambda_1]
self.lambdas_list.append(lambdas)
elif len(self.start_lambdas)==self.number_of_lambdas:
for i in range(self.number_of_lambdas):
self.lambdas_list.append(self.start_lambdas[i])
elif len(self.start_lambdas)==1:
self.lambdas_list.append(self.start_lambdas[0])
for i in range(1, self.number_of_lambdas):
lambda_0 = self.start_lambdas[0][0] + i*h
if lambda_0 > 1:
lambda_0 = lambda_0 - 1
lambda_1 = 1 - lambda_0
lambdas = [lambda_0, lambda_1]
self.lambdas_list.append(lambdas)
else: # многомерный случай
if len(self.start_lambdas)==self.number_of_lambdas:
for i in range(self.number_of_lambdas):
self.lambdas_list.append(self.start_lambdas[i])
else:
if self.number_of_lambdas > 1:
h = 1.0 / (self.number_of_lambdas - 1)
else:
h = 1
evolvent = Evolvent([0]*self.task.problem.number_of_objectives, [1]*self.task.problem.number_of_objectives, self.task.problem.number_of_objectives)

for i in range(self.number_of_lambdas):
x = i*h
y = evolvent.get_image(x)
sum = 0
for i in range(self.task.problem.number_of_objectives):
sum += y[i]
for i in range(self.task.problem.number_of_objectives):
y[i] = y[i] / sum
lambdas = list(y)
self.lambdas_list.append(lambdas)

self.current_lambdas = self.lambdas_list[0]
self.method.max_iter_for_convolution = int(
self.parameters.global_method_iteration_count / self.number_of_lambdas)

# TODO: проверить load/store

4 changes: 2 additions & 2 deletions iOpt/method/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def __init__(self,
self.evolvent = evolvent
self.search_data = search_data

self.M = [1.0 for _ in range(task.problem.number_of_objectives + task.problem.number_of_constraints)]
self.Z = [np.infty for _ in range(task.problem.number_of_objectives + task.problem.number_of_constraints)]
self.M = [1.0 for _ in range(1 + task.problem.number_of_constraints)]
self.Z = [np.infty for _ in range(1 + task.problem.number_of_constraints)]
self.dimension = task.problem.number_of_float_variables
self.search_data.solution.solution_accuracy = np.infty
self.numberOfAllFunctions = task.problem.number_of_objectives + task.problem.number_of_constraints
Expand Down
Loading

0 comments on commit f0ffb22

Please sign in to comment.