使用ctypes封装C代码后调用Scipy direct优化遇类型错误求助
问题:ctypes封装C函数后,Scipy direct优化时的参数错误
我已用ctypes将C实现的styblinski_tang函数封装到Python中,单独调用(如输入1,1)可得到正确结果-10。但用Scipy的direct方法优化时,先出现TypeError: this function takes at least 2 arguments (1 given)错误;添加Python包装函数后,又触发ctypes参数类型错误。
初始Python代码(ctype_tutorial.py)
import ctypes from ctypes import * import numpy as np from numpy import ctypeslib from scipy.optimize import minimize from scipy.optimize import direct, Bounds, basinhopping clibrary = ctypes.CDLL(r"C:\Users\mhaja\OneDrive\Desktop\Github\Honours\ctypes\clibrary.so") styblinski_tang = clibrary.styblinski_tang styblinski_tang.argtypes = [ctypes.c_int, ctypes.c_int] styblinski_tang.restype = ctypes.c_int print(styblinski_tang(1, 1)) result = direct(styblinski_tang, [[-4,4], [-4,4]]) print(result.x, result.fun, result.nfev)
C代码(clibrary.c)
#include <stdio.h> #include <math.h> int styblinski_tang(int x, int y){ return 0.5 * (pow(x, 4) - 16*pow(x, 2) + 5*x + pow(y, 4) - 16*pow(y, 2) + 5*y); }
初始报错信息
-10 Traceback (most recent call last): File "c:\Users\mhaja\OneDrive\Desktop\Github\Honours\ctypes\ctypes_tutorial.py", line 44, in <module> result = direct(styblinski_tang, [[-4,4], [-4,4]]) File "C:\Users\mhaja\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\scipy\optimize\_direct_py.py", line 256, in direct x, fun, ret_code, nfev, nit = _direct( File "C:\Users\mhaja\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\scipy\optimize\_direct_py.py", line 249, in _func_wrap f = func(x) TypeError: this function takes at least 2 arguments (1 given)
添加包装函数后的Python代码
import ctypes from ctypes import * import numpy as np from numpy import ctypeslib from scipy.optimize import minimize from scipy.optimize import direct, Bounds, basinhopping clibrary = ctypes.CDLL(r"C:\Users\mhaja\OneDrive\Desktop\Github\Honours\ctypes\clibrary.so") styblinski_tang = clibrary.styblinski_tang styblinski_tang.argtypes = [ctypes.c_int, ctypes.c_int] styblinski_tang.restype = ctypes.c_int print(styblinski_tang(1, 1)) # 包装函数 def foo(xy): x,y = xy return styblinski_tang(x, y) print(foo([1,1])) result = direct(foo, [[-4,4], [-4,4]]) print(result.x, result.fun, result.nfev)
更新后报错信息
-10 -10 Traceback (most recent call last): File "c:\Users\mhaja\OneDrive\Desktop\Github\Honours\ctypes\ctypes_tutorial.py", line 51, in <module> result = direct(foo, [[-4,4], [-4,4]]) File "C:\Users\mhaja\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\scipy\optimize\_direct_py.py", line 256, in direct x, fun, ret_code, nfev, nit = _direct( File "C:\Users\mhaja\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\scipy\optimize\_direct_py.py", line 249, in _func_wrap f = func(x) File "c:\Users\mhaja\OneDrive\Desktop\Github\Honours\ctypes\ctypes_tutorial.py", line 47, in foo return styblinski_tang(x, y) ctypes.ArgumentError: argument 1: TypeError: wrong type
解决方案
问题根源
- Scipy的
direct函数会将优化变量打包为单个numpy数组传入目标函数,但你的C封装函数需要两个独立的int参数,导致参数数量不匹配。 - 添加包装函数后,
direct传入的是numpy浮点类型元素,而ctypes要求严格匹配argtypes的c_int类型,直接传递numpy数值会触发类型错误。 - C函数返回值用int类型,但计算结果是浮点数,会被截断,导致精度丢失。
修正步骤
1. 修改C代码,改用浮点类型
将参数和返回值改为double,避免精度损失:
#include <stdio.h> #include <math.h> double styblinski_tang(double x, double y){ return 0.5 * (pow(x, 4) - 16*pow(x, 2) + 5*x + pow(y, 4) - 16*pow(y, 2) + 5*y); }
2. 修正Python封装与包装函数
更新ctypes的参数/返回类型,同时在包装函数中将numpy数组元素转换为ctypes兼容类型:
import ctypes import numpy as np from scipy.optimize import direct clibrary = ctypes.CDLL(r"C:\Users\mhaja\OneDrive\Desktop\Github\Honours\ctypes\clibrary.so") styblinski_tang = clibrary.styblinski_tang # 更新为double类型 styblinski_tang.argtypes = [ctypes.c_double, ctypes.c_double] styblinski_tang.restype = ctypes.c_double print(styblinski_tang(1.0, 1.0)) # 输出-10.0,保留浮点精度 def foo(xy): # 显式转换为ctypes兼容类型 x = ctypes.c_double(xy[0]) y = ctypes.c_double(xy[1]) return styblinski_tang(x, y) print(foo([1.0,1.0])) result = direct(foo, [[-4,4], [-4,4]]) print(result.x, result.fun, result.nfev)
补充说明
- 优化算法通常需要浮点变量,C函数改用
double更合理,避免整数截断导致的精度问题。 - 包装函数必须显式转换numpy数值,因为
direct传入的是numpyfloat64,ctypes不会自动隐式转换numpy数组元素。 - 若坚持使用整数参数,只需将包装函数中的转换改为
ctypes.c_int(int(xy[0])),同时保持C函数的int类型,但优化结果会受限(仅能取整数点)。
内容的提问来源于stack exchange,提问作者mehrad hajati
相关产品推荐
相关产品推荐

