我从StackOverflow Post找到了一个powerset函数:
public static T[][] FastPowerSet<T>(T[] seq)
{
var powerSet = new T[1 << seq.Length][];
powerSet[0] = new T[0]; // starting only with empty set
for (int i = 0; i < seq.Length; i++)
{
var cur = seq[i];
int count = 1 << i; // doubling list each time
for (int j = 0; j < count; j++)
{
var source = powerSet[j];
var destination = powerSet[count + j] = new T[source.Length + 1];
for (int q = 0; q < source.Length; q++)
destination[q] = source[q];
destination[source.Length] = cur;
}
}
return powerSet;
}
但我对整个powerset并不感兴趣。它使用太多内存,仅限于整数的maxvalue,并且耗时太长。想象一下,我有一个无限长度的字符串,我可以使用它,我无法存储它。我只希望10个值位于通过powerset的25%的位置。
例如,如果我向powerset函数发送一个包含22个值的数组:
var toTakePowerSetOf = {3,-3,39,-39,392,-392,3920,-3920, 9, -9, 92, -92, 920, -920, 9203, -9203, 2, -2, 20, -20, 203, -203}
我通常会得到一个4194304元素的powerset。但我只关心索引@ 1049089/4194304的值{3,-9,203}。如何编辑快速powerset函数以使用无限精度,转到特定索引,并且只存储~10个值。
索引计算为2 ^ n / 4,其中n是toTakePowerSetOf中元素的数量。对于我的例子,有22个元素:2 ^ 22 = 4194304。 4194304/4 = 1048576。我寻求的实际价值是1049089,距离513。在我的问题中,我说我想检查周围的10个值,但我想我应该说我想检查一下513左右的数字值(.0122%)。
我试图使用的这个算法可能会导致更快的因子分解,但我需要弄清楚因为这些因素总是出现在通过powerset的25%附近。它可能没有多大意义,但如果它有效,我会与你分享,我们可以解决P = NP lol
答案 0 :(得分:2)
给定的FastPowerSet算法的问题是您需要计算新的前面的所有功率集。另一个Algo是Wikipedia page的权力集。
这是一个简短的实现:
public static T[][] FastPowerSet2<T>(T[] seq)
{
var powerSet = new T[1 << seq.Length][];
powerSet[0] = new T[0]; // starting only with empty set
for (uint i = 1; i < powerSet.Length; i++)
{
powerSet[i] = PowerSetItem(i, seq, powerSet.Length);
}
return powerSet;
}
private static T[] PowerSetItemBig<T>(BigInteger neededSetIndex, T[] p)
{
byte[] neededSetBytes = neededSetIndex.ToByteArray();
BitArray b = new BitArray(neededSetBytes);
return p.Take(b.Length).Where((s, j) => b[j]).ToArray();
}
private static T[] PowerSetItem<T>(uint powersetIndex, T[] sequence, int powersetLength)
{
BitArray b = new BitArray(BitConverter.GetBytes(powersetIndex));
if (b.Length < powersetLength)
{
var prefix = new BitArray(powersetLength - b.Length);
b = Append(prefix, b);
}
return sequence.Where((s, j) => b[j]).ToArray();
}
public static BitArray Append(BitArray current, BitArray after)
{
var bools = new bool[current.Count + after.Count];
current.CopyTo(bools, 0);
after.CopyTo(bools, current.Count);
return new BitArray(bools);
}
使用这些功能,您还可以使用以下命令生成特定的powerset项目:
int[] P = { 3, -3, 39, -39, 392, -392, 3920, -3920, 9, -9, 92, -92, 920, -920, 9203, -9203, 2, -2, 20, -20, 203, -203 };
var p1049089 = PowerSetItem(1049089, P, (2^P.Length));
Console.WriteLine(string.Join(", ", p1049089));
BigInteger版本与
一起使用var p1049089 = PowerSetItemBig(new BigInteger(1049089), P);
注意:我使用linq获取了一些快捷方式,并省略了对传入数组的一些绑定检查,但这适用于此特定用例
答案 1 :(得分:1)
我的解决方案可以获得25%左右的数据集。两者都在该索引之后和该索引之前设置。
我的解决方案不仅限于整数大小,也不使用位数组。
它将处理极长的序列。所需要的只是上下文大小(在你的情况下为513)并不是非常大。
以下是代码的解释:
所以,你想看到一些前向和后向“背景”围绕25%指数的权力集(我称之为“中心”)。
25%索引处的集合由单个项目组成。这是因为2 ^ n / 4 = 1&lt;&lt; (N-1-2) 0000000000100 .....
当我们从这个集合/数字前进时,我们基本上重复相同的前513个电源集,但包括中心项目:
0000000000100..... = +0 context = powerSet[0] U { seq[central] }
1000000000100..... = +1 context = powerSet[1] U { seq[central] }
0100000000100..... = +2 context = powerSet[2] U { seq[central] }
1100000000100..... = +3 context = powerSet[3] U { seq[central] }
0010000000100..... = +4 context = powerSet[4] U { seq[central] }
当我们倒退时,数字表现得有些相似,但这些位看起来相反:
1111111111000..... = -1 context = { seq[0], seq[1], ..., seq[central - 1] } \ powerSet[0]
0111111111000..... = -2 context = { seq[0], seq[1], ..., seq[central - 1] } \ powerSet[1]
1011111111000..... = -3 context = { seq[0], seq[1], ..., seq[central - 1] } \ powerSet[2]
0011111111000..... = -4 context = { seq[0], seq[1], ..., seq[central - 1] } \ powerSet[3]
1101111111000..... = -5 context = { seq[0], seq[1], ..., seq[central - 1] } \ powerSet[4]
通过将后向上下文与前向上下文相结合,我们得到了完整的[-514 .. +513]上下文
以下是解决问题的代码:
public static T[][] PartialPowerSet<T>(T[] seq, int forwardContextSize) {
int n = seq.Length;
int centralItemIndex = n - 2; //=log2(2^n/4)
int numberOfItemsForContext = (int)Math.Ceiling(Math.Log(forwardContextSize, 2));
var smallContextSeq = seq.Take(numberOfItemsForContext).ToArray();
var smallContextPowerSet = FastPowerSet(smallContextSeq);
smallContextPowerSet = smallContextPowerSet.Take(forwardContextSize + 1).ToArray();
var forwardContextTemplateItems = new[] { seq[centralItemIndex] }; //To get forward context we're adding (union) the small context items
var forwardContextItems = smallContextPowerSet.Select(s => s.Concat(forwardContextTemplateItems).ToArray());
var backwardContextTemplateItems = seq.Take(centralItemIndex - 1).ToList(); //To get backward context we're removing (minus) the small context items from the set of all items up to, but not including the central item
var backwardContextItems = smallContextPowerSet.Reverse().Select(s => backwardContextTemplateItems.Except(s).ToArray()); //Getting sets for c-513, c-512, ...., c-1. That's why we reverse the order of the smallContextPowerSet.
return backwardContextItems.Concat(forwardContextItems).ToArray();
}
static void Main(string[] args) {
var toTakePowerSetOf = new[] { 3, -3, 39, -39, 392, -392, 3920, -3920, 9, -9, 92, -92, 920, -920, 9203, -9203, 2, -2, 20, -20, 203, -203 };
var res = PartialPowerSet(toTakePowerSetOf, 513);
Console.WriteLine(string.Join(",", res[513 + 1 + 513])); //Prints "3,-9,203"
}
打印3,-9,203