The problem is described as follows:
I need to generate a basis(matrix) in lexicographic order.
For two different basis vector {n1,n2,⋯,nM} and {t1,t2,⋯,tM}, there must exist a certain index 1≤k≤M−1 such that ni=ti for 1≤i≤k−1, while nk≠tk. We say {n1,n2,⋯,nM} is superior to {t1,t2,⋯,tM} if nk>tk.
The whole algorithm can be described as follows, supposing n1+n2+⋯+nM=N,
Starting from {N,0,0,⋯,0}, supposing nk≠0 while ni=0 for all k+1≤i≤M−1, then the next basis vector is {t1,t2,⋯,tM} with
(1) ti=ni, for 1≤i≤k−1;
(2) tk=nk−1;
(3) t(k+1)=N-Sum[ni,{i,1,k}]
(4) ti=0 for i≥k+2
The generating procedure shall stop at the final vector {0,0,...,0,N}
My code is presented as follows
baseGenerator[M_Integer, N_Integer] :=
NestList[
Block[{k, base},
k = Part[{M}-FirstPosition[Reverse[#[[1 ;; M - 1]]], x_ /; x > 0], 1];
base = #;
base[[k]] = #[[k]] - 1;
base[[k + 1]] = N - Total[#[[1 ;; k]]] + 1;
base[[k + 2 ;; M]] = 0;
base] &,
Join[{N}, ConstantArray[0, M - 1]], (N + M - 1)!/(N!*(M - 1)!) - 1]
Each line corresponds to a specfic step described above. I don't think my code is efficient since it cost much more time than MATLAB writing with loop. Is there any method to improve it a lot ?
In fact, most of the time is costed when calculating position k with command FirstPosisiton
.
Answer
Matlab is the fertile soil of bad Mathematica programming... try
baseGenerator2[m_Integer, n_Integer] :=
Reverse@Sort[Join @@ Permutations /@ IntegerPartitions[n, {m}, Range[n, 0, -1]]]
And for your own sanity, don't use uppercase initials on symbols - you may very well clash with built-ins and/or create debugging nightmares (e.g. N
is a built-in, by happenstance you did not have an issue there).
Comments
Post a Comment