arma::find_unique 如何确定唯一索引?

How does arma::find_unique determine unique indices?

我正在使用 arma::find_unique,我认为它 return 编辑了向量中每个唯一值第一次出现的索引,但它似乎 return 其他东西。

这是一个玩具函数:

// [[Rcpp::export]]
arma::uvec test(arma::vec& x_) {
  vec x=arma::sort(x_);
  return arma::find_unique(x);
}

如果我 运行 R 中的函数带有一个简单的向量 test(5:1) 我得到一个包含所有索引的向量 0,1,2,3,4 这很有意义,因为每个值都是唯一的。

如果我尝试类似的操作:

set.seed(1991)
var=sample(1:8,20,TRUE)
test(var)

输出:

1,3,6,7,19,12,14,18.

除了第一个之外,所有这些值都有意义。为什么索引 1 处的第一个唯一值不是 0?显然我误解了 arma::find_unique 的意图,所以如果有人能启发我,我将不胜感激。

编辑 我的会话信息

好的,以下是@nrussell 提供的,这个人很了不起,并且在评论中给出了这个“答案”。 (我不值得打勾,也不值得点赞。)

Actually, I'm pretty sure this is all just a misinterpretation of the Armadillo documentation, which never actually guarantees that a stable sort is used, as @Carl was expecting. Underneath, std::sort is being called, which is not guaranteed to be a stable sort by the C++ standard; also stated here:

"The order of equal elements is not guaranteed to be preserved."

我可以演示此 here, replicating the "packet" structure 在犰狳算法中的使用。我的猜测是 libc++(通常由 OS X 使用)确实实现了 std::sort 作为稳定排序,而 libstdc++ 没有。

轮到我了:稳定排序,或维护具有相同键(即值)的记录的相对顺序,是这个问题背后的关键问题。例如,考虑以下内容:

dog car pool dig

稳定 排序的第一个字母排序得到:

car dog dig pool

因为单词“dog”在向量中出现在“dig”之前,因此在输出中它必须出现在“dig”之前。

不稳定 排序的第一个字母排序得到:

car dig dog pool

car dog dig pool

主体与数字相关,因为每个生成的密钥实际上都存在于其他地方。所以,我们有:

2, 3, 2, 4

因此,当找到唯一值时:

2, 3, 4

2 的 id 可以是 0 或 2。

正如@nrussell 所解释的那样,macOS 自 OS X Mavericks (10.9) 默认依赖于 --stdlib=libc++ 而不是传统的 --stdlib=libstdc++ 编译标志。这可能是我无法复制它的原因,因为一种实现选择了稳定性而另一种则没有。

原答案

首先,我无法在 mac 上复制它OS...(见末)

虽然 (@nrussel),但我们似乎能够在 Linux 上重现这一点。这意味着在某些时候,链接代码中存在问题。

其次,arma::find_unique is implemented here using matrix ops with op_find_unique。后者是实现比较器的关键。

因此,简而言之,假设您对向量进行排序并且第一项始终被认为是唯一的,那么应该没有任何可能。

测试函数

#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::uvec test(arma::vec& x_) {
    Rcpp::Rcout << "Input:" << x_.t() << std::endl;
    arma::vec x = arma::sort(x_);
    Rcpp::Rcout << "Sorted:" << x.t() << std::endl;
    arma::uvec o = arma::find_unique(x);
    Rcpp::Rcout << "Indices:" << o.t() << std::endl;
    return o;
}
    
/*** R
set.seed(1991)
(v=sample(1:8,20,TRUE))
## [1] 2 2 1 5 7 6 7 6 4 1 5 3 1 4 4 2 8 7 7 8
sort(v)
## [1] 1 1 1 2 2 2 3 4 4 4 5 5 6 6 7 7 7 7 8 8

test(v)
### Received
##    2.0000   2.0000   1.0000   5.0000   7.0000   6.0000   7.0000   6.0000   4.0000   1.0000   5.0000   3.0000   1.0000   4.0000   4.0000   2.0000   8.0000   7.0000   7.0000   8.0000

### Sorted
## 1.0000   1.0000   1.0000   2.0000   2.0000   2.0000   3.0000   4.0000   4.0000   4.0000   5.0000   5.0000   6.0000   6.0000   7.0000   7.0000   7.0000   7.0000   8.0000   8.0000

### Output
## 0    3    6    7   10   12   14   18
*/