Algorithm 融合元组以找到等价类

Algorithm 融合元组以找到等价类,algorithm,Algorithm,假设我们有一个包含k个元素的有限域D={d1,…dk} 我们考虑d^ n的一个子集,即一组元组< A1,…,A>,AI在D. 我们想用S’2^D^n的子集(紧凑地)表示它,即一组形式为的元组,Ai是D的子集。这意味着对于S’中的任何元组S,Ai的叉积中的所有元素都存在于S中 例如,考虑d={a,b,c},k=3,n=2,元组s=< a,b>+< a,c>+< b,b>+< b,c> 我们可以用S'=来表示S 此单例解决方案也是最小的,S'=+也是一个解决方案,但它更大,因此不太理想 在具体的例

假设我们有一个包含k个元素的有限域D={d1,…dk}

我们考虑d^ n的一个子集,即一组元组< A1,…,A>,AI在D.

我们想用S’2^D^n的子集(紧凑地)表示它,即一组形式为的元组,Ai是D的子集。这意味着对于S’中的任何元组S,Ai的叉积中的所有元素都存在于S中

例如,考虑d={a,b,c},k=3,n=2,元组s=< a,b>+< a,c>+< b,b>+< b,c>

我们可以用S'=来表示S

此单例解决方案也是最小的,S'=+也是一个解决方案,但它更大,因此不太理想

在具体的例子中,我们需要处理一些大小:域D中的k~1000个元素,n10^6

一种天真的方法是首先将S插入S’2^D^n的域,然后使用以下测试,S’中的两个两元组s1、s2可以融合在S’iff中形成一个元组。它们只有一个不同的组成部分

e、 g.
+->(第二个组件不同)

+->(第二个组件不同)

+->(第一个组件不同)

现在可能有几个最小S',我们对找到任何一个都感兴趣,并且某种最小化的近似也可以,只要它们不会给出错误的结果(即,即使S'没有可能的小,但我们得到的结果非常快)

Naive算法必须处理这样一个事实,即任何新引入的“融合”元组都可以与其他元组匹配,因此它在大型输入集上的伸缩性非常差,即使n仍然很低。您需要进行| S | ^2比较以确保收敛,任何时候您融合两个元素,我目前都在重新测试每一对(如何改进?)

很多效率取决于迭代顺序,因此可以选择以某种方式对集合进行排序,或者使用散列进行索引,但我不确定如何做到这一点

命令式伪代码将是理想的,或者指向问题的重新表述的指针,指向我可以运行解算器的东西,将非常有帮助。

下面是一些psuedo(我没有测试过的C代码),它演示了你的s'=+方法。除空间要求外,当对元素使用整数索引时,其可忽略不计;添加和测试元组的总体效率和速度应该非常快。如果你想要一个实用的解决方案,那么你已经有了一个,你只需要使用正确的ADT

ElementType[] domain = new ElementType[]; // a simple array of domain elements
  FillDomain(domain); // insert all domain elements
  SortArray(domain); // sort the domain elements  K log K time
SortedDictionary<int, HashSet<int>> subsets; // int's are index/ref into domain
subsets = new SortedDictionary<int, HashSet<int>>();
//
void AddTuple(SortedDictionary<int, HashSet<int>> tuples, ElementType[] domain, ElementType first, elementType second) {
    int a = BinarySearch(domain, first); // log K time (binary search)
    int b = BinarySearch(domain, second); // log K time (binary search)
    if(tuples.ContainsKey(a)) { // log N time (binary search on sorted keys)
        if(!tuples[a].Contains(b)) { // constant time (hash lookup)
            tuples[a].Add(b); // constant time (hash add)
        }         
    } else { // constant time (instance + hash add)
        tuples[a] = new HashSet<in>();
        tuples[a].Add(b);
    }
}
//
bool ContainsTuple(SortedDictionary<int, HashSet<int>> tuples, ElementType[] domain, ElementType first, ElementType second) {
    int a = BinarySearch(domain, first); // log K time (binary search)
    int b = BinarySearch(domain, second); // log K time (binary search)
    if(tuples.ContainsKey(a)) { // log N time (binary search on sorted keys)
        if(tuples[a].Contains(b)) { // constant time (hash test)
            return true;
        }
    }
    return false;
}
ElementType[]域=新ElementType[];//域元素的简单数组
填充域(域);//插入所有域元素
Sortaray(域);//对域元素进行排序K log K time
分类词典子集;//int是域的索引/引用
子集=新的SortedDictionary();
//
void AddTuple(SortedDictionary元组,ElementType[]域,ElementType第一,ElementType第二){
int a=BinarySearch(域,第一);//记录K次(二进制搜索)
int b=BinarySearch(域,秒);//记录K次(二进制搜索)
if(tuples.ContainsKey(a)){//log N time(对排序键进行二进制搜索)
如果(!tuples[a].包含(b)){//常数时间(哈希查找)
元组[a].添加(b);//常量时间(哈希添加)
}         
}else{//常量时间(实例+哈希添加)
元组[a]=新的HashSet();
元组[a]。添加(b);
}
}
//
bool ContainsTuple(SortedDictionary元组,ElementType[]域,ElementType第一,ElementType第二){
int a=BinarySearch(域,第一);//记录K次(二进制搜索)
int b=BinarySearch(域,秒);//记录K次(二进制搜索)
if(tuples.ContainsKey(a)){//log N time(对排序键进行二进制搜索)
如果(元组[a].包含(b)){//常数时间(哈希测试)
返回true;
}
}
返回false;
}
优化元组子集所节省的空间不会超过优化过程本身的速度。对于大小优化(如果您知道K将小于65536),您可以在SortedDictionary和HashSet中使用短整数而不是整数。但即使是50 mil整数,每32位整数*50 mil~=200 MB也只占用4字节

编辑 下面是另一种方法,通过将元组编码/映射到字符串,您可以利用二进制字符串比较以及UTF-16/UTF-8编码非常节省大小的事实。同样,这仍然无法实现您想要的合并优化,但速度和效率将非常好

下面是一些JavaScript中的快速伪代码

Array.prototype.binarySearch = function(elm) {
  var l = 0, h = this.length - 1, i; 
  while(l <= h) { 
    i = (l + h) >> 1; 
    if(this[i] < elm) l = ++i; 
    else if(this[i] > elm) h = --i; 
    else return i; 
  } 
  return -(++l); 
};
// map your ordered domain elements to characters 
// For example JavaScript's UTF-16 should be fine
// UTF-8 would work as well
var domain = {
  "a": String.fromCharCode(1),
  "b": String.fromCharCode(2),
  "c": String.fromCharCode(3),
  "d": String.fromCharCode(4)
}
var tupleStrings = [];
// map your tuple to the string encoding
function map(tuple) {
  var str = "";
  for(var i=0; i<tuple.length; i++) {
    str += domain[tuple[i]];
  }
  return str;
}
function add(tuple) {
  var str = map(tuple);
  // binary search
  var index = tupleStrings.binarySearch(str);
  if(index < 0) index = ~index;
  // insert depends on tupleString's type implementation
  tupleStrings.splice(index, 0, str);
}
function contains(tuple) {
  var str = map(tuple);
  // binary search 
  return tupleString.binarySearch(str) >= 0;
}

add(["a","b"]);
add(["a","c"]);
add(["b","b"]);
add(["b","c"]);
add(["c","c"]);
add(["d","a"]);
alert(contains(["a","a"]));
alert(contains(["d","a"]));
alert(JSON.stringify(tupleStrings, null, "\n"));
Array.prototype.binarySearch=function(elm){
var l=0,h=this.length-1,i;
而(l>1;
如果(这个[i]elm)h=--i;
否则我会回来;
} 
返回-(++l);
};
//将有序域元素映射到字符
//例如,JavaScript的UTF-16应该可以
//UTF-8也可以
变量域={
“a”:字符串。fromCharCode(1),
“b”:字符串。fromCharCode(2),
“c”:字符串。fromCharCode(3),
“d”:String.fromCharCode(4)
}
var-tupleStrings=[];
//将元组映射到字符串编码
函数映射(元组){
var str=“”;

对于(var i=0;i有趣的问题!这看起来非常类似于在0/1矩阵中找到一组覆盖一组1的矩形的问题,只是“矩形”的定义更宽松。不过,我不确定这是否有用。这个问题相当于;-)。在你的问题中,元组中的任何索引都使用同一个域,而在我的问题中,每个索引的域可能不同,但这只是语义。是的,在我的现实世界问题中,每个元素的域可能不同,我们有多个集合而不是集合,但这些都是无关紧要的次要问题。不幸的是,你的问题的答案是什么TCS上的ion不是很有帮助,我不关心复杂性(高n),我需要一些在实践中有效的东西。而且,我也不关心