Skip to content

CNC_PYTHON&&CPP联合编程

资料:

  • https://pybind11.readthedocs.io/en/stable/advanced/cast/eigen.html
  • https://www.cnblogs.com/hyl2018/p/14089299.html
  • https://www.yingnd.com/python/105835.html

这篇笔记,记录借助pybind11,python调用eigen库进行KU=F的求解.

准备

  1. 安装vs2022,选择C++桌面开发;
  2. 下载eigen源码,https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.zip
  3. 安装python3.10+,安装numpy,pybind11;

第一步,编写cpp代码

solve_KUF.cpp中:

#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <stdexcept>

namespace py = pybind11;

Eigen::VectorXd solveKUF(const Eigen::MatrixXd& A, const Eigen::VectorXd& B) {
    // 输入验证
    if (A.rows() != A.cols()) {
        throw std::invalid_argument("Matrix A must be square");
    }
    if (A.rows() != B.rows()) {
        throw std::invalid_argument("Matrix A and Vector B must have same number of rows");
    }

    // 转换为稀疏矩阵
    Eigen::SparseMatrix<double> sparseA = A.sparseView();

    // 使用BiCGSTAB求解器
    Eigen::BiCGSTAB<Eigen::SparseMatrix<double>> solver;
    solver.compute(sparseA);

    if (solver.info() != Eigen::Success) {
        throw std::runtime_error("Matrix decomposition failed");
    }

    Eigen::VectorXd X = solver.solve(B);

    if (solver.info() != Eigen::Success) {
        throw std::runtime_error("Solving failed");
    }

    return X;
}

// Pybind11模块定义
PYBIND11_MODULE(solve_KUF, m) {
    m.doc() = "Python module for solving sparse linear system AX=B using Eigen";

    m.def("solveKUF", &solveKUF,
          py::arg("A"), py::arg("B"),
          "Solve the linear system AX=B for sparse matrix A and vector B\n"
          "Args:\n"
          "    A: NxN numpy array (sparse matrix in dense format)\n"
          "    B: Nx1 numpy array\n"
          "Returns:\n"
          "    Solution vector X as numpy array");
}

pybind11支持numpy数组和eigen MatixXd之间的自动转换.

第二步,编写setup.py文件

在setup.py中:

from setuptools import setup, Extension
import pybind11

# 定义扩展模块
ext_modules =Extension(
        'solve_KUF',
        sources=['solve_KUF.cpp'],
        include_dirs=[pybind11.get_include(),
                      'L:\\EF2D\\includes\\eigen-3.4.0'],  # 添加Eigen和pybind11头文件路径
        language='c++',
        extra_compile_args=['--std=c++17', '--O3']  # 优化标志

    )

setup(
    name='solve_KUF',
    version='0.1',
    ext_modules=[ext_modules],
)

第三步,编译

在目录中 执行:

python.exe路径 setup.py build_ext --inplace

如果出现:build文件夹和solve_KUF.cp310-win_amd64.pyd就 说明编译成功.

第四步,测试

import numpy as np
import solve_KUF

# 创建一个稀疏矩阵的密集表示
N = 5
A = np.zeros((N, N))
np.fill_diagonal(A, 2.0)  # 对角线为2
A[0, 1] = 1.0
A[1, 0] = 1.0

# 创建右侧向量
B = np.random.rand(N)

# 求解AX=B
X = solve_KUF.solveKUF(A, B)

print("A:\n", A)
print("\nB:\n", B)
print("\nSolution X:\n", X)
print("\nA @ X (should equal B):\n", A @ X)