Skip to content

自定义问题

在 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 None

3.2 方法说明

  1. __init__ 方法:

    • 初始化问题参数
    • 设置决策变量的取值范围
    • 调用父类初始化方法,参数说明:
      • decision_num: 决策变量维度
      • 2: 目标函数个数(双目标优化问题)
      • 0: 约束条件个数(0表示无约束问题)
      • n: 环境变化周期
      • tau: 环境变化强度
      • solution_num: 种群大小
      • total_evaluate_time: 总评估次数
      • 'Dynamic': 问题类型,表示这是一个动态无约束优化问题
  2. _evaluate_objectives 方法:

    • 计算目标函数值
    • 处理环境变化
    • 返回目标函数值矩阵
  3. _evaluate_constraints 方法:

    • 计算约束条件值
    • 对于无约束问题,返回 None
    • 返回约束值矩阵
  4. _calculate_pareto_front 方法:

    • 计算帕累托前沿
    • 对于没有已知帕累托前沿的问题,返回 None
    • 返回帕累托前沿矩阵
  5. _calculate_pareto_set 方法:

    • 计算帕累托解集
    • 对于没有已知帕累托解集的问题,返回 None
    • 返回帕累托解集矩阵
  6. 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)

注意事项

  1. 确保您的问题类继承自 Problem 基类
  2. 必须实现 __init___evaluate_objectives 方法
  3. 正确处理环境变化
  4. 对于无约束问题,_evaluate_constraints 方法应返回 None
  5. 对于没有已知帕累托前沿和解集的问题,_calculate_pareto_front_calculate_pareto_set 方法可以返回 None
  6. 注意决策变量的取值范围

使用建议

  1. 复制基础模板到您的问题目录中
  2. 修改 config.jsoninfo.json 中的参数和信息
  3. main.py 中:
    • 修改类名和文档字符串
    • __init__ 中添加您的问题参数
    • _evaluate_objectives 方法中实现您的目标函数
    • 根据需要实现 _evaluate_constraints 方法
    • 如果问题有已知的帕累托前沿和解集,实现 _calculate_pareto_front_calculate_pareto_set 方法