Easy way to populate this matrix? - matrix

I would like to populate an n * n (n being odd) matrix in the following way:
_ _ _ 23 22 21 20
_ _ 24 10 9 8 37
_ 25 11 3 2 19 36
26 12 4 1 7 18 35
27 13 5 6 17 34 _
28 14 15 16 33 _ _
29 30 31 32 _ _ _
What is an easy way to do this using Mathematica?

With this helper function:
Clear[makeSteps];
makeSteps[0] = {};
makeSteps[m_Integer?Positive] :=
Most#Flatten[
Table[#, {m}] & /# {{-1, 0}, {-1, 1}, {0, 1}, {1, 0}, {1, -1}, {0, -1}}, 1];
We can construct the matrix as
constructMatrix[n_Integer?OddQ] :=
Module[{cycles, positions},
cycles = (n+1)/2;
positions =
Flatten[FoldList[Plus, cycles + {#, -#}, makeSteps[#]] & /#
Range[0, cycles - 1], 1];
SparseArray[Reverse[positions, {2}] -> Range[Length[positions]]]];
To get the matrix you described, use
constructMatrix[7] // MatrixForm
The idea behind this is to examine the pattern that the positions of consecutive numbers 1.. follow. You can see that these form the cycles. The zeroth cycle is trivial - contains a number 1 at position {0,0} (if we count positions from the center). The next cycle is formed by taking the first number (2) at position {1,-1} and adding to it one by one the following steps: {0, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 0} (as we move around the center). The second cycle is similar, but we have to start with {2,-2}, repeat each of the previous steps twice, and add the sixth step (going up), repeated only once: {0, -1}. The third cycle is analogous: start with {3,-3}, repeat all the steps 3 times, except {0,-1} which is repeated only twice. The auxiliary function makeSteps automates the process. In the main function then, we have to collect all positions together, and then add to them {cycles, cycles} since they were counted from the center, which has a position {cycles,cycles}. Finally, we construct the SparseArray out of these positions.

I don't know the Mathematica syntax but I guess you could use an algorithm like this:
start in the middle of the matrix
enter a 1 into the middle
go up-right (y-1 / x+1)
set integer iter=1
set integer num=2
while cursor is in matrix repeat:
enter num in current field
increase num by 1
repeat iter times:
go left (x-1 / y)
enter num in current field
increase num by 1
repeat iter times:
go down-left (x-1 / y+1)
enter num in current field
increase num by 1
repeat iter times:
go down (x / y+1)
enter num in current field
increase num by 1
repeat iter times:
go right (x+1 / y)
enter num in current field
increase num by 1
repeat iter times:
go up-right (x+1 / y-1)
enter num in current field
increase num by 1
repeat iter-1 times:
go up (x / y-1)
enter num in current field
increase num by 1
go up-up-right (y-2 / x+1)
increase iter by 1
you can also pretty easily convert this algorithm into a functional version or into a tail-recursion.
Well, you will have to check in the while loop if you aren't out of bounds as well. If n is odd then you can just count num up while:
m = floor(n/2)
num <= n*n - (m+m*m)
I'm pretty sure that there's a simpler algorithm but that's the most intuitive one to me.

The magic numbers on the diagonal starting at 1 and going up right can be arrived at from
f[n_] := 2 Sum[2 m - 1, {m, 1, n}] + UnitStep[n - 3] Sum[2 m, {m, 1, n - 2}]
In := f#Range#5
Out := {2, 8, 20, 38, 62}
With this it should be easy to set up a SparseArray. I'll play around with it a bit and see how hard that is.

First version:
i = 10;
a = b = c = Array[0 &, {2 (2 i + 1), 2 (2 i + 1)}];
f[n_] := 3*n*(n + 1) + 1;
k = f[i - 2];
p[i_Integer] :=
ToRules#Reduce[
-x + y < i - 1 && -x + y > -i + 1 &&
(2 i + 1 - x)^2 + (2 i + 1 - y)^2 <= 2 i i - 2 &&
3 i - 1 > x > i + 1 &&
3 i - 1 > y > i + 1, {x, y}, Integers];
((a[[Sequence ## #]] = 1) & /# ({x, y} /. {p[i]}));
((a[[Sequence ## (# + {2, 2})]] = 0) & /# ({x, y} /. {p[i - 1]}));
(b[[Sequence ## #]] = k--)&/#((# + 2 i {1, 1}) &/# (SortBy[(# - 2 i {1, 1}) &/#
Position[a, 1],
N#(Mod[-10^-9 - Pi/4 + ArcTan[Sequence ## #], 2 Pi]) &]));
c = Table[b[[2 (2 i + 1) - j, k]], {j, 2 (2 i + 1) - 1},
{k, 2 (2 i + 1) - 1}];
MatrixPlot[c]
Edit
A better one:
genMat[m_] := Module[{f, k, k1, i, n, a = {{1}}},
f[n_] := 3*n*(n + 1) + 1;
For[n = 1, n <= m, n++,
a = ArrayPad[a, 1];
k1 = (f[n - 1] + (k = f[n]) + 2)/2 - 1;
For[i = 2, i <= n + 1, i++, a[[i, 2n + 1]] = k--; a[[2-i+2 n, 1]] = k1--];
For[i = n + 2, i <= 2 n + 1, i++, a[[i, 3n+2-i]] = k--; a[[-i,i-n]] = k1--];
For[i = n, i >= 1, i--, a[[2n+1, i]] = k--;a[[1, -i + 2 n + 2]] = k1--];
];
Return#MatrixForm[a];
]
genMat[5]

A partial solution, using image procssing:
Image /# (Differences#(ImageData /#
NestList[
Fold[ImageAdd,
p = #, (HitMissTransform[p, #, Padding -> 0] & /#
{{{1}, {-1}},
{{-1}, {-1}, {1}},
{{1, -1, -1}},
{{-1, -1, 1}},
{{-1, -1, -1, -1}, {-1, -1, -1, -1}, {1, 1, -1, -1}},
{{-1, -1, -1, 1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}}})] &, img, 4]))

Related

convert a number to a variable base in mathematica

let n be an integer and A = {2,3,...,10} and I want to do as follows:
divide n to 2, so there is a reminder r2 and a quotient q2.
divide q2 to 3, so there is a reminder r3 and a quotient q3.
we repeat this until the quotient is less than the next number.
write together the last quotient with the previous reminders.
For example n=45
45/2 ....... r_2=1, q_2=22
22/3 ....... r_3=1, q_3=7
7/4 ....... r_4=3, q_4=1
since q4 = 1 is less than the next number i.e. 5, we break.
the result is q4r4r3r2 where it is equal to 1311.
Thank you for your help.
I did this but it does not work
n = 45;
i = 2;
list = {Mod[n, i]};
While[Quotient[n, i] >= i + 1, n == Quotient[n, i]; i++;
AppendTo[list, Mod[n, i]];
If[Quotient[n, i] < i + 1, Break[]]; AppendTo[list, Quotient[n, i]]];
list
Row[Reverse[list]]
which gives
{1, 0, 15, 1, 11, 0, 9, 3, 7, 3}
Row[{3, 7, 3, 9, 0, 11, 1, 15, 0, 1}]
where it is not my desired result.
This is the code:
A = Table[i, {i, 2, 10}]; (* array of numbers *)
n = 45; (* initial value *)
ans = {}; (* future answer which is now empty list *)
For[i = 1, i <= Length[A], i++, (* looping over A *)
If[n < A[[i]], (* exit condition *)
ans = Append[ans, n]; (* appending last n when exit *)
Break[]
];
qr = QuotientRemainder[n, A[[i]]]; (* calculating both quotient and reminder *)
ans = Append[ans, qr[[2]]]; (* adding second member to the answer *)
Print[qr]; (* printing *)
n = qr[[1]]; (* using first member as new n to process *)
];
ans (* printing result in Mathematica manner *)
It gives
{1, 1, 3, 1}
You might use something like this:
f[n_Integer] :=
NestWhileList[
{QuotientRemainder[#[[1, 1]], #[[2]] + 1], #[[2]] + 1} &,
{{n}, 1},
#[[1, 1]] != 0 &
] // Rest
f[45]
{{{22, 1}, 2}, {{7, 1}, 3}, {{1, 3}, 4}, {{0, 1}, 5}}
You can use Part to get whatever bits of the output you desire.
Here's a somewhat more advanced way if you can handle the syntax:
f2[n_Integer] := Reap[f2[{n, 0}, 2]][[2, 1, 2 ;;]] // Reverse
f2[{q_, r_}, i_] := f2[Sow # r; QuotientRemainder[q, i], i + 1]
f2[{0, r_}, i_] := Sow # r
f2[45]
{1, 3, 1, 1}

Reducing length of list with Total and a threshold parameter

I'm looking for a way to reduce the length of a huge list with the Total function and a threshold parameter. I would like to avoid the use of For and If (coming from old habits).
Example :
List that I want to "reduce" :{1,5,3,8,11,3,4} with a threshold of 5.
Output that I want : {6,11,11,7}
That means that I use the Total function on the first parts of the list and look if the result of this function is higher than my threshold. If so, I use the result of the Total function and go to the next part of the list.
Another example is {1,1,1,1,1} with a threshold of 5. Result should be {5}.
Thanks!
EDIT : it is working but it is pretty slow. Any ideas in order to be faster?
EDIT 2 : the loop stuff (quit simple and not smart)
For[i = 1, i < Length[mylist] + 1, i++,
sum = sum + mylist[[i]];
If[sum > Threshold ,
result = Append[result , sum]; sum = 0; ]; ];
EDIT 3 : I have now a new thing to do.
I have to work now with a 2D list like {{1,2}{4,9}{1,3}{0,5}{7,3}}
It is more or less the same idea but the 1st and 2nd part of the list have to be higher than the thresold stuff (both of them).
Example : If lst[[1]] and lst[[2]] > threshold do the summuation for each part of the 2D list. I tried to adapt the f2 function from Mr.Wizard for this case but I didn't succeed. If it is easier, I can provide 2 independant lists and work with this input f3[lst1_,lst2_,thres_]:=
Reap[Sow#Fold[If[Element of the lst1 > thr && Element of the lst2, Sow##; #2, # + #2] &, 0, lst1]][[2, 1]] for example.
EDIT 4 :
You are right, it is not really clear. But the use of the Min## > thr statement is working perfectly.
Old code (ugly and not smart at all):
sumP = 0;
resP = {};
sumU = 0;
resU = {};
For[i = 1, i < Length[list1 + 1, i++,
sumP = sumP + list1[[i]];
sumU = sumU + list2[[i]];
If[sumP > 5 && sumU > 5 ,
resP = Append[resP, sumP]; sumP = 0;
resU = Append[resU, sumU]; sumU = 0;
];
]
NEW fast by Mr.Wizard :
f6[lst_, thr_] :=
Reap[Sow#Fold[If[Min## > thr , Sow##1; #2, #1 + #2] &, 0, lst]][[2,
1]]
That ~40times faster. Thanks a lot.
Thread[{resP, resU}] == f6[Thread[{list1,list2}], 5] True
I recommend using Fold for this kind of operation, combined with either linked lists or Sow and Reap to accumulate results. Append is slow because lists in Mathematica are arrays and must be reallocated every time an element is appended.
Starting with:
lst = {2, 6, 4, 4, 1, 3, 1, 2, 4, 1, 2, 4, 0, 7, 4};
Here is the linked-list version:
Flatten # Fold[If[Last## > 5, {#, #2}, {First##, Last## + #2}] &, {{}, 0}, lst]
{8, 8, 7, 7, 11, 4}
This is what the output looks like before Flatten:
{{{{{{{}, 8}, 8}, 7}, 7}, 11}, 4}
Here is the method using Sow and Reap:
Reap[Sow # Fold[If[# > 5, Sow##; #2, # + #2] &, 0, lst]][[2, 1]]
{8, 8, 7, 7, 11, 4}
A similar method applied to other problems: (1) (2)
The Sow # on the outside of Fold effectively appends the last element of the sequence which would otherwise be dropped by the algorithm.
Here are the methods packaged as functions, along with george's for easy comparison:
f1[lst_, thr_] :=
Flatten # Fold[If[Last## > thr, {#, #2}, {First##, Last## + #2}] &, {{}, 0}, lst]
f2[lst_, thr_] :=
Reap[Sow#Fold[If[# > thr, Sow##; #2, # + #2] &, 0, lst]][[2, 1]]
george[t_, thresh_] := Module[{i = 0, s},
Reap[While[i < Length[t], s = 0;
While[++i <= Length[t] && (s += t[[i]]) < thresh]; Sow[s]]][[2, 1]]
]
Timings:
big = RandomInteger[9, 500000];
george[big, 5] // Timing // First
1.279
f1[big, 5] // Timing // First
f2[big, 5] // Timing // First
0.593
0.468
Here is the obvious approach which is oh 300x faster.. Pretty isn't always best.
t = Random[Integer, 10] & /# Range[2000];
threshold = 4;
Timing[
i = 0;
t0 = Reap[
While[i < Length[t], s = 0;
While[++i <= Length[t] && (s += t[[i]]) < threshold ];
Sow[s]]][[2, 1]]][[1]]
Total[t] == Total[t0]
Timing[ t1 =
t //. {a___, b_ /; b < threshold, c_, d___} -> {a, b + c, d} ][[1]]
t1 == t0
I interpret your requirement as:
if an element in the list is less than the threshold value, add it to the next element in the list;
repeat this process until the list no longer changes.
So, for the threshold 5 and the input list {1,5,3,8,11,3,4} you'ld get
{6,3,8,11,3,4}
{6,11,11,3,4}
{6,11,11,7}
EDIT
I've now tested this solution to your problem ...
Implement the operation by using a replacement rule:
myList = {1,5,3,8,11,3,4}
threshold = 5
mylist = mylist //. {a___, b_ /; b < threshold, c_, d___} :> {a, b+c, d}
Note the use of ReplaceRepeated (symbolification //.).

Smooth connection between piecewise parts

Example piecewise wise function:
f[x_]:=Piecewise[{{x^2, 0<x<1-epsilon},{x,1<x<2-epsilon},{2,x>2}}]
Is there a way to connect these parts in interval epsilon, so I get a smooth function?
EDIT: By smooth, I don't mean it needs to be derivable in point of connection, just that in some numerical work it looks like a "natural" connection.
EDIT2:
Two black circles represent the points where lies the problem. I'd like it to look like a derivable function (although it doesn't need to be in rigor mathematical sense, but I don't want these two spikes). Red circle represents the part where it looks good.
What I could do is do this by nonlinear fitting the [x-epsilon, x+epsilon], but I was hoping that there was an easier way with piecewise function.
At first, given a function we should define it precisely on the whole range {x,0,2}, ie. its values on ranges 1-epsilon <= x < 1 and 2 - epsilon <= x < 2.
The easiest way is to define f1[x] piecewise linear on the both ranges, however the resulting function wouldn't be differentiable on the gluing points, and it would involve spikes.
To prevent such a situation we should choose (in this case) at least third order polynomials there:
P[x_] := a x^3 + b x^2 + c x + d
and glue them together with f[x] assuming "gluing conditions" (equality of functions at given points as well as of their first derivatives) ie. solve resulting equations :
W[x_, eps_]:= P[x]//. Flatten#Solve[{#^2 == P[#],
1 == P[1],
2# == 3a#^2 +2b# +c,
1 == 3a +2b +c}, {a, b, c, d}]&#(1-eps)
Z[x_, eps_]:= P[x]//. Flatten#Solve[{# == P[#],
2 == P[2],
1 == 3a#^2 +2b# +c,
0 == 12a +4b +c}, {a, b, c, d}]&#(2-eps)
To visualise the resuls we can take advantege of Manipulate :
f1[x_, eps_]:= Piecewise[{{x^2, 0 < x < 1 -eps}, {W[x, eps], 1 -eps <= x < 1},
{ x , 1 <= x < 2 -eps}, {Z[x, eps], 2 -eps <= x < 2},
{ 2 , x >=2}}];
Manipulate[ Plot[f1[x, eps], {x, 0, 2.3},
PlotRange -> {0, 2.3}, ImageSize->{650,650}]
//Quiet, {eps, 0, 1}]
Depending on epsilon > 0 we get differentiable functions f1, while for epsilon = 0 f1 is not differentiable at two points.
Plot[f1[x, eps]/. eps -> .4, {x, 0, 2.3}, PlotRange -> {0, 2.3},
ImageSize -> {500, 500}, PlotStyle -> {Blue, Thick}]
If we wanted f1 to be a smooth function (infinitely differentiable) we should play around defining f1 in range [1 - epsilon <= x < 1) with a transcendental function, something like for example Exp[1/(x-1)] etc.
You could do a gradually change between the functions that define the begin and end point of the interval. Below I do this by shifting the weight in the weighted sum of these functions depending on the position in the interval:
ClearAll[f]
epsilon = 0.1;
f[x_] :=
Piecewise[
{
{x^2, 0 < x < 1 - epsilon},
{Rescale[x, {1 - epsilon, 1}, {1, 0}] x^2 + Rescale[x, {1 - epsilon, 1}, {0, 1}] x,
1 - epsilon <= x <= 1},
{x, 1 < x < 2 - epsilon},
{Rescale[x, {2 - epsilon, 2}, {1, 0}] x + Rescale[x, {2 - epsilon, 2}, {0, 1}] 2,
2 - epsilon <= x <= 2},
{2, x > 2}
}
]
Plot[f[x], {x, 0, 2.5}]
I am not sure I understand your question, but from what I gather here is an idea
ClearAll[f]
e = 0.1
f[x_] := Piecewise[{{x^2, 0 < x < 1 - e}, {whatEver,
1 - e <= x <= 1 + e}, {x, 1 + e < x < 2}, {2, x > 2}}, error]
f[1] the gives whatEver.

How to make code for sum of 2 integrals in Mathematica

I am trying to quickly solve the following problem:
f[r_] := Sum[(((-1)^n (2 r - 2 n - 7)!!)/(2^n n! (r - 2 n - 1)!))
* x^(r - 2*n - 1),
{n, 0, r/2}];
Nw := Transpose[Table[f[j], {i, 1}, {j, 5, 200, 1}]];
X1 = Integrate[Nw . Transpose[Nw], {x, -1, 1}]
I can get the answer quickly with this code:
$starttime = AbsoluteTime[]; Quiet[LaunchKernels[]];
DIM = 50;
Print["$Version = ", $Version, " ||| ",
"Number of Kernels : ", Length[Kernels[]]];
Nw = Transpose[Table[f[j], {i, 1}, {j, 5, DIM, 1}]];
nw2 = Nw.Transpose[Nw];
Round[First[AbsoluteTiming[nw3 = ParallelMap[Expand, nw2]; ]]]
intrule = (pol_Plus)?(PolynomialQ[#1, x]&) :>
(Select[pol, !FreeQ[#1, x] & ] /.
x^(n_.) /; n > -1 :> ((-1)^n + 1)/(n + 1)) + 2*(pol /. x -> 0)]);
Round[First[AbsoluteTiming[X1 = ParallelTable[row /. intrule, {row, nw3}]; ]]]
X1
Print["overall time needed in seconds: ", Round[AbsoluteTime[] - $starttime]];
But how can I manage this code if I need to solve the following problem, where a and b are known constants?
X1 = a Integrate[Nw.Transpose[Nw], {x, -1, 0.235}]
+ b Integrate[Nw.Transpose[Nw], {x, 0.235,1}];
Here's a simple function to do definite integrals of polynomials
polyIntegrate[expr_List, {x_, x0_, x1_}] := polyIntegrate[#, {x, x0, x1}]&/#expr
polyIntegrate[expr_, {x_, x0_, x1_}] := Check[Total[#
Table[(x1^(1 + n) - x0^(1 + n))/(1 + n), {n, 0, Length[#] - 1}]
]&[CoefficientList[expr, x]], $Failed, {General::poly}]
On its range of applicability, this is about 100 times faster than using Integrate. This should be fast enough for your problem. If not, then it could be parallelized.
f[r_] := Sum[(((-1)^n*(2*r - 2*n - 7)!!)/(2^n*n!*(r - 2*n - 1)!))*
x^(r - 2*n - 1), {n, 0, r/2}];
Nw = Transpose[Table[f[j], {i, 1}, {j, 5, 50, 1}]];
a*polyIntegrate[Nw.Transpose[Nw], {x, -1, 0.235}] +
b*polyIntegrate[Nw.Transpose[Nw], {x, 0.235, 1}] // Timing // Short
(* Returns: {7.9405,{{0.0097638 a+0.00293462 b,<<44>>,
-0.0000123978 a+0.0000123978 b},<<44>>,{<<1>>}}} *)

How to efficiently set matrix's minor in Mathematica?

While looking at the belisarius's question about generation of non-singular integer matrices with uniform distribution of its elements, I was studying a paper by Dana Randal, "Efficient generation of random non-singular matrices". The algorithm proposed is recursive, and involves generating a matrix of lower dimension and assigning it to a given minor. I used combinations of Insert and Transpose to do it, but there are must be more efficient ways of doing it. How would you do it?
The following is the code:
Clear[Gen];
Gen[p_, 1] := {{{1}}, RandomInteger[{1, p - 1}, {1, 1}]};
Gen[p_, n_] := Module[{v, r, aa, tt, afr, am, tm},
While[True,
v = RandomInteger[{0, p - 1}, n];
r = LengthWhile[v, # == 0 &] + 1;
If[r <= n, Break[]]
];
afr = UnitVector[n, r];
{am, tm} = Gen[p, n - 1];
{Insert[
Transpose[
Insert[Transpose[am], RandomInteger[{0, p - 1}, n - 1], r]], afr,
1], Insert[
Transpose[Insert[Transpose[tm], ConstantArray[0, n - 1], r]], v,
r]}
]
NonSingularRandomMatrix[p_?PrimeQ, n_] := Mod[Dot ## Gen[p, n], p]
It does generate a non-singular matrix, and has uniform distribution of matrix elements, but requires p to be prime:
The code is also not every efficient, which is, I suspect due to my inefficient matrix constructors:
In[10]:= Timing[NonSingularRandomMatrix[101, 300];]
Out[10]= {0.421, Null}
EDIT So let me condense my question. The minor matrix of a given matrix m can be computed as follows:
MinorMatrix[m_?MatrixQ, {i_, j_}] :=
Drop[Transpose[Drop[Transpose[m], {j}]], {i}]
It is the original matrix with i-th row and j-th column deleted.
I now need to create a matrix of size n by n that will have the given minor matrix mm at position {i,j}. What I used in the algorithm was:
ExpandMinor[minmat_, {i_, j_}, v1_,
v2_] /; {Length[v1] - 1, Length[v2]} == Dimensions[minmat] :=
Insert[Transpose[Insert[Transpose[minmat], v2, j]], v1, i]
Example:
In[31]:= ExpandMinor[
IdentityMatrix[4], {2, 3}, {1, 2, 3, 4, 5}, {2, 3, 4, 4}]
Out[31]= {{1, 0, 2, 0, 0}, {1, 2, 3, 4, 5}, {0, 1, 3, 0, 0}, {0, 0, 4,
1, 0}, {0, 0, 4, 0, 1}}
I am hoping this can be done more efficiently, which is what I am soliciting in the question.
Per blisarius's suggestion I looked into implementing ExpandMinor via ArrayFlatten.
Clear[ExpandMinorAlt];
ExpandMinorAlt[m_, {i_ /; i > 1, j_}, v1_,
v2_] /; {Length[v1] - 1, Length[v2]} == Dimensions[m] :=
ArrayFlatten[{
{Part[m, ;; i - 1, ;; j - 1], Transpose#{v2[[;; i - 1]]},
Part[m, ;; i - 1, j ;;]},
{{v1[[;; j - 1]]}, {{v1[[j]]}}, {v1[[j + 1 ;;]]}},
{Part[m, i ;;, ;; j - 1], Transpose#{v2[[i ;;]]}, Part[m, i ;;, j ;;]}
}]
ExpandMinorAlt[m_, {1, j_}, v1_,
v2_] /; {Length[v1] - 1, Length[v2]} == Dimensions[m] :=
ArrayFlatten[{
{{v1[[;; j - 1]]}, {{v1[[j]]}}, {v1[[j + 1 ;;]]}},
{Part[m, All, ;; j - 1], Transpose#{v2}, Part[m, All, j ;;]}
}]
In[192]:= dim = 5;
mm = RandomInteger[{-5, 5}, {dim, dim}];
v1 = RandomInteger[{-5, 5}, dim + 1];
v2 = RandomInteger[{-5, 5}, dim];
In[196]:=
Table[ExpandMinor[mm, {i, j}, v1, v2] ==
ExpandMinorAlt[mm, {i, j}, v1, v2], {i, dim}, {j, dim}] //
Flatten // DeleteDuplicates
Out[196]= {True}
It took me a while to get here, but since I spent a good part of my postdoc generating random matrices, I could not help it, so here goes. The main inefficiency in the code comes from the necessity to move matrices around (copy them). If we could reformulate the algorithm so that we only modify a single matrix in place, we could win big. For this, we must compute the positions where the inserted vectors/rows will end up, given that we will typically insert in the middle of smaller matrices and thus shift the elements. This is possible. Here is the code:
gen = Compile[{{p, _Integer}, {n, _Integer}},
Module[{vmat = Table[0, {n}, {n}],
rs = Table[0, {n}],(* A vector of r-s*)
amatr = Table[0, {n}, {n}],
tmatr = Table[0, {n}, {n}],
i = 1,
v = Table[0, {n}],
r = n + 1,
rsc = Table[0, {n}], (* recomputed r-s *)
matstarts = Table[0, {n}], (* Horizontal positions of submatrix starts at a given step *)
remainingShifts = Table[0, {n}]
(*
** shifts that will be performed after a given row/vector insertion,
** and can affect the real positions where the elements will end up
*)
},
(*
** Compute the r-s and vectors v all at once. Pad smaller
** vectors v with zeros to fill a rectangular matrix
*)
For[i = 1, i <= n, i++,
While[True,
v = RandomInteger[{0, p - 1}, i];
For[r = 1, r <= i && v[[r]] == 0, r++];
If[r <= i,
vmat[[i]] = PadRight[v, n];
rs[[i]] = r;
Break[]]
]];
(*
** We must recompute the actual r-s, since the elements will
** move due to subsequent column insertions.
** The code below repeatedly adds shifts to the
** r-s on the left, resulting from insertions on the right.
** For example, if vector of r-s
** is {1,2,1,3}, it will become {1,2,1,3}->{2,3,1,3}->{2,4,1,3},
** and the end result shows where
** in the actual matrix the columns (and also rows for the case of
** tmatr) will be inserted
*)
rsc = rs;
For[i = 2, i <= n, i++,
remainingShifts = Take[rsc, i - 1];
For[r = 1, r <= i - 1, r++,
If[remainingShifts[[r]] == rsc[[i]],
Break[]
]
];
If[ r <= n,
rsc[[;; i - 1]] += UnitStep[rsc[[;; i - 1]] - rsc[[i]]]
]
];
(*
** Compute the starting left positions of sub-
** matrices at each step (1x1,2x2,etc)
*)
matstarts = FoldList[Min, First#rsc, Rest#rsc];
(* Initialize matrices - this replaces the recursion base *)
amatr[[n, rsc[[1]]]] = 1;
tmatr[[rsc[[1]], rsc[[1]]]] = RandomInteger[{1, p - 1}];
(* Repeatedly perform insertions - this replaces recursion *)
For[i = 2, i <= n, i++,
amatr[[n - i + 2 ;; n, rsc[[i]]]] = RandomInteger[{0, p - 1}, i - 1];
amatr[[n - i + 1, rsc[[i]]]] = 1;
tmatr[[n - i + 2 ;; n, rsc[[i]]]] = Table[0, {i - 1}];
tmatr[[rsc[[i]],
Fold[# + 1 - Unitize[# - #2] &,
matstarts[[i]] + Range[0, i - 1], Sort[Drop[rsc, i]]]]] =
vmat[[i, 1 ;; i]];
];
{amatr, tmatr}
],
{{FoldList[__], _Integer, 1}}, CompilationTarget -> "C"];
NonSignularRanomMatrix[p_?PrimeQ, n_] := Mod[Dot ## Gen[p, n],p];
NonSignularRanomMatrixAlt[p_?PrimeQ, n_] := Mod[Dot ## gen[p, n],p];
Here is the timing for the large matrix:
In[1114]:= gen [101, 300]; // Timing
Out[1114]= {0.078, Null}
For the histogram, I get the identical plots, and the 10-fold efficiency boost:
In[1118]:=
Histogram[Table[NonSignularRanomMatrix[11, 5][[2, 3]], {10^4}]]; // Timing
Out[1118]= {7.75, Null}
In[1119]:=
Histogram[Table[NonSignularRanomMatrixAlt[11, 5][[2, 3]], {10^4}]]; // Timing
Out[1119]= {0.687, Null}
I expect that upon careful profiling of the above compiled code, one could further improve the performance. Also, I did not use runtime Listable attribute in Compile, while this should be possible. It may also be that the parts of the code which perform assignment to minors are generic enough so that the logic can be factored out of the main function - I did not investigate that yet.
For the first part of your question (which I hope I understand properly) can
MinorMatrix be written as follows?
MinorMatrixAlt[m_?MatrixQ, {i_, j_}] := Drop[mat, {i}, {j}]

Resources