Re: random matrix from row and column sums
- To: mathgroup at smc.vnet.net
- Subject: [mg53698] Re: random matrix from row and column sums
- From: "Ray Koopman" <koopman at sfu.ca>
- Date: Mon, 24 Jan 2005 03:37:19 -0500 (EST)
- References: <csinpt$njk$1@smc.vnet.net><csntqf$4jh$1@smc.vnet.net>
- Sender: owner-wri-mathgroup at wolfram.com
The algorithm in my previous post is suitable only for tables with small counts. It runs out of space very quickly as the counts grow. Here is something that uses less space and is also faster, faster even than using Reduce. It is built around P[n,m], which returns a list of all the decompositions of an integer n into the sum of m nonincreasing nonnegative integers. In[1]:= P[0,m_] := {Table[0,{m}]}; P[n_,m_]/;n<m := With[{z=Table[0,{m-n}]},Join[#,z]&/@P[n,n]]; P[n_,1] := {{n}}; P[n_,2] := Table[{n-i,i},{i,0,n/2}]; P[n_,m_] := ToExpression[ "Block[" <> ToString[Table[SequenceForm["n",k],{k,m-2}]] <> ",Flatten[Table[" <> ToString[Table[If[k==m,SequenceForm["n",m-2,"-i",m-1], SequenceForm["i",k]],{k,m,1,-1}]] <> "," <> StringTake[ToString[Table[Which[ k==1,StringForm["{i1,0,``/``}",n,m], k==2,StringForm["{i2,i1,(n1=``-i1)/``}",n,m-1], True,StringForm["{i`3`,i`2`,(n`2`=n`1`-i`2`)/`4`}", k-2,k-1,k,m+1-k]], {k,m-1}]], {2,-2}] <> "]," <> ToString[m-2] <> "]]" ] In[6]:= allfxy[fx_,fy_] := Block[{ky = Length@fy, f, fxy, gy}, fxy = Reap[ Scan[ Scan[ If[And@@MapThread[LessEqual,{#,fy}],Sow[{#}]]&, Permutations@#]&, P[fx[[1]],ky]] ][[2,1]]; Do[f = Reap[ Scan[ Scan[ If[And@@MapThread[LessEqual,{#,fy}],Sow[#]]&, Permutations@#]&, P[fx[[ix]],ky]] ][[2,1]]; fxy = Reap[Scan[Function[gxy, gy = Plus@@gxy; Scan[If[And@@MapThread[LessEqual,{#+gy,fy}],Sow[Append[gxy,#]]]&, f]], fxy]][[2,1]], {ix,2,Length@fx-1}]; Append[#,fy-Plus@@#]&/@fxy] In[7]:= NonnegativeIntegerMatrices[rows_, cols_] := Module[ {mat, r, c, a, vars, cond, red, m = Length[rows], n = Length[cols]}, mat = Table[a[i, j], {i, m}, {j, n}]; r = Thread[Plus @@ Transpose[mat] == rows]; c = Thread[Plus @@ mat == cols]; vars = Flatten[mat]; cond = Thread[Flatten[mat] >= 0]; red = {ToRules[Reduce[Join[r, c, cond], vars, Integers]]}; If[red != {}, mat /. red, {}]] In[8]:= Timing@Length[m = allfxy[{7,3,2},{2,9,1}]] Timing@Length[mat = NonnegativeIntegerMatrices[{7,3,2},{2,9,1}]] Sort@m === Sort@mat Out[8]= {0.01 Second,17} Out[9]= {0.03 Second,17} Out[10]= True In[11]:= Timing@Length[m = allfxy[Range@4,Range@4]] Timing@Length[mat = NonnegativeIntegerMatrices[Range@4,Range@4]] Sort@m === Sort@mat Out[11]= {0.02 Second,261} Out[12]= {0.44 Second,261} Out[13]= True In[14]:= Timing@Length[m = allfxy[Range@5,Range@5]] Timing@Length[mat = NonnegativeIntegerMatrices[Range@5,Range@5]] Sort@m === Sort@mat Out[14]= {2.38 Second,22645} Out[15]= {57.49 Second,22645} Out[16]= True