You can do much better. Here is the code based on the low-level sparse array of APIs placed here , which I will reproduce to make the code self-sufficient:
ClearAll[spart, getIC, getJR, getSparseData, getDefaultElement, makeSparseArray]; HoldPattern[spart[SparseArray[s___], p_]] := {s}[[p]]; getIC[s_SparseArray] := spart[s, 4][[2, 1]]; getJR[s_SparseArray] := Flatten@spart [s, 4][[2, 2]]; getSparseData[s_SparseArray] := spart[s, 4][[3]]; getDefaultElement[s_SparseArray] := spart[s, 3]; makeSparseArray[dims : {_, _}, jc : {__Integer}, ir : {__Integer}, data_List, defElem_: 0] := SparseArray @@ {Automatic, dims, defElem, {1, {jc, List /@ ir}, data}}; Clear[formSparseDivisible]; formSparseDivisible[a_, aa_, iaa_, chunkSize_: 100] := Module[{getDataChunkCode, i, start, ic, jr, sparseData, dims, dataChunk, res}, getDataChunkCode := If[# === {}, {}, SparseArray[1 - Unitize@ (Mod[#, aa] & /@ #)]] &@ If[i*chunkSize >= Length[a], {}, Take[a, {i*chunkSize + 1, Min[(i + 1)*chunkSize, Length[a]]}]]; i = 0; start = getDataChunkCode; i++; ic = getIC[start]; jr = getJR[start]; sparseData = getSparseData[start]; dims = Dimensions[start]; While[True, dataChunk = getDataChunkCode; i++; If[dataChunk === {}, Break[]]; ic = Join[ic, Rest@getIC [dataChunk] + Last@ic ]; jr = Join[jr, getJR[dataChunk]]; sparseData = Join[sparseData, getSparseData[dataChunk]]; dims[[1]] += First[Dimensions[dataChunk]]; ]; res = Transpose[makeSparseArray[dims, ic, jr, sparseData]]; res[[All, 1]] = N@iaa ; res]
Now, here is the timing:
In[249]:= n = 1500; iaa = aa = Range[2 n]; a = Range[n]; AbsoluteTiming[res = formSparseDivisible[a, aa, iaa, 100];] Out[252]= {0.2656250, Null} In[253]:= AbsoluteTiming[ res1 = SparseArray[{{i_, 1} :> iaa[[i]], {i_, j_} /; Divisible[a[[j]], aa[[i]]] -> 1.}, {2*n, n}];] Out[253]= {29.1562500, Null}
So, we have 100x acceleration for this array size. And, of course, the results are the same:
In[254]:= Normal@res1 == Normal@res Out[254]= True
The main idea of ββthe solution is to vectorize the problem ( Mod ) and stage-by-stage construction of the resulting sparse array in pieces using the above lower-level API.
EDIT
The code assumes that the lists are of the correct length - in particular, a must be of length n , and aa and iaa be 2n . So, in order to compare with other answers, the test code should be slightly modified (only for a ):
n = 500; iaa = RandomReal[{0, 1}, 2 n]; a = Range[ n]; aa = RandomInteger[{1, 4 n}, 2 n]; In[300]:= AbsoluteTiming[U=SparseArray[ReplacePart[Outer[Boole[Divisible[
EDIT 2
The desired matrix size takes about 3 seconds to complete on my not-so-fast laptop (M8) and with pretty decent memory usage:
In[323]:= n=5000; iaa=RandomReal[{0,1},2 n]; a=Range[ n];aa=RandomInteger[{1,4 n},2 n]; AbsoluteTiming[res = formSparseDivisible[a,aa,iaa,200]] Out[326]= {3.0781250,SparseArray[<36484>,{10000,5000}]}