【问题标题】:How can I solve the sparse linear system with the coefficients in Z_2?如何用 Z_2 中的系数求解稀疏线性系统?
【发布时间】:2016-06-22 14:23:18
【问题描述】:

我想使用 Eigen 求解系数在 Z_2 中的大型稀疏线性方程组。首先我们尝试了 Boolean 类型,它不起作用,因为在 Boolean 中 1+1=1,但我希望 1+1=0。因此,解决方案可能是一种新的定制标量类型。但它究竟是如何工作的呢?也欢迎其他软件包或软件的一些建议。

【问题讨论】:

  • 用 operator^ 代替 operator+?
  • @lorro 为什么? 1^1=1。
  • @Eric 好的,谢谢。但是如何重载布尔运算符?

标签: c++ linear-algebra eigen finite-field


【解决方案1】:

由于基本类型的运算符不能重载。您需要一个自定义的标量类型。这是告诉您如何执行此操作的基本文档。

http://eigen.tuxfamily.org/dox/TopicCustomizingEigen.html#CustomScalarType

基本上你需要做 3 件事。

  1. 确保类型 T 支持通用运算符(+、-、*、/ 等)
  2. 添加 struct Eigen::NumTraits 的特化
  3. 定义对您的类型有意义的数学函数。这包括标准的,如 sqrt、pow、sin、tan、conj、real、imag 等,以及特定于 Eigen 的 abs2。 (参见文件 Eigen/src/Core/MathFunctions.h)

实际上你只能定义方程求解所需的那些运算符和数学函数。

以上链接提供了adtl::adouble 类型的简单示例。代码很短,因为大部分操作已经定义好。在 Eigen 源目录 unsupported/ 中,还有另一个 3rd-party 类型 mpfr::mpreal 支持。你可以从这个链接开始。

https://eigen.tuxfamily.org/dox/unsupported/group__MPRealSupport__Module.html

在 Eigen 源目录中,这些文件与 mpfr::mpreal 支持相关。它们可能很有用。

./unsupported/Eigen/MPRealSupport ./unsupported/test/mpreal/mpreal.h ./unsupported/test/mpreal_support.cpp


这是 Z_2 中支持矩阵乘法的最小工作示例:

#include <iostream>
#include <Eigen/Eigen>

namespace Z2 {

struct Scalar {
  Scalar() :
      data(0) {
  }
  Scalar(bool x) :
      data(x) {
  }
  bool data;

  inline Scalar operator+=(const Scalar& a) {
    return data ^= a.data;
  }
};

inline Scalar abs(const Scalar& a) {
  return a;
}

inline Scalar operator+(const Scalar& a, const Scalar& b) {
  return a.data ^ b.data;
}

inline Scalar operator*(const Scalar& a, const Scalar& b) {
  return a.data & b.data;
}

template<class E, class CT>
std::basic_ostream<E, CT> &operator <<(std::basic_ostream<E, CT> &os,
                                       const Z2::Scalar &m) {
  return os << m.data;
}

}

namespace Eigen {
// follow all other traits of bool
template<> struct NumTraits<Z2::Scalar> : NumTraits<bool> {
  typedef Z2::Scalar Real;
  typedef typename internal::conditional<sizeof(Z2::Scalar) <= 2, float, double>::type NonInteger;
  typedef Z2::Scalar Nested;
};
}

int main(void) {
  using namespace Eigen;
  Matrix<Z2::Scalar, Dynamic, Dynamic> x(2, 2), y(2, 2), i(2, 2), j(2, 2);
  x.row(0) << 1, 1;
  y.col(0) << 1, 1;
  i.setIdentity();
  j = i.array() + 1;
  std::cout << "x=\n" << x << std::endl;
  std::cout << "y=\n" << y << std::endl;
  std::cout << "i=\n" << i << std::endl;
  std::cout << "j=\n" << j << std::endl;
  std::cout << "x+y=\n" << x + y << std::endl;
  std::cout << "x.*y=\n" << x.array() * y.array() << std::endl;
  std::cout << "y*j=\n" << y * j << std::endl;
  std::cout << "abs(x)=\n" << x.array().abs() << std::endl;
  return 0;
}

结果:

x=
1 1
0 0
y=
1 0
1 0
i=
1 0
0 1
j=
0 1
1 0
x+y=
0 1
1 0
x.*y=
1 0
0 0
y*j=
0 1
0 1
abs(x)=
1 1
0 0

【讨论】:

  • 是的,现在我知道 ^ 是正确的运算符。然而,正如我提到的,我想使用包 Eigen 来解决稀疏线性系统。所以实际上我想先定义一个像 Eigen :: Matrix ( m , n, BOOL) 这样的布尔值矩阵,这个 BOOL 是你说的带有修改运算符的 bool 类型。我不知道如何实现它。
  • @Misery 我明白了。这就是你需要重载的原因。
  • 太棒了。我真的很感激。但是为了解决线性系统,我仍然需要重载很多运算符,例如 -,>,...它们中的大多数都运行良好,除了: 1. 我必须重载一些函数,例如 sqrt,abs,我做到了它像这样:'namespace std{ Z2::Scalar abs(Z2::Scalar& a){ return a.data; } Z2::Scalar sqrt(Z2::Scalar& a){ return a.data; } }' 但是还是不行,说没有匹配的功能。你有什么想法吗?
  • @Misery 查看更新。我修复了NumTraits 中的错误。最好将 abs() 放在命名空间 Z2 中。
  • 现在可以了!我刚刚尝试了一个小矩阵,它给出了正确的答案。现在我只是将除法运算符定义为与乘法相同。我不确定 Eigen 是否会自动判断分母是否为非零。不幸的是,我现在无法支持您的答案。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2015-08-07
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
相关资源
最近更新 更多