You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

解决方案

问题根源

  1. Scipy的direct函数会将优化变量打包为单个numpy数组传入目标函数,但你的C封装函数需要两个独立的int参数,导致参数数量不匹配。
  2. 添加包装函数后,direct传入的是numpy浮点类型元素,而ctypes要求严格匹配argtypes的c_int类型,直接传递numpy数值会触发类型错误。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:21:14