Source code for mealpy.human_based.CDDO

#!/usr/bin/env python
# Created by "Thieu" at 23:41, 15/08/2025 ----------%                                                                               
#       Email: nguyenthieu2102@gmail.com            %                                                    
#       Github: https://github.com/thieu1995        %                         
# --------------------------------------------------%

from mealpy.optimizer import Optimizer
from mealpy.utils.opt_info import OptInfo, ScientificConcern


[docs]class OriginalCDDO(Optimizer): """ The original version of: Child Drawing Development Optimization (CCDO) Parameters ---------- epoch : int Maximum number of iterations. Default is 10000. pop_size : int Population size (number of trees). Default is 100. pattern_size : int Size of the pattern matrix, in range [1, 1000]. Default is 10. creativity_rate : float Creativity rate, in range [0.0, 1.0]. Default is 0.1. Danger ------ 1. This source code was converted from the original Matlab implementation in the paper into Python. The Matlab code itself has many issues, for example, parameters are defined but never used. Several variables are declared, such as p1, p2, p3. Parameters like child skill rate and child level rate are initialized as hyperparameters at the beginning, but inside the loop they are randomly generated, which is far from the paper. 2. Moreover, the biggest flaw of this algorithm lies in the if–else condition during the update process. There is a high chance that neither condition will be executed, because the golden ratio is not necessarily within the interval [1.5, 2], as it is computed based on a random position. In addition, when comparing the position with a random integer T (hand pressure), it is unclear why this is done. It is highly likely that the algorithm will only execute that single condition. References ---------- 1. Abdulhameed, S., Rashid, T.A. Child Drawing Development Optimization Algorithm Based on Child’s Cognitive Development. Arab J Sci Eng 47, 1337–1351 (2022). https://doi.org/10.1007/s13369-021-05928-6 Examples -------- >>> import numpy as np >>> from mealpy import FloatVar, CDDO >>> >>> def objective_function(solution): >>> return np.sum(solution**2) >>> >>> problem_dict = { >>> "bounds": FloatVar(lb=(-10.,) * 30, ub=(10.,) * 30, name="delta"), >>> "minmax": "min", >>> "obj_func": objective_function >>> } >>> >>> model = CDDO.OriginalCDDO(epoch=1000, pop_size=50, pattern_size=10, creativity_rate=0.1) >>> g_best = model.solve(problem_dict) >>> print(f"Solution: {g_best.solution}, Fitness: {g_best.target.fitness}") >>> print(f"Solution: {model.g_best.solution}, Fitness: {model.g_best.target.fitness}") """ OPT_INFO = OptInfo(name="Child Drawing Development Optimization", year=2022, difficulty="medium", kind="original", scientific_status="questionable", concerns=( ScientificConcern.LACK_OF_NOVELTY, ScientificConcern.QUESTIONABLE_MATH, ScientificConcern.INCORRECT_EQUATIONS, ScientificConcern.FABRICATED_RESULTS )) def __init__(self, epoch: int = 10000, pop_size: int = 100, pattern_size=10, creativity_rate=0.1, **kwargs: object) -> None: """ Args: epoch (int): maximum number of iterations, default = 10000 pop_size (int): number of population size, default = 100 pattern_size (int): size of the pattern matrix, default = 10 creativity_rate (float): creativity rate, default = 0.1 """ super().__init__(**kwargs) self.epoch = self.validator.check_int("epoch", epoch, [1, 100000]) self.pop_size = self.validator.check_int("pop_size", pop_size, [5, 10000]) self.pattern_size = self.validator.check_int("pattern_size", pattern_size, [1, 1000]) self.creativity_rate = self.validator.check_float("creativity_rate", creativity_rate, [0.0, 1.0]) self.set_parameters(["epoch", "pop_size", "pattern_size", "creativity_rate"]) self.sort_flag = False
[docs] def before_main_loop(self): self.LR = self.generator.uniform(0.1, 1.0) # Child level rate self.SR = self.generator.uniform(0.1, 1.0) # Child Skill Rate self.pop_local = self.pop.copy() # Golden ratio self.list_gr = [] for idx in range(self.pop_size): p1 = self.generator.integers(0, self.problem.n_dims) p2 = self.generator.integers(0, self.problem.n_dims) if self.pop[idx].solution[p1] == 0: self.list_gr.append(self.pop[idx].solution[p2]) else: self.list_gr.append(self.pop[idx].solution[p1] + self.pop[idx].solution[p2] / self.pop[idx].solution[p1])
[docs] def evolve(self, epoch): """ The main operations (equations) of algorithm. Inherit from Optimizer class Args: epoch (int): The current iteration """ # Pattern matrix _, pattern, _ = self.get_special_agents(self.pop, n_best=self.pattern_size, minmax=self.problem.minmax) for idx in range(0, self.pop_size): hand_pressure = self.generator.integers(self.problem.lb[0], self.problem.ub[0] + 1) pp = self.generator.integers(0, self.problem.n_dims) pos_new = self.pop[idx].solution.copy() if self.pop[idx].solution[pp] <= hand_pressure: # Update the drawings pos_new = (self.list_gr[idx] + self.SR * self.generator.random(self.problem.n_dims) * (self.pop_local[idx].solution - self.pop[idx].solution) + self.LR * self.generator.random(self.problem.n_dims) * (self.g_best.solution - self.pop[idx].solution)) self.LR = self.generator.integers(6, 11) / 10 self.SR = self.generator.integers(6, 11) / 10 elif 1.5 < self.list_gr[idx] < 2: # Consider the learnt patterns pos_new = pattern[self.generator.integers(0, self.pattern_size)].solution - self.creativity_rate * self.pop_local[idx].solution self.LR = self.generator.integers(0, 6) / 10 self.SR = self.generator.integers(0, 6) / 10 pos_new = self.correct_solution(pos_new) agent = self.generate_empty_agent(pos_new) self.pop[idx] = agent if self.mode not in self.AVAILABLE_MODES: self.pop[idx].target = self.get_target(pos_new) if self.mode in self.AVAILABLE_MODES: self.pop = self.update_target_for_population(self.pop) # Update the local information self.pop_local = self.greedy_selection_population(self.pop_local, self.pop, self.problem.minmax)