Recursion optimization - arrays

I'm trying to find a certain path through my 2d array
My array could look like this:
temp = [
["placeholder", 2, 0],
["placeholder", 1, 7, 3],
["placeholder", 4, 5, 8],
["placeholder", 6, 3, 5, 2],
["placeholder", 7],
["placeholder", 3, 0],
]
The inner arrays contain a placeholder followed by a variable amount of integers. These integers range in value between 0-19 (0 and 19 both included)
I wanna find a path from top to bottom through these inner arrays where no number is used more than once.
At temp[0] i can choose my 1st value either 2 or 0
At temp[1] i can choose my 2nd value either 1, 7 or 3
At temp[2] i can choose my 3rd value either 4, 5 or 8
At temp[3] i can choose my 4th value either 6, 3, 5 or 2
Notice at this step I cannot pick 2 if I had already chosen 2 in the 1st step
I cannot pick 3 if I had already chosen 3 in the 2nd step
I cannot pick 5 if I had already chosen 5 in the 3rd step
etc.
These are some legal paths:
2-1-4-6-7-3
0-1-4-5-7-3
These are some illegal paths:
2-1-4-2-7-3 (2 is touched twice)
0-1-4-5-7-0 (0 is touched twice)
I want my function to output a completely legal path.
I just want my function to return false if no path is found.
I've tried to write my own recursive solution to this problem, which I think is working, but suffers from heavy inefficiency and therefore takes literal ages to complete.
The size of my intended array is more like 20 x 1..20
So far my code looks like this (written in Python 3) (and with a temp array):
temp= [
["placeholder", 7, 3],
["placeholder", 3, 3],
["placeholder", 4, 3],
["placeholder", 3, 8],
["placeholder", 1, 3],
]
def findpath(array, path = []):
if path and path.count(path[-1]) > 1:
return False
if len(path) == len(array):
print(path)
return True
routes = array[len(path)][1:]
for route in routes:
path.append(route)
if findpath(array, path):
return True
path.pop(-1)
findpath(temp)
This code prints: [7, 3, 4, 8, 1]
This approach is brute-forcing through every possibility until a solution is reached. In a worst-case scenario, my temp array would contain 20 arrays all containing 20 values each, that would make for 20! possible solutions, or in other words 2.432.902.008.176.640.000 possible paths. Let's exaggerate and say my pc takes 1 ms to process a single iteration of this function. My math could be wrong but that would mean this process could take 77,146,816.6 years to complete (not accounting for leap years), and imma be honest, I don't got this kinda time.
There must be a smarter way to approach this problem.
One thing I've noticed is that if the function encounters an inner array at step e.g. 15, containing only a single int e.g. 2, then the function will try adjusting its latest picks (first step 14 then step 13) one at a time, without realizing it has already picked 2 at step 2. In this situation by going back to step 2 and change the value from 2 to something else will save a f*** ton of iteration. The only problem is I have no idea how to implement this, nor any idea how to optimize this further.
Here is a real example array (not sure if it contains a solution)
temp = [
['placeholder', 2, 6, 11, 14, 15, 16, 18],
['placeholder', 2, 6, 7, 10, 11, 14, 15, 16, 17, 18, 19],
['placeholder', 2, 6, 10, 11, 14, 15, 16, 18, 19],
['placeholder', 2, 6, 11, 14, 15, 16, 18, 19],
['placeholder', 2, 6, 11, 14, 15, 16],
['placeholder', 2, 6, 7, 10, 11, 14, 15, 16, 18, 19],
['placeholder', 2, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19],
['placeholder', 11, 15, 16],
['placeholder', 11, 14, 15, 16],
['placeholder', 0, 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 11, 15],
['placeholder', 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 2, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 15],
['placeholder', 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
['placeholder', 2, 11, 14, 15, 16],
['placeholder', 2, 6, 7, 8, 10, 11, 14, 15, 16, 17, 18, 19]
]
Hope you can help me learn <3

functional heritage
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding mutations like .append and .pop and other side effects.
Below we use a set to efficiently skip invalid combinations and a tuple to store the path. A new set and tuple are constructed for each recursion -
def traverse(t, s = set(), p = ()):
if not t:
yield p
else:
[ [_, *values], *more ] = t
for v in values:
if v not in s:
yield from traverse(more, {*s, v}, (*p, v))
Using the data in your sample program -
temp = \
[ ["placeholder", 7, 3]
, ["placeholder", 3, 3]
, ["placeholder", 4, 3]
, ["placeholder", 3, 8]
, ["placeholder", 1, 3]
]
for p in traverse(temp):
print(p)
(7, 3, 4, 8, 1)
(7, 3, 4, 8, 1)
And using the data in your original question -
temp = \
[ ["placeholder", 2, 0]
, ["placeholder", 1, 7, 3]
, ["placeholder", 4, 5, 8]
, ["placeholder", 6, 3, 5, 2]
, ["placeholder", 7]
, ["placeholder", 3, 0]
]
for p in traverse(temp):
print(p)
(2, 1, 4, 6, 7, 3)
(2, 1, 4, 6, 7, 0)
(2, 1, 4, 3, 7, 0)
(2, 1, 4, 5, 7, 3)
(2, 1, 4, 5, 7, 0)
(2, 1, 5, 6, 7, 3)
(2, 1, 5, 6, 7, 0)
(2, 1, 5, 3, 7, 0)
(2, 1, 8, 6, 7, 3)
(2, 1, 8, 6, 7, 0)
(2, 1, 8, 3, 7, 0)
(2, 1, 8, 5, 7, 3)
(2, 1, 8, 5, 7, 0)
(2, 3, 4, 6, 7, 0)
(2, 3, 4, 5, 7, 0)
(2, 3, 5, 6, 7, 0)
(2, 3, 8, 6, 7, 0)
(2, 3, 8, 5, 7, 0)
(0, 1, 4, 6, 7, 3)
(0, 1, 4, 5, 7, 3)
(0, 1, 4, 2, 7, 3)
(0, 1, 5, 6, 7, 3)
(0, 1, 5, 2, 7, 3)
(0, 1, 8, 6, 7, 3)
(0, 1, 8, 5, 7, 3)
(0, 1, 8, 2, 7, 3)
generators are lazy
Because we're using a generator, we can stop generating the paths at any time. Perhaps you only want to find the first valid path -
def first_valid_path(t):
for path in traverse(t):
return path
temp = \
[ ["placeholder", 2, 0]
, ["placeholder", 1, 7, 3]
, ["placeholder", 4, 5, 8]
, ["placeholder", 6, 3, 5, 2]
, ["placeholder", 7]
, ["placeholder", 3, 0]
]
print(first_valid_path(temp))
(2, 1, 4, 6, 7, 3)
optimisation
One such optimisation we can make is to sort the input array by the number of possibilities, least posibilities first, as these are the most difficult to fulfill -
temp.sort(key=len)
print(temp)
[ ['placeholder', 15]
, ['placeholder', 11, 15]
, ['placeholder', 11, 15, 16]
, ['placeholder', 11, 14, 15, 16]
, ['placeholder', 2, 11, 14, 15, 16]
, ['placeholder', 2, 6, 11, 14, 15, 16]
, ['placeholder', 2, 6, 11, 14, 15, 16, 18]
, ['placeholder', 2, 6, 11, 14, 15, 16, 18, 19]
, ['placeholder', 2, 6, 10, 11, 14, 15, 16, 18, 19]
, ['placeholder', 2, 6, 7, 10, 11, 14, 15, 16, 18, 19]
, ['placeholder', 2, 6, 7, 10, 11, 14, 15, 16, 17, 18, 19]
, ['placeholder', 2, 6, 7, 8, 10, 11, 14, 15, 16, 17, 18, 19]
, ['placeholder', 2, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19]
, ['placeholder', 2, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19]
, ['placeholder', 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
, ['placeholder', 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
, ['placeholder', 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
, ['placeholder', 0, 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
, ['placeholder', 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
, ['placeholder', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
]
I didn't measure it, but a solution is found instantly (less than one second) -
print(first_valid_path(temp))
(15, 11, 16, 14, 2, 6, 18, 19, 10, 7, 17, 8, 9, 13, 12, 4, 1, 0, 5, 3)
To put the path in correct order, it would need to be un-sorted. There are a number of ways this can be done and I will consider updating the post later with a proposed solution. For now, that is left as an exercise for the reader :D
unsort
If you made it this far, great! Above I proposed a sorting and unsorting process and below I'll show one such way to handle the unsorting -
def traverse(init):
def sort(t):
z = list(enumerate(t))
z.sort(key=lambda _: len(_[1]))
return z
def unsort(p):
p.sort(key=lambda _: _[0])
return tuple(v for (_, v) in p)
def loop(t, s, p):
if not t:
yield unsort(p)
else:
[ (k, [_, *values]), *more ] = t
for v in values:
if v not in s:
yield from loop(more, {*s, v}, [*p, (k, v)])
yield from loop(sort(init), set(), [])
This works by creating an intermediate representation with sort -
[ (16, ['placeholder', 15])
, (10, ['placeholder', 11, 15])
, (7, ['placeholder', 11, 15, 16])
, (8, ['placeholder', 11, 14, 15, 16])
, (18, ['placeholder', 2, 11, 14, 15, 16])
, (4, ['placeholder', 2, 6, 11, 14, 15, 16])
, (0, ['placeholder', 2, 6, 11, 14, 15, 16, 18])
, (3, ['placeholder', 2, 6, 11, 14, 15, 16, 18, 19])
, (2, ['placeholder', 2, 6, 10, 11, 14, 15, 16, 18, 19])
, (5, ['placeholder', 2, 6, 7, 10, 11, 14, 15, 16, 18, 19])
, (1, ['placeholder', 2, 6, 7, 10, 11, 14, 15, 16, 17, 18, 19])
, (19, ['placeholder', 2, 6, 7, 8, 10, 11, 14, 15, 16, 17, 18, 19])
, (6, ['placeholder', 2, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19])
, (14, ['placeholder', 2, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19])
, (11, ['placeholder', 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
, (15, ['placeholder', 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
, (12, ['placeholder', 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
, (9, ['placeholder', 0, 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
, (17, ['placeholder', 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
, (13, ['placeholder', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
]
The paths are made up of tuples (sort_key, value) and unsorted using the sort_key -
[(16, 15), (10, 11), (7, 16), (8, 14), (18, 2), (4, 6), (0, 18), (3, 19), (2, 10), (5, 7), (1, 17), (19, 8), (6, 9), (14, 13), (11, 12), (15, 4), (12, 1), (9, 0), (17, 5), (13, 3)]
Finally the sort_key is removed and only the value path we care about is yielded. Now we can see the path in the correct order. The result is instantly computed (less than one second) -
print(first_valid_path(temp))
(18, 17, 10, 19, 6, 7, 9, 16, 14, 0, 11, 12, 1, 3, 13, 4, 15, 5, 2, 8)
all valid paths
Above we use find_first_path but our sorting/unsorting technique is also efficient at finding all solutions -
for p in traverse(temp):
print(p)
For this particular input, there is only one valid path. However this program terminates quickly (less than one second), signalling that all possibilities have been exhausted.

Related

Reverse-bit iteration in 2D

I use this reverse-bit method of iteration for rendering tasks in one dimension, the goal being to iterate through an array with the bits of the iterator reversed so that instead of computing an array slowly from left to right the order is spread out. I use this for instance when rendering the graph of a 1D function, because this reversed bit iteration first computes values at well-spaced intervals a representative image appears only after a very small fraction of all the values are computed.
So after only a partial rendering we already have a good idea of how the final graph will look. Now I want to apply the same principle to 2D rendering, think raytracing and such, the idea is having a good overall view of the image being rendered even from an early stage. The problem is that making the same idea work as a 2D iteration isn't trivial.
Here's how I do it in 1D:
#include <stdio.h>
#include <stdint.h>
#include <math.h>
static const uint8_t ffo_lut[2048] = {
0,
1,
2, 2,
3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11
};
int32_t log2_ffo32(uint32_t x) // returns the number of bits up to the most significant set bit so that 2^return > x >= 2^(return-1)
{
uint32_t y;
y = x >> 21; if (y) return ffo_lut[y] + 21;
y = x >> 10; if (y) return ffo_lut[y] + 10;
return ffo_lut[x];
}
uint32_t reverse_bits32(uint32_t v)
{
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
return (v >> 16 ) | ( v << 16);
}
uint32_t reverse_n_bits32(uint32_t v, int n)
{
return reverse_bits32(v) >> (32 - n);
}
uint32_t reverse_iterator_bits32(int *i, uint32_t count) // i should not be the for loop iterator but rather a variable that starts from 0 and isn't touched outside of this function
{
uint32_t ir;
ir = reverse_n_bits32(*i, log2_ffo32(count-1)); // reverse the correct number of bits
(*i)++; // iterate i for the next call to this function
if (ir >= count) // if ir is too large
ir = reverse_iterator_bits32(i, count); // get the next ir in the sequence
return ir;
}
int main()
{
int i, i2, ir, count = 13;
for (i2 = i = 0; i < count; i++)
{
ir = reverse_iterator_bits32(&i2, count);
printf("%d -> %d\n", i, ir);
}
return 0;
}
So there's the main iterator i which iterates normally from 0 to count-1, there's i2 which iterates from 0 to the next power of 2 of count minus 1 with gaps, and there's ir which is the reverse bit iterator. For a count of 13 we get this ir sequence: 0 8 4 12 2 10 6 1 9 5 3 11 7. Note that it's the same sequence as if we had count of 16 with the 3 higher values missing.
But sadly a naive approach to 2D iteration leaves to be desired, one axis will complete entire lines in one stretch, whereas I want the points to be well spread out in 2D. I tried making a 1D iterator (over the full pixel count) that has its bits reversed and then using division and modulo turn this into 2D coordinates, but the quality of the results depend on the dimensions, with power-of-2 dimensions this solves nothing.
For an image of 8x8, ideally the first pixel calculated would be (0,0), then (4,4), (2,2), (2,6), (6,2), (6,6), (1,1), (1,5), (5,1) and so on, but I just can't figure out an elegant way to make a loop that iterates in 2D in such a sequence.
Reversing the bits achieves the expected effect in 1D, you could combine this shuffling technique with another one where you get the x and y coordinates be selecting the even, resp. odd, bits of the resulting number. Combining both methods in a single shuffle is highly desirable to avoid costly bit twiddling operations.
You could also use Gray Codes to shuffle values with n significant bits into a pseudo random order. Here is a trivial function to produce gray codes:
uint32_t gray(uint32_t x) { return x ^ (x - 1); }
Based on chqrlie's idea I used one iterator then distributed its bits in reverse order to x and y coordinates. I used a pretty dumb loop to do the shuffling and maybe that could be improved, but I can't think of anything obvious.
#include <stdio.h>
#include <stdint.h>
#include <math.h>
static const uint8_t ffo_lut[2048] = {
0,
1,
2, 2,
3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 };
int32_t log2_ffo32(uint32_t x) // returns the number of bits up to the most significant set bit so that 2^return > x >= 2^(return-1)
{
uint32_t y;
y = x>>21; if (y) return ffo_lut[y]+21;
y = x>>10; if (y) return ffo_lut[y]+10;
return ffo_lut[x];
}
typedef struct { int x, y; } xyi_t;
#define MAXN(x, y) (((x) > (y)) ? (x) : (y))
#define get_bit(word, pos) (((word) >> (pos)) & 1)
xyi_t reverse_iterator_bits_2d(uint64_t *i, xyi_t dim)
{
xyi_t ir, dim_bits;
int ib, sh, shift;
shift = log2_ffo32(MAXN(dim.x, dim.y) - 1) - 1; // number of bits needed for each dimension
shuffle_start:
// Shuffle bits from i into ir.x and ir.y
ir.x = 0;
ir.y = 0;
sh = shift;
for (ib=0; *i >> ib; ib++, sh--)
{
ir.x |= get_bit(*i, ib) << sh;
ib++;
ir.y |= get_bit(*i, ib) << sh;
}
(*i)++; // iterate i for the next call to this function
if (ir.x >= dim.x || ir.y >= dim.y) // if ir is too large
goto shuffle_start; // get the next ir in the sequence
return ir;
}
int main()
{
xyi_t ip, dim = { 7 , 5 };
uint64_t i, i2, ir;
uint64_t count = dim.x*dim.y;
for (i2 = i = 0; i < count; i++)
{
ip = reverse_iterator_bits_2d(&i2, dim);
printf("(%d,%d) ", ip.x, ip.y);
if ((i&7)==7) printf("\n");
}
return 0;
}
The resulting pattern gives a fairly uniform image. Here's how it looks on a 320x240 render as it progresses:
Epilogue
I found it useful to fill in the blanks as it renders, by which I mean that every new pixel calculated is rendered as a block of the appropriate size given the current stride so that there is no visible black background unlike in the animation above. Here's an example of a loop that does this:
int max_bits = log2_ffo32(MAXN(dim.x, dim.y) - 1);
int stride = 4096; // initial value only used for first pixel at (0,0)
for (i2=i=0; i < pix_count; i++)
{
ip = reverse_iterator_bits_2d(&i2, dim);
source_pixel = pixel_rendering_function(ip);
int i2_bits = log2_ffo32(i2-2); // log2_ffo64 would be better
// When we change strides (block sizes)
if (i2-1 == (1 << i2_bits) && (i2_bits & 1) == 0)
{
int stride_shift = max_bits - (i2_bits>>1) - 1;
//stride_shift--; // a cool fractal pattern emerges
stride = 1 << stride_shift;
}
// Fill block of unset pixels around the new pixel
if (stride > 1)
{
xyi_t ib, start, end;
start = sub_xyi(ip, set_xyi(stride >> 1));
end = add_xyi(start, set_xyi(stride));
start = max_xyi(start, XYI0);
end = min_xyi(end, dim);
for (ib.y = start.y; ib.y < end.y; ib.y++)
for (ib.x = start.x; ib.x < end.x; ib.x++)
image_buffer[ib.y * dim.x + ib.x] = source_pixel;
}
}
Functions ending in _xyi to handle 2D vectors of int are not included but are fairly obvious.

Ruby search for the same values in multidimensional array

I have an array with many arrays inside (2d) (in this example there are four of them):
[
[13, 15, 18, 23, 23, 11, 14, 19, 19, 5, 10, 10, 8, 8],
[8, 15, 19, 21, 21, 12, 16, 18, 18, 11, 13, 13, 6, 6],
[9, 15, 21, 23, 23, 7, 13, 15, 15, 12, 14, 14, 8, 8],
[2, 8, 14, 16, 16, 7, 13, 15, 15, 12, 14, 14, 8, 8]
]
I need to find if any element on any of these arrays is the same and at the same index as in other array. I need to get all those numbers and their indexes.
For ex. First_array[1] = 15, as well as second_array[1] = 15 and third_array[1] = 15. So I need these, with their indexes.
Also all needed values must come from arrays that are to the left or to the right to the array. For ex. - array_one[3] = 23, array_two[3] = 21 and array_three[3] = 23. I dont need these since array_two has a different value and it separates array_one from array_three.
And What I can get is the length of arrays (they all the same length) and the number of arrays, as variables.
I hope you got my point :)
Looks like I am abit closer to my goal. It seems this checks well for the second array (so only two first arrays being checked, but if this was done, the rest should be much easier). And do not judge me, judge just the code :D I know its ugly, its just a prototype:
array.each do |c|
c.each do |v|
c.each_with_index do |k, i|
next_array = array[i + 1]
if next_array.include? v
its_index = next_array.index(v)
if c.index(v) == its_index
p v
end
end
break
end
end
return
end
arr = [[13, 15, 18, 23, 23, 11, 14, 19, 19, 5, 10, 10, 8, 8],
[ 8, 15, 19, 21, 23, 12, 16, 18, 19, 11, 13, 13, 6, 8],
[ 9, 15, 21, 23, 16, 12, 13, 15, 15, 12, 14, 14, 8, 8],
[ 2, 8, 14, 21, 16, 7, 13, 15, 15, 12, 14, 14, 8, 8]]
I've modified arr in a few places.
arr.transpose.each_with_index.with_object({}) do |(col,j),h|
i = 0
h[j] = col.chunk(&:itself).each_with_object({}) do |(x,arr),g|
count = arr.size
g.update(i=>{ value: x, number: count }) if count > 1
i += count
end
end
#=> {0=>{},
# 1=>{0=>{:value=>15, :number=>3}},
# 2=>{},
# 3=>{},
# 4=>{0=>{:value=>23, :number=>2}, 2=>{:value=>16, :number=>2}},
# 5=>{1=>{:value=>12, :number=>2}}
# 6=>{2=>{:value=>13, :number=>2}},
# 7=>{2=>{:value=>15, :number=>2}},
# 8=>{0=>{:value=>19, :number=>2}, 2=>{:value=>15, :number=>2}},
# 9=>{2=>{:value=>12, :number=>2}},
# 10=>{2=>{:value=>14, :number=>2}},
# 11=>{2=>{:value=>14, :number=>2}},
# 12=>{2=>{:value=> 8, :number=>2}},
# 13=>{0=>{:value=> 8, :number=>4}}}
The keys of this hash are indices of columns of arr. The values are hashes that contain the locations and counts of all vertically-adjacent elements which appear at least twice. The columns at indices 0, 2 and 3, are the only ones that contains no vertically-adjacent duplicate values. The column at index 1 contains 3 15's beginning at row index 0; the column at index 4 contains 2 23's, beginning at row index 0 and 2 16's, beginning at row index 2.
matrix = [
[13, 15, 18, 23, 23, 11, 14, 19, 19, 5, 10, 10, 8, 8],
[ 8, 15, 19, 21, 21, 12, 16, 18, 18, 11, 13, 13, 6, 6],
[ 9, 15, 21, 23, 23, 7, 13, 15, 15, 12, 14, 14, 8, 8],
[ 2, 8, 14, 16, 16, 7, 13, 15, 15, 12, 14, 14, 8, 8]
]
equal_surround = matrix
.each_with_index.map do |v,i|
v.each_with_index.map do |k,j|
if (i-1>=0 && k == matrix[i-1][j])
k
elsif (i+1 < matrix.length && k == matrix[i+1][j])
k
else
nil
end
end
end
=> [
[nil, 15, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil],
[nil, 15, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil],
[nil, 15, nil, nil, nil, 7, 13, 15, 15, 12, 14, 14, 8, 8],
[nil, nil, nil, nil, nil, 7, 13, 15, 15, 12, 14, 14, 8, 8]
]
You didn't show any code, so I won't write any either.
I can tell you that array#transpose should make this problem much more manageable, though.
You'll just need to iterate on the rows (former columns) and look for any repeating number.
You can either do it FORTRAN style with a loop or with fancier Enumerable methods, like each_with_index, map or chunk.
test_array = [
[13, 15, 18, 23, 23, 11, 14, 19, 19, 5, 10, 10, 8, 8],
[8, 15, 19, 21, 21, 12, 16, 18, 18, 11, 13, 13, 6, 6],
[9, 15, 21, 23, 23, 7, 13, 15, 15, 12, 14, 14, 8, 8],
[2, 8, 14, 16, 16, 7, 13, 15, 15, 12, 14, 14, 8, 8]
]
final_res = Hash.new {|h,k| h[k] = Array.new }
test_array.each_cons(2).to_a.each_with_index do |(a,b),i|
final_match = Hash.new {|h,k| h[k] = Array.new }
res = a & b
res.each do |ele|
a_index = a.each_index.select{|i| a[i] == ele}
b_index = b.each_index.select{|i| b[i] == ele}
(a_index & b_index).size > 0 ? final_match[ele] << (a_index & b_index) : ''
end
final_match.each_value {|v| v.flatten!}
final_res[:"Match Values Between Array #{i+1} amd Array #{i+2}"] << final_match
end
final_res.each do |a|
puts a
end
OUTPUT:
Match Values Between Array 1 amd Array 2
{15=>[1]}
Match Values Between Array 2 amd Array 3
{15=>[1]}
Match Values Between Array 3 amd Array 4
{15=>[7, 8], 7=>[5], 13=>[6], 12=>[9], 14=>[10, 11], 8=>[12, 13]}

Sum of ruby arrays in a loop

I want to find sum of arrays from 1 to 100.Each number is converted to array containing its own digits eg 97 will be [9,7].Here is what i have tried
(1..100).to_a.each do |i|
i.to_s.split("").map(&:to_i).inject(0) { |sum, number| sum + number }
end
But the sum of arrays are not displayed correctly!
For example;We first create an array of the digits and then return sum
[1]=1
[5]=5
[1, 0]=1
[1, 1]=2
[1, 2]=3
[1, 3]=4
[1, 4]=5
So sum of individual arrays is to be returned.
each will iterate the array, but not create a new array with the result of the block. If you want the results at the end, you need to use map:
result = (1..100).to_a.map do |i|
i.to_s.split("").map(&:to_i).inject(0) { |sum, number| sum + number }
end
result
#=> [1, 2, 3, 4, ...]
For summing an array you can also simply write
array.inject(:+)
# instead of
array.inject(0) { |sum, number| sum + number }
Also, the to_a is not necessary, you can directly call each and/or map on a range. So the simplified code would be
result = (1..100).map do |i|
i.to_s.split("").map(&:to_i).inject(:+)
end
result
#=> [1, 2, 3, 4, ...]
For your codes, you just need to change each method to map.
(1..100).to_a.map do |i|
i.to_s.split("").map(&:to_i).inject(0) { |sum, number| sum + number }
end
more simplicity way:
result = (1..100).to_a.map{ |e| e.to_s.split('').map(&:to_i).reduce(:+) }
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1]
if you want to get the sum of result, just do like this:
result.reduce(:+)
If I understand your question correctly you want the sum of these new arrays, right? This should solve your problem:
(1..100).map { |i| i.to_s.split("").map(&:to_i).inject(:+) }.inject(:+)
digits and sum are newer methods, simplifying this to
(1..100).sum{|i| i.digits.sum}
Another alternative for modern newer versions of Ruby:
(1..100).flat_map(&:digits).sum

Indexing highest value of numpy matrix

I have a numpy array of shape (4, 7) like this:
array([[ 1, 4, 5, 7, 8, 6, 7]
[ 2, 23, 2, 4, 8, 94, 2],
[ 1, 5, 6, 7, 10, 15, 20],
[ 3, 9, 2, 7, 6, 5, 4]])
I would like to get the index of the highest element, i.e. 94, in a form like: first row fifth column. Thus the output should be a numpy array ([1,5]) (matlab-style).
You get the index of the maximum index using arr.argmax() but to get the actual row and column you must use np.unravel_index as below:
import numpy as np
arr = np.array([[ 1, 4, 5, 7, 8, 6, 7],
[ 2, 23, 2, 4, 8, 94, 2],
[ 1, 5, 6, 7, 10, 15, 20],
[ 3, 9, 2, 7, 6, 5, 4]])
maximum = np.unravel_index(arr.argmax(), arr.shape)
print(maximum)
# (1, 5)
You have to use np.unravel_index as by default np.argmax will return the index from a flattened array (which in your case would be index 12).

App Engine downtime

Does Google's App Engine have excessive downtime, specifically with regards to datastore writes?
Additionally, downtime seems to be scheduled during high traffic times, e.g., in the middle of the afternoon vs. 3:00AM in the morning. Is this normal? Will it improve as the technology matures?
Short Answers
Afternoon vs early morning downtime. The datastore has been unavailable for writes about 20-30% more often in the afternoon than in the wee hours of the morning (Pacific time; includes put, update, and delete availability).
Note: I'm sure Google would like downtime to occur during off-peak hours. Thus I expect they'll continue to try to minimize downtime, or schedule it for off-peak hours whenever possible.
Downtime trending. The number of 15-minute periods during which the datastore has been unavailable has been decreasing. In the past 366 days, there were an average of 3.8 15-minute periods in which the datastore was unavailable per day. In the past 200 days, this has decreased by 60% to 2.3 per day. Write downtime over the past few months has actually been quite good - since March 1st, there have been less than 0.25 15-minute chunks of write downtime per day. Here's a graph of datastore write downtime:
Downtime trending http://imagebin.ca/img/4wkHVQPc.png
Source of Answers
To answer your question, I wrote this script which extracts downtime data from GAE's Datastore Status page.
Graphs
Datastore write downtime from 2009-Jul-20 to 2010-Jul-20 (4 hour bins):
alt text http://imagebin.ca/img/p9ScWTm.png
Datastore write downtime from 2009-Jul-20 to 2010-Jul-20 (1 hour bins):
alt text http://imagebin.ca/img/9FbLut2G.png
Datastore downtime from 2009-Jul-20 to 2010-Jul-20 (4 hour bins):
alt text http://imagebin.ca/img/t3XKLk.png
Datastore downtime from 2010-Jan-01 to 2010-Jul-20 (4 hour bins):
alt text http://imagebin.ca/img/k36T9h.png
Raw data
(you can tweak the variables at the top of the script if you'd like to collect your own data with slightly different parameters):
# RAW Data: Each element counts the number of days in which the datastore
# was unavailable for at least some portion of a given 15-minute window. The
# first element corresponds to the time chunk from 00:00 to 00:15, and so on.
RESULTS_SINCE_2010JAN01_BIN15 = [0, 0, 0, 0, 3, 11, 3, 3, 3, 3, 12, 3, 3, 3, 4, 14, 4, 4, 4, 4, 12, 2, 2, 2, 2, 14, 4, 4, 4, 4, 11, 2, 2, 2, 2, 11, 5, 5, 5, 5, 13, 4, 4, 4, 4, 14, 7, 5, 5, 5, 14, 4, 3, 3, 3, 13, 2, 2, 2, 2, 12, 5, 4, 4, 4, 14, 5, 3, 3, 3, 12, 7, 2, 2, 2, 5, 5, 0, 0, 0, 2, 9, 3, 2, 2, 2, 10, 1, 1, 1, 2, 9, 3, 3, 3, 15]
RESULTS_SINCE_2009JUL20_BIN15 = [0, 0, 0, 0, 11, 21, 5, 5, 5, 5, 29, 6, 6, 6, 7, 38, 11, 11, 11, 11, 37, 7, 7, 7, 7, 44, 12, 12, 12, 12, 37, 10, 10, 10, 10, 34, 7, 7, 7, 7, 46, 11, 11, 11, 11, 39, 15, 13, 13, 13, 44, 13, 12, 12, 12, 44, 5, 5, 5, 5, 34, 11, 10, 10, 10, 40, 13, 11, 11, 11, 31, 21, 12, 12, 11, 19, 21, 4, 4, 4, 13, 28, 10, 9, 9, 16, 36, 10, 10, 10, 12, 32, 7, 7, 6, 35]
RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN15 = [0, 0, 0, 0, 4, 12, 4, 4, 4, 4, 22, 6, 6, 6, 7, 27, 7, 7, 7, 7, 21, 6, 6, 6, 6, 32, 9, 9, 9, 9, 26, 8, 8, 8, 8, 27, 7, 7, 7, 7, 30, 7, 7, 7, 7, 27, 10, 8, 8, 8, 28, 10, 9, 9, 9, 28, 4, 4, 4, 4, 21, 4, 4, 4, 4, 25, 6, 4, 4, 4, 18, 14, 9, 10, 9, 16, 17, 2, 2, 2, 8, 18, 7, 6, 6, 9, 19, 5, 5, 5, 6, 18, 5, 5, 4, 21]
# RESULTS DISTILLED FROM COLLECTED_RESULTS
RESULTS_SINCE_2010JAN01_BIN60 = [RESULTS_SINCE_2010JAN01_BIN15[i*4]+RESULTS_SINCE_2010JAN01_BIN15[i*4+1]+RESULTS_SINCE_2010JAN01_BIN15[i*4+2]+RESULTS_SINCE_2010JAN01_BIN15[i*4+3] for i in xrange(24)]
RESULTS_SINCE_2010JAN01_BIN240 = [RESULTS_SINCE_2010JAN01_BIN60[i*4]+RESULTS_SINCE_2010JAN01_BIN60[i*4+1]+RESULTS_SINCE_2010JAN01_BIN60[i*4+2]+RESULTS_SINCE_2010JAN01_BIN60[i*4+3] for i in xrange(6)]
RESULTS_SINCE_2010JAN01_BIN480 = [RESULTS_SINCE_2010JAN01_BIN60[i*2]+RESULTS_SINCE_2010JAN01_BIN60[i*2+1] for i in xrange(3)]
RESULTS_SINCE_2009JUL20_BIN60 = [RESULTS_SINCE_2009JUL20_BIN15[i*4]+RESULTS_SINCE_2009JUL20_BIN15[i*4+1]+RESULTS_SINCE_2009JUL20_BIN15[i*4+2]+RESULTS_SINCE_2009JUL20_BIN15[i*4+3] for i in xrange(24)]
RESULTS_SINCE_2009JUL20_BIN240 = [RESULTS_SINCE_2009JUL20_BIN60[i*4]+RESULTS_SINCE_2009JUL20_BIN60[i*4+1]+RESULTS_SINCE_2009JUL20_BIN60[i*4+2]+RESULTS_SINCE_2009JUL20_BIN60[i*4+3] for i in xrange(6)]
RESULTS_SINCE_2009JUL20_BIN480 = [RESULTS_SINCE_2009JUL20_BIN240[i*2]+RESULTS_SINCE_2009JUL20_BIN240[i*2+1] for i in xrange(3)]
RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN60 = [RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN15[i*4]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN15[i*4+1]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN15[i*4+2]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN15[i*4+3] for i in xrange(24)]
RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN240 = [RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN60[i*4]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN60[i*4+1]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN60[i*4+2]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN60[i*4+3] for i in xrange(6)]
RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN480 = [RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN240[i*2]+RESULTS_WRITE_DOWNTIME_SINCE_2009JUL20_BIN240[i*2+1] for i in xrange(3)]

Resources