自定义问题
在 FlexDMO 平台中,您可以通过自定义问题来测试和评估算法的性能。本文档将详细介绍如何实现一个符合平台规范的问题,包括创建问题目录结构、编写配置文件、实现问题类以及测试问题。通过遵循本文档的步骤,您可以快速开发自己的优化问题,并确保其能够与平台正确集成。
1. 创建问题目录结构
首先,在 problems/benchmark/ 目录下创建您的问题目录,例如 YourProblem:
problems/benchmark/YourProblem/
├── main.py # 问题主实现文件,包含目标函数和约束条件
├── config.json # 问题配置文件,定义问题参数
├── info.json # 问题信息文件,包含问题的相关信息2. 问题配置文件 (config.json)
配置文件用于定义问题的参数,这些参数将被平台读取并显示在参数设置界面中:
json
{
"decision_num": 10, // 决策变量维度
"n": 10, // 环境变化周期
"tau": 10, // 环境变化强度
"total_evaluate_time": 30, // 总评估次数
"solution_num": 100 // 种群大小
}
参数说明
decision_num: 决策变量的维度n: 环境变化的周期tau: 环境变化的强度total_evaluate_time: 算法运行的总评估次数solution_num: 种群大小
3. 问题信息文件 (info.json)
问题信息文件用于定义问题的基本信息,这些信息将被平台读取并显示在问题选择界面中:
json
{
"name": "YourProblem",
"category": "Constrained",
"constraints": 1,
"difficulty": "Moving boundary",
"description": "简要说明问题的动态特征与主要难点"
}
4. 问题实现 (main.py)
在 FlexDMO 平台中,所有问题都需要继承自 Problem 抽象类。这个抽象类定义了问题必须实现的方法和属性,确保问题能够与平台正确交互。
3.1 基础模板
python
import numpy as np
from problems.Problem import Problem
class YourProblem(Problem):
"""
您的问题实现类
实现了多目标优化问题的目标函数
支持动态环境变化
"""
def __init__(self, decision_num, n, tau, solution_num, total_evaluate_time):
"""
初始化问题
参数:
decision_num (int): 决策变量维度
n (int): 环境变化周期
tau (int): 环境变化强度
solution_num (int): 种群大小
total_evaluate_time (int): 总评估次数
"""
super().__init__(decision_num, 2, 0, n, tau, solution_num, total_evaluate_time, 'Dynamic')
self.xl = np.array([0.0] * decision_num) # 决策变量下界
self.xu = np.array([1.0] * decision_num) # 决策变量上界
def _evaluate_objectives(self, X, t=None):
"""
计算目标函数值
参数:
X (numpy.ndarray): 决策变量
t (int): 当前时间步
"""
# TODO: 实现您的目标函数
f1 = ... # 第一个目标函数
f2 = ... # 第二个目标函数
return np.column_stack([f1, f2])
def _evaluate_constraints(self, X, t):
"""
返回约束值,形状:[n_samples, n_con],不满足为正。
对于无约束问题,返回 None。
参数:
X (numpy.ndarray): 决策变量
t (int): 当前时间步
"""
if self.n_con == 0:
return None
# TODO: 实现您的约束条件
return None
def _calculate_pareto_front(self, t=None):
"""
计算帕累托前沿
参数:
t (int): 当前时间步
返回:
numpy.ndarray 或 None: 帕累托前沿,形状为 [n_points, n_obj]。
对于没有已知帕累托前沿的问题,返回 None。
"""
# TODO: 如果问题有已知的帕累托前沿,实现此方法
return None
def _calculate_pareto_set(self, t=None):
"""
计算帕累托解集
参数:
t (int): 当前时间步
返回:
numpy.ndarray 或 None: 帕累托解集,形状为 [n_points, n_var]。
对于没有已知的帕累托解集的问题,返回 None。
"""
# TODO: 如果问题有已知的帕累托解集,实现此方法
return None3.2 方法说明
__init__方法:- 初始化问题参数
- 设置决策变量的取值范围
- 调用父类初始化方法,参数说明:
decision_num: 决策变量维度2: 目标函数个数(双目标优化问题)0: 约束条件个数(0表示无约束问题)n: 环境变化周期tau: 环境变化强度solution_num: 种群大小total_evaluate_time: 总评估次数'Dynamic': 问题类型,表示这是一个动态无约束优化问题
_evaluate_objectives方法:- 计算目标函数值
- 处理环境变化
- 返回目标函数值矩阵
_evaluate_constraints方法:- 计算约束条件值
- 对于无约束问题,返回 None
- 返回约束值矩阵
_calculate_pareto_front方法:- 计算帕累托前沿
- 对于没有已知帕累托前沿的问题,返回 None
- 返回帕累托前沿矩阵
_calculate_pareto_set方法:- 计算帕累托解集
- 对于没有已知帕累托解集的问题,返回 None
- 返回帕累托解集矩阵
get_objective_constraints方法(推荐):- 返回可视化所需的目标空间不可行域描述
- 支持轴向边界、区间和圆形障碍
- 实时显示和结果回放都会读取该描述
轴向边界示例:
python
def get_objective_constraints(self, t=None):
if t is None:
t = self.t
threshold = self._threshold(t)
return [{
"axis": 0,
"operator": ">=",
"threshold": float(threshold),
}]移动圆形不可行域示例:
python
return [{
"kind": "circle",
"center": [float(center_f1), float(center_f2)],
"radius": float(radius),
}]5. 测试问题
您可以使用以下代码测试您的问题:
python
from algorithms.search_algorithm.NSGA2.main import NSGA2
from algorithms.response_strategy.NoResponse.main import NoResponse
# 创建问题实例
problem = YourProblem(10, 10, 10, 100, 30)
# 创建算法实例
algorithm = NSGA2()
# 创建响应策略实例
response = NoResponse()
# 执行优化过程
result = algorithm.optimize(problem, response)注意事项
- 确保您的问题类继承自
Problem基类 - 必须实现
__init__和_evaluate_objectives方法 - 正确处理环境变化
- 对于无约束问题,
_evaluate_constraints方法应返回 None - 对于没有已知帕累托前沿和解集的问题,
_calculate_pareto_front和_calculate_pareto_set方法可以返回 None - 注意决策变量的取值范围
使用建议
- 复制基础模板到您的问题目录中
- 修改
config.json和info.json中的参数和信息 - 在
main.py中:- 修改类名和文档字符串
- 在
__init__中添加您的问题参数 - 在
_evaluate_objectives方法中实现您的目标函数 - 根据需要实现
_evaluate_constraints方法 - 如果问题有已知的帕累托前沿和解集,实现
_calculate_pareto_front和_calculate_pareto_set方法
