bool multiplication with exclusive-or, not or (wit

2019-07-01 12:22发布

问题:

I'm trying to implement hamming error correcting codes, and to do this I need to take a bool Vector (the data) and multiply it with a bool Matrix(hamming generator matrix), performing XOR operations (instead of what looks like OR as Eigen's default bool behavior). An example of what I am doing is found in this simple tutorial: http://michael.dipperstein.com/hamming/

I don't necessarily have to use Eigen, so please feel free to suggest something other than Eigen if you have the solution.

So for example a bit of C++ code that compiles, but does not quite work the right way:

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

using namespace std;
using namespace Eigen;

typedef Eigen::Matrix<bool, 4, 7> Matrix4by7Bool;
typedef Eigen::Matrix<bool, 1, 4> Vector4Bool;
int main()
{
Matrix4by7Bool gm;
gm << 0,1,1,1,0,0,0,
      1,0,1,0,1,0,0,
      1,1,0,0,0,1,0,
      1,1,1,0,0,0,1;

Vector4Bool dm;
dm << 1,0,1,0;

cout << dm * gm;
}

currently results in: 1 1 1 1 0 1 0
but I need: 1 0 1 1 0 1 0

The difference is that the default behavior is to multiply and then OR each multiplication. Since I need XOR instead of OR, wondering what the best way to do this with Eigen is?

Happy to try and elaborate if this does not make sense.

BTW, not sure if it matters but I'm working on a MacBook Air, using G++. Just downloaded Eigen today so its prob the newest available (eigen3)

Thank you,
Keith

UPDATE: Given the accepted solution below, I wanted to repost the correct code as reference for people:

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

using namespace std;
using namespace Eigen;

typedef Eigen::Array<bool, 4, 7> Array4by7Bool;
typedef Eigen::Array<bool, 4, 1> Array1by4Bool;

struct logical_xor {
  bool operator() (bool a, bool b) const
  {
    return a != b;
  }
};

int main()
{
  Array4by7Bool gm;
  gm << 0,1,1,1,0,0,0,
        1,0,1,0,1,0,0,
        1,1,0,0,0,1,0,
        1,1,1,0,0,0,1;

  Array1by4Bool dm;
  dm << 1,0,1,0;

  cout << "result: "  <<  (gm.colwise() * dm).colwise().redux(logical_xor()) << endl;
}

回答1:

You can mimic a matrix_vector product using broadcasting and a partial reduction:

struct logical_xor { bool operator(bool a, bool b) { return a != b; }
result = (gm.array().colwise() * dm.transpose().array()).colwise().redux(logical_xor());

If you declare your variables as Array and dm is already a column array, then this simplifies to:

result = (gm.colwise() * dm).colwise().redux(logical_xor());


回答2:

You can do that. The below is a proof of concept. It contains the minimum you need to make your example compile and give your desired result.

It is probably rather fragile, and it's c&p'ed from other code I had lying around, so it won't earn any points for being pretty or idiomatic.

The basic idea is that you create your own bool type where addition is XOR, and the give the relevant operators and NumTraits you need.

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

using namespace std;
using namespace Eigen;

class mybool {
public:
  bool b;
  mybool() { b = false; }
  mybool(bool b) : b(b) {}
  mybool(int a) : b(a!=0) {}
  mybool operator* (const mybool m) const {return m.b & b;} 
  mybool operator+ (const mybool m) const {return m.b ^ b;} 
  mybool operator+= (const mybool m) {b ^= m.b; return b;}
  friend ostream& operator<<(ostream& os, const mybool& m);
};

ostream& operator<<(ostream& os, const mybool& m) { os << m.b; return os; }

namespace Eigen {
template<> struct NumTraits<mybool>
{
  typedef int Real;
  typedef mybool Nested;
  enum {
    IsComplex = 0,
    IsInteger = 1,
    IsSigned = 0,
    RequireInitialization = 0,
    ReadCost = 1,
    AddCost = 2,
    MulCost = 2
  };
  static Real epsilon() { return 1; }
};
}


typedef Matrix<mybool, 4, 7> Matrix4by7Bool;
typedef Matrix<mybool, 1, 4> Vector4Bool;
int main()
{
  Matrix4by7Bool gm;
  gm << 0,1,1,1,0,0,0,
        1,0,1,0,1,0,0,
        1,1,0,0,0,1,0,
       1,1,1,0,0,0,1;

  Vector4Bool dm;
  dm << 1,0,1,0;

  cout << dm * gm;
}