代码之家  ›  专栏  ›  技术社区  ›  Mankka

什么是Matlab重复的特征等价物?

  •  2
  • Mankka  · 技术社区  · 6 年前

    在Matlab中,两者都有 repmat repelem . 对于矩阵 x1 x2 大小 [d, n1] [d, n2] ,您可以在Matlab中执行此操作:

    n1 = size(x1, 2);
    n2 = size(x2, 2);
    
    M = repmat(x1, 1, n2) - repelem(x2, 1, n1);
    

    TL;DR:Variant 2是最好的,但它取决于编译器和其他东西。

    int d = x1.rows();
    int n1 = x1.cols();
    int n2 = x2.cols();
    
    Eigen::MatrixXd M(d, n1*n2);
    
    // Variant 1:
    int idx = 0;
    for (int c = 0; c != n2; c++) {
      for (int r = 0; r != n1; r++) {
        M.col(idx) = x1.col(r) - x2.col(c);
        idx += 1;
      }
    }
    
    // Variant 2:
    for (int c = 0, idx = 0; c != n2; c += 1, idx += n1)
      M.block(0, idx, d, n1) = x1.colwise() - x2.col(c);
    
    // Variant 3:
    M = - x2.replicate(n1, 1);
    M.resize(d, n1*n2);
    M += x1.replicate(1, n2);
    
    // Variant 5:
    M = x1.rowwise().replicate(n2) - x2(all,VectorXi::LinSpaced(n1*n2,0,n2-1));
    

    以下是我目前的时间安排,完整代码见下文。Matlab时序是多线程和单线程MATLAB R2017B.用C++编译的版本 -O3 -DNDEBUG -march=native -mtune=native i5-6500 ,所以我有 AVX .

                   time in seconds
    Code         gcc-7  gcc-8 clang-6
    -----------------------------------
    Matlab mt  51
    Matlab st  84
    V. 1           38    37     57
    V. 2           36    34     23
    V. 3          598   599    187
    V. 5           94   172    107
    

    Matlab代码:

    ds = 1:10;
    n1s = 5:5:500;
    n2s = 5:5:500;
    
    z1 = randn(max(ds), max(n1s));
    z2 = randn(max(ds), max(n2s));
    
    tic;
    s = 0;
    for idx = 1:numel(ds)
        for jdx = 1:numel(n1s)
            for kdx = 1:numel(n2s)
                K = MFdiff(z1(1:ds(idx), 1:n1s(jdx)),...
                    z2(1:ds(idx), 1:n2s(kdx)));
                s = s + K(1,1);
            end
        end
    end
    toc
    

    C++代码:

    #include <iostream>
    #include <Eigen/Dense>
    
    using namespace Eigen;
    
    template <typename Derived1, typename Derived2>
    MatrixXd MFdiff1(
      DenseBase<Derived1> const & x1,
      DenseBase<Derived2> const & x2)
    {
      int d = x1.rows();
      int n1 = x1.cols();
      int n2 = x2.cols();
    
      MatrixXd out(d, n1*n2);
    
      int idx = 0;
      for (int c = 0; c != n2; c++) {
        for (int r = 0; r != n1; r++) {
          out.col(idx) = x1.col(r) - x2.col(c);
          idx += 1;
        }
      }
    
      return out;
    }
    
    template <typename Derived1, typename Derived2>
    MatrixXd MFdiff2(
      DenseBase<Derived1> const & x1,
      DenseBase<Derived2> const & x2)
    {
      int d = x1.rows();
      int n1 = x1.cols();
      int n2 = x2.cols();
    
      MatrixXd out(d, n1*n2);
    
      for (int c = 0, idx = 0; c != n2; c+=1, idx += n1)
        out.block(0, idx, d, n1) = x1.colwise() - x2.col(c);
    
      return out;
    }
    
    template <typename Derived1, typename Derived2>
    MatrixXd MFdiff3(
      DenseBase<Derived1> const & x1,
      DenseBase<Derived2> const & x2)
    {
      int d = x1.rows();
      int n1 = x1.cols();
      int n2 = x2.cols();
    
      MatrixXd out;
      out = - x2.replicate(n1, 1);
      out.resize(d, n1*n2);
      out += x1.replicate(1, n2);
    
      return out;
    }
    
    template <typename Derived1, typename Derived2>
    MatrixXd MFdiff5(
      DenseBase<Derived1> const & x1,
      DenseBase<Derived2> const & x2)
    {
      int n1 = x1.cols();
      int n2 = x2.cols();
    
      return x1.rowwise().replicate(n2) - x2(all,VectorXi::LinSpaced(n1*n2,0,n2-1));
    }
    
    double test(VectorXi const & ds,
          VectorXi const & n1s,
          VectorXi const & n2s)
    {
      MatrixXd z1 = MatrixXd::Random(ds.maxCoeff(), n1s.maxCoeff());
      MatrixXd z2 = MatrixXd::Random(ds.maxCoeff(), n2s.maxCoeff());
    
      double s = 0;
      for (int idx = 0; idx!=ds.rows(); idx++) {
        for (int jdx = 0; jdx!=n1s.rows(); jdx++) {
          for (int kdx = 0; kdx!=n2s.rows(); kdx++) {
            MatrixXd K = MFdiff5(z1.block(0, 0, ds(idx), n1s(jdx)),
                     z2.block(0, 0, ds(idx), n2s(kdx)));
            s += K(0,0);
          }
        }
      }
    
      return s;
    }  
    
    int main() {
      VectorXi ds = VectorXi::LinSpaced(10, 1, 10);
      VectorXi n1s = VectorXi::LinSpaced(100, 5, 500);
      VectorXi n2s = VectorXi::LinSpaced(100, 5, 500);
    
      std::cout << test(ds, n1s, n2s) << '\n';
    }
    
    1 回复  |  直到 6 年前
        1
  •  4
  •   ggael    6 年前

    使用Eigen的头,你可以写:

    M = x1.rowwise().replicate(n2) - x2(Eigen::all,VectorXi::LinSpaced(n1*n2,0,n2-1));
    

    独立基准( BenchTimer.h -O3 -DNDEBUG 与gcc 7和clang 6一起:

    #include <iostream>
    #include <Eigen/Dense>
    #include <bench/BenchTimer.h>
    using namespace Eigen;
    using namespace std;
    
    EIGEN_DONT_INLINE
    void foo1(const MatrixXd& x1, const MatrixXd& x2, MatrixXd& M)
    {
      int d = x1.rows();
      int n1 = x1.cols();
      int n2 = x2.cols();
    
      int idx = 0;
      for (int c = 0; c != n2; c++) {
        M.block(0, idx, d, n1) = x1.colwise() - x2.col(c);
        idx += n1;
      }
    }
    
    EIGEN_DONT_INLINE
    void foo2(const MatrixXd& x1, const MatrixXd& x2, MatrixXd& M)
    {
      int n1 = x1.cols();
      int n2 = x2.cols();
    
      M = x1.rowwise().replicate(n2) - x2(all,VectorXi::LinSpaced(n1*n2,0,n2-1));
    }
    
    int main()
    {
      int tries = 2;
      int rep = 1;
    
      int d = 100;
      int n1 = 100;
      int n2 = 100;
    
      MatrixXd x1(d,n1); x1.setRandom();
      MatrixXd x2(d,n2); x2.setRandom();
      MatrixXd M(d, n1*n2);
    
      BenchTimer t;
      BENCH(t, tries, rep, foo1(x1, x2, M));
      std::cout << "Time: " << t.best() << "s" << std::endl;
    
      BENCH(t, tries, rep, foo2(x1, x2, M));
      std::cout << "Time: " << t.best() << "s" << std::endl;
    }