Matlab调用Python实现的PSO算法时矩阵传递报错问题排查
问题背景
我有一段Matlab代码,需要调用Python写的PSO算法,其中一个参数是10×5的矩阵。这个矩阵在Python里单独跑PSO完全正常,但Matlab调用时一直报错。
Matlab代码
s = size(CurrentPop, 1); velocity_matrix = []; NewPop = []; for gen = 1:gen_max NewPop, velocity_matrix = py.pso_algorithm.pso(n_chr, n_par, CurrentPop, velocity_matrix, gen); CurrentPop = EvaluateFirestation(NewPop, n_par, fuelmodels);
报错信息
Error using pso_algorithm>pso (line 46)
Python Error: TypeError: slice indices must be integers or None or have an index method
Python function 'pso' might not be able to accept at least one input argument at position 3. The function may require a specific data type that you can construct from the MATLAB array. For more information, see the documentation for Python function 'pso' and working with Python arrays.
报错出在Python函数的particles = particles_array[:, :n_par]这一行。
Python PSO函数代码
def pso(population, n_par, current_pop, velocity_matrix, generation): # Initialization # Population particles_array = np.array(current_pop) particles = particles_array[:, :n_par] # Particle's best position pbest_position = particles # Fitness # ULTIMA COLUNA DE CURRENT_POP pbest_fitness = particles_array[:, n_par] # Index of the best particle gbest_index = np.argmin(pbest_fitness) # VAI BUSCAR O INDICE DO MENOR VALOR EM PBEST_FITNESS # Global best particle position gbest_position = pbest_position[gbest_index] # Velocity (starting from 0 speed) if generation == 1: velocity = [[0.0 for j in range(n_par)] for i in range(population)] else: velocity = velocity_matrix for n in range(population): # Update the velocity of each particle velocity[n] = update_velocity(particles[n], velocity[n], pbest_position[n], gbest_position, n_par) # Move the particles to new position particles[n] = update_position(particles[n], velocity[n]) particles = np.insert(particles, n_par, pbest_fitness, axis=1) velocity = np.array(velocity) # print(particles) # print(velocity) return particles, velocity
问题原因与解决方法
核心问题
Matlab往Python传数据时,默认不是NumPy数组类型,而是Matlab自己的数组对象。直接用np.array(current_pop)转换这种对象,可能导致数组无法正常切片;另外,n_par这类数值参数传过去可能是Matlab的数值对象,不是Python原生整数,也会触发切片报错。
具体解决步骤
把数值参数转成Python整数
在Matlab里,先把n_chr、n_par、gen转成Python整数类型再传:py_n_chr = py.int(n_chr); py_n_par = py.int(n_par);直接把Matlab数组转成NumPy数组
传递CurrentPop之前,用py.numpy.array()转成Python能识别的NumPy数组:py_CurrentPop = py.numpy.array(CurrentPop);处理初始空的velocity_matrix
Matlab里初始的空数组[]传到Python后没法直接用,改成初始化为对应形状的零矩阵:velocity_matrix = py.numpy.zeros(py.tuple({s, n_par}));Python函数里加类型兼容处理(可选)
在Python函数开头,强制把参数转成原生类型,避免类型不兼容:def pso(population, n_par, current_pop, velocity_matrix, generation): # 转成Python原生整数 population = int(population) n_par = int(n_par) generation = int(generation) # 确保current_pop是NumPy数组 if not isinstance(current_pop, np.ndarray): # 先转成列表再转NumPy数组 particles_array = np.array(current_pop.tolist()) else: particles_array = current_pop # 后面的代码不变
修改后的Matlab调用示例
s = size(CurrentPop, 1); % 初始化velocity_matrix为NumPy零矩阵 velocity_matrix = py.numpy.zeros(py.tuple({s, n_par})); NewPop = []; % 转换数值参数为Python整数 py_n_chr = py.int(n_chr); py_n_par = py.int(n_par); for gen = 1:gen_max py_CurrentPop = py.numpy.array(CurrentPop); py_gen = py.int(gen); NewPop, velocity_matrix = py.pso_algorithm.pso(py_n_chr, py_n_par, py_CurrentPop, velocity_matrix, py_gen); CurrentPop = EvaluateFirestation(NewPop, n_par, fuelmodels); end
内容的提问来源于stack exchange,提问作者João Sousa

