comps results in simpler, more efficient, easier to control functions.
Two lists (x,y) for a Cartesian product are usual. The products are half duplicates. If each column starts with a perfect square, the duplicates are eliminated.
Then each column is generated. Each column starts with a perfect square but then must also be specifically trimmed in length. Each multiple is compared to the limititing value.
So, about 25% or less of the Cartesian product are used, that is, calculated.
calcc limits the value of each factor multiple it calculates just like
comps but unlike
comps it doesn't use an initial-factor list.
Each initial-factor squared is first on the multiple list. Each initial-factor is the
head of each factor lists input.
I tried making
comps use one list only instead of two. The function was short, more complicated but not faster. Two remaining problems with it were the calculation for the limit value which only needs to be calculated one time at the beginning and a problem with all such functions a glob of parameters or superflous
where calculations. The functions need the parameters but should not be recalculated time-after-time.
runr passes the initial-factor to apply to itself and all other factors. The list sent to
calcc starts with a perfect square factor value. The diagonal eliminates duplicates.
runr with a length
n factor list and the limit based on that list length.
The 11 multiples extend to
n. Successive columns shorten to none at about
Checking every perfect square against the limit does not save time.
I also tried
mergeAll from Data.List.Ordered but it seemed to error around 3/4 the way down a prime list. I still have to investigate.
sort is what I still use but the functions now let me create a single list or a list of lists for
calcc _ _ = 
calcc f lim (x:xs)
| m<= lim= m:calcc f lim xs
| True= 
where m= f*x
runr _ = 
runr lim xss@(x:xs) = (calcc x lim xss)++runr lim xs
rrunr n = runr lim ds
where ds= take n n7sl
lim= 11*last ds
last.rms (sort $ rrunr 5000) $ n7sl
(0.07 secs, 50,617,744 bytes)
last.rms (sort $ rrunr 10000) $ n7sl
(0.18 secs, 115,282,560 bytes)
last.rms (sort $ rrunr 15000) $ n7sl
(0.25 secs, 179,096,928 bytes)
unionAll instead of
mergeAll because each sub-list is already in order. It did result in a minor speed up.
runr produces individual sub-lists for
runr _ = 
runr lim xss@(x:xs) = [calcc x lim xss]++runr lim xs
last $ rms (unionAll $ rrunr 10000) n7sl
(0.12 secs, 89,250,264 bytes)
last $ rms (unionAll $ rrunr 15000) n7sl
(0.20 secs, 140,110,392 bytes)
last $ rms (unionAll $ rrunr 20000) n7sl
(0.27 secs, 192,858,656 bytes)
I have an infinite version of this which is much simpler coding but it is a little slower.
mupcl _  = 
mupcl (x:xs) (y:ys) = [(x*) <$> y]++ mupcl xs ys
uat = unionAll.mupcl n7sl $ (\i-> (take i n7sl)) <$> [1..]
take 50000 $ rms uat n7sl
(0.45 secs, 269,026,264 bytes)
I updated this because finding the nth prime is important and this can. It's still slower than the fixed just before this but has some uses not available to the fixed.
I toyed with making the sublists sequences but then found that I could generate the sublist end value and multiply it by all previous values and itself. Sequence would access the end value in about O(1) which is awesome but the end values are in one-to-one correspondence with each sublist.
The diagonal of these is just each sublist is one longer than the previous.This is the top diagonal necessary for an infinite list.
The previous functions use a bottom diagonal and a limit value. If they used the top diagonal would they end as this function? IDK
The composite list was being traversed twice and it was driving me nuts.
I could not come up with a single function that would multiply two identical infinite lists diagonally.
I had developed one function to multiply 2s, 3s & 5s together to form the Hamming list. Saturday morning I looked at that function and followed the pattern for this function. It amazed me it worked.
unionAll does the limiting.
umap = unionAll $ map (\n -> (n*) <$> n7sl) n7sl
But, I am such an impatient idiot the function is going through two lists, exactly what I didn't want. I have an aversion to
tails, more like a phobia because of experience with
tails crashing my PC in an infinite function. What I discovered the past two or three months is that
unionAll do magic with infinite lists. They automatically limit end points. Talk about no coding. I spent so much time coding end points in this and in the Hamming numbers (which are way fast, too) that I really feel like an idiot. @Will Ness knows way more than I, too. Haskell is
pure (no pun) magic with laziness.
c2 = unionAll $ map (\xs@(x:_)-> (x*) <$> xs) $ tails n7sl
(minus n7sl c2) !! 1000000
(1.55 secs, 3,545,902,888 bytes)
And now, it's way faster than the non-infinite above.
This does 75803 primes to 962509 in 0.08 and the non-infinite does 75803 to 962509 in 0.27 and uses a little more memory.
(minus n7sl c2) !! 75803
(0.08 secs, 162,030,280 bytes)
OMG. It worked! I told @Will Ness it might, but that it would not with the non-infinite. What it is is the size of the wheel. I started calling it a wheel when I saw the deltas to create it. Mine is not a wheel because I have to generate the deltas from a column in Excel. I take 300 of
n7sl into a column in Excel them I remove all the 11 multiples. I take the deltas of the remainder then find where it repeats.
My no 11s list is
n11sl = scanl (+) 13 $ cycle n11s
The improvement is not stark and going any further with this would not be beneficial.
c2 modified to use
c2 = unionAll $ map (\xs@(x:_) -> (x*) <$> xs) $ tails n11sl
Executing it would be
(11:(minus n11sl c2)) !! 1000000
(1.30 secs, 2,968,456,072 bytes)
(11:(minus n11sl c2)) !! 500000
(0.55 secs, 1,305,594,104 bytes)