I'm trying to identify unique arrays by comparing two lists, one which is growing in length. The number of elements in the list grows as 2^n^2
, where n
is the dimension of the array.
I'm not sure how to better optimize this code for speed, but it is very slow for arrays larger than 3x3, i.e. n=4
in the code below. I suspect that the If
and the AppendTo
are slowing things down, and I don't believe I can use ParallelTable
due to the nature of the search.
f[n_, i_] := Partition[IntegerDigits[i, 2, (n*n)], n, n]
g[n_, i_] := {f[n, i], Transpose[f[n, i]], J.f[n, i], Transpose[J.f[n, i]], J.f[n, i].J, Transpose[J.f[n, i].J], f[n, i].J, Transpose[f[n, i].J]}
h[n_, i_] := ContainsAny[uniqueArray, g[n, i]]
m[n_] := Table[If[h[n, i], , uniqueArray = AppendTo[uniqueArray, f[n, i]]], {i, 2^n^2}][[2^n^2]]
n = 2;
J = Reverse[IdentityMatrix[n]];
uniqueArray = {};
m[n]; // AbsoluteTiming
m[1]; // AbsoluteTiming
{0.000346, Null}
m[2]; // AbsoluteTiming
{0.001656, Null}
m[3]; // AbsoluteTiming
{0.061311, Null}
m[4]; // AbsoluteTiming
{169.272, Null}
This question builds on the following: A few tuples at a time?
EDIT Ok, I thought I could reduce the time of this search by doing some sorting before checking for uniqueness. For instance, an binary array with two 1's cannot be the same as an array with with three 1's, i.e. these cannot be the same:
MatrixForm[{{0,0},{1,1}}]
MatrixForm[{{0,1},{1,1}}]
So, it seems reasonable to only compares arrays of the same total. I amended the initial code in the following way:
f[n_, i_] := Partition[IntegerDigits[i, 2, (n*n)], n, n]
m[n_] := Table[
If[
ContainsAny[
uniqueArraySplit[[Total[Flatten[f[n, i]]] + 1]],
{f[n, i],
Transpose[f[n, i]],
J.f[n, i],
Transpose[J.f[n, i]],
J.f[n, i].J,
Transpose[J.f[n, i].J],
f[n, i].J,
Transpose[f[n, i].J]
}
],
Nothing,
AppendTo[uniqueArraySplit[[Total[Flatten[f[n, i]]] + 1]],
f[n, i]]
],
{i, 2^n^2}][[2^n^2]]
n = 4;
J = Reverse[IdentityMatrix[n]];
uniqueArraySplit = Table[{}, {p, n^2 + 1}];
m[n]; // AbsoluteTiming
m[4]; // AbsoluteTiming
{165.308, Null}
Now I'm stumped. I removed two functions, and I removed unnecessary searches, and yet it barely improved the timing... Any help would be greatly appreciated.
n
to get? Even if you'd optimize theTable
calculation to do one iteration per nanosecond,n=8
would take over 500 years. 2^n^2 simply grows very fast. Unless you come up with a different algorithm, anything above n=5 or maybe n=6 will take a very long time. $\endgroup$AppendTo
with anAssociation
, which should make insertion faster $\endgroup$n=6
is essentially impossible. Perhaps there's a better algorithm, yet I haven't been able to think about one. Get the results forn=5
andn=6
would be a victory. Is there a syntax change needed to switchAppendTo
withAssociation
? When I substituted the latter it didn't write anything to the nested list. $\endgroup$n=6
, get a book like "Hackers Delight", translate the transpose/reverse operations to bit-twiddling operations, and learn C. Back-of-the envelope calculation suggests that it should be possible to run this forn=6
in hours. But that it something you'd have to do yourself ;-) $\endgroup$