analytics

Monday, February 9, 2015

Finding a nice way of drawing a graph

Vertices move towards other vertices they're connected to unless they are less than 100 pixels in distance from them, then they move away. And they move away from vertices they're not connected to unless they are more than 100 pixels away in which case it doesn't matter. All movements are normalized to 1 pixel left and right and up and down.

Cell labeling for bucketing positions on the grid

This idea is for cutting down on the number of items one has to check for possible interactions.
The cells can be labeled in this fashion (example: 4*j+i with i,j from 0..3):
An item on the plane within a square, like position 1567.5, 500 might be in cell 6 considering where it falls within the square on the plane. So one could check in cell 6-4 = 2 and cell 6+4 = 10 and 6-1 = 5 and 6+1 = 7 for possible interactions with the items in those cells, or counting diagonals also 6-3 and 6+3, 6-5 and 6+5. The +- 1, 3, 4, 5 is the same for any choice of cell except those on the edges.

So you might want to make your cell grid say 7x7 but only use the central 5x5 and cells number 0-6, 7*n+0, 41-48, and 7*n+6 would all be out of bounds ...To check a cells neighbors one would check it's cell number +- 1, 7, 6, 8

A "sparse" implementation could perhaps use something like a dictionary in python, and make new cells whenever there is a need for one with the specified number, and deleted when it is empty...

Sunday, February 8, 2015

Easy seed value for square root algorithms

For even number of digits of the number to find the square root of:
3672
average the number you get when you slide the decimal point halfway across and the power of 10 you moved the decimal point by:
(36.72 + 100)/2 = 68.36, this will always be a bit larger than the actual square root, in this case  60.59

For odd number of digits first multiply by 10...
36725 x 10 = 367250
Then proceed as before
(367.250 + 1000)/2 = 683.625 and then divide by sqr(10) = 216, the actual is 191
It works even better in binary...
36725=
1000111101110101
10001111
 2^7= 1000000
(128 + 241)/2 = 181 when the actual is 191...

So this is a good way to find the initial seed value to continue with a precise method that needs a good guess like the Babylonian method to work it's best...

Wednesday, January 21, 2015

2 tone and 3 bit dithering with inverse square brightness


The above picture uses only the colors full white and full black.
The way I did it is to start with an array of boolean values the size of the picture above all set to true. Then make a list of every [x,y] value for all the pixels, and scramble the order of them. Then go through this scrambled list of values and look in the array of booleans at the truth value of any cell within a distance 5 of the pixel in question. A sum is kept of the inverses of the distances^2 of all the cells that are true out of those. The maximum this could come out to is 12.76. So the ratio of what the sum comes out to divided by 12.76 is compared to the ratio of the brightness of the grayscale image at that pixel divided by 255 (the maximum brightness). If the first ratio is greater than the second the array of booleans is set to False at that [x,y]. Then the array is converted to an image with True values making a pixel white and false black.

**Python Source Code**
from PIL import Image
import random
def main():
    im = Image.open("lion.png")
    map=[]
    for i in range(0, im.size[1]):
        row = []
        for j in range(0, im.size[0]):
            row.append(True)
        map.append(row)
    pixels = []
    for i in range(0, im.size[0]):
        for j in range(0, im.size[1]):
            pixels.append([j,i])
    random.shuffle(pixels)
 
    for p in pixels:
        sumbright = 0
     
        for x in range(-5, 6):
            for y in range(-5, 6):
                if x!=0 or y !=0:
                    if p[0] +x >= 0 and p[0]+x < len(map):
                        if p[1]+y >=0 and p[1]+y < len(map[0]):
                            d = (x**2.0 + y**2.0)
                            if d**.5 <= 5:
                                if map[p[0]+x][p[1]+y] == True:
                                    sumbright +=1.0/d
                             
                             
                             
        if 1.0*sumbright /12.78  > 1.0*im.getpixel((p[1],p[0])) / 255:
            map[p[0]][p[1]] = False
     
    im2 = Image.new("RGB", (im.size[0], im.size[1]))
    for i in range(0, im.size[0]):
        for j in range(0, im.size[1]):
            if map[j][i] == True:
                im2.putpixel((i,j), (255,255,255))
    im2.save("lion2a.png")
main()


**8 color**
Also modified the code for doing 8 color or 3 bit dithered images, full or no red, full or no green, full or no blue...
Extreme close up:
For comparison, the state of the art is Floyd Steinberg dithering which for 8 colors produces images like this:
I think this way I'm doing it is a big improvement...
**Python Source Code**
from PIL import Image
import random
def main():
    im = Image.open("parrot.png")
    map=[]
    for i in range(0, im.size[1]):
        row = []
        for j in range(0, im.size[0]):
            row.append([True, True, True])
        map.append(row)
    pixels = []
    for i in range(0, im.size[0]):
        for j in range(0, im.size[1]):
            pixels.append([j,i])
    random.shuffle(pixels)
    print(len(map[0]), len(map))
    print(im.size[0], im.size[1])
    for p in pixels:
        sumbrightred = 0
        sumbrightgreen = 0
        sumbrightblue = 0
        for x in range(-5, 6):
            for y in range(-5, 6):
                if x!=0 or y !=0:
                    if p[0] +x >= 0 and p[0]+x < len(map):
                        if p[1]+y >=0 and p[1]+y < len(map[0]):
                            d = (x**2.0 + y**2.0)
                            if d**.5 <= 5:
                                try:
                                    if map[p[0]+x][p[1]+y][0] == True:
                                        sumbrightred +=1.0/d
                                    if map[p[0]+x][p[1]+y][1] == True:
                                        sumbrightgreen +=1.0/d
                                    if map[p[0]+x][p[1]+y][2] == True:
                                        sumbrightblue +=1.0/d
                                except:
                                    print(p[0]+x, p[1]+y)
                               
        if 1.0*sumbrightred /12.78  > 1.0*im.getpixel((p[1],p[0]))[0] / 255:
            map[p[0]][p[1]][0] = False
        if 1.0*sumbrightgreen /12.78  > 1.0*im.getpixel((p[1],p[0]))[1] / 255:
            map[p[0]][p[1]][1] = False
        if 1.0*sumbrightblue /12.78  > 1.0*im.getpixel((p[1],p[0]))[2] / 255:
            map[p[0]][p[1]][2] = False
    im2 = Image.new("RGB", (im.size[0], im.size[1]))
    for i in range(0, im.size[0]):
        for j in range(0, im.size[1]):
            color = [0,0,0]
            if map[j][i][0] == True:
                color[0] = 255
            if map[j][i][1] == True:
                color[1] = 255
            if map[j][i][2] == True:
                color[2] = 255
            im2.putpixel((i,j), tuple(color))
    im2.save("parrot2.png")
main()

Friday, January 16, 2015

material


I made this material by breaking up cotton balls very finely and coating them with graphite powder, then mixing that up with 2 part epoxy and forming it. It is really impressively hard and strong. Beating on it with a hammer on the driveway doesn't leave any visible marks (and makes such a loud noise I might make a video), and cutting into it with a knife only makes a slight mark in the outermost surface probably just into the epoxy coating...

**After polishing the outer surface flat with Aluminum Oxide Sand paper, after the surface was flattened it smoothed the sand paper instead of further smoothing the material
 I found I was able to drill holes through it without compromising the strength of the bulk structure or it breaking into pieces around the hole...

Wednesday, January 14, 2015

Sort worm

A sort worm is a creature I made whose genes work on a list, this one I made works on lists of 10 items like so:
[2, 8, 7, 4, 5, 3, 6, 9, 0, 1]
I chose to use 25 genes as being roughly 10*log(10) of the form:
[a,b] where a and b are positions on the list and the gene is expressed by comparing items in the list at those positions and swapping them if the number at the lower position is greater than the one at the higher position. "His" dna is:
[[1, 4], [7, 9], [2, 6], [0, 7], [1, 7], [6, 8], [3, 5], [3, 8], [2, 4], [2, 3], [5, 7], [0, 6], [6, 9], [8, 9], [0, 2], [3, 6], [4, 8], [0, 1], [5, 6], [7, 9], [4, 6], [1, 3], [4, 7], [6, 7], [3, 5]]

So working on the given list:
[2, 8, 7, 4, 5, 3, 6, 9, 0, 1] original list
[2, 5, 7, 4, 8, 3, 6, 9, 0, 1] swapped items 1 and 4 (0 indexed) because the rightmost is less than the leftmost of the two
[2, 5, 7, 4, 8, 3, 6, 1, 0, 9] swapped 7 and 9...
[2, 5, 6, 4, 8, 3, 7, 1, 0, 9] etc...
[1, 5, 6, 4, 8, 3, 7, 2, 0, 9]
[1, 2, 6, 4, 8, 3, 7, 5, 0, 9]
[1, 2, 6, 4, 8, 3, 0, 5, 7, 9]
[1, 2, 6, 3, 8, 4, 0, 5, 7, 9]
[1, 2, 6, 3, 8, 4, 0, 5, 7, 9]
[1, 2, 6, 3, 8, 4, 0, 5, 7, 9]
[1, 2, 3, 6, 8, 4, 0, 5, 7, 9]
[1, 2, 3, 6, 8, 4, 0, 5, 7, 9]
[0, 2, 3, 6, 8, 4, 1, 5, 7, 9]
[0, 2, 3, 6, 8, 4, 1, 5, 7, 9]
[0, 2, 3, 6, 8, 4, 1, 5, 7, 9]
[0, 2, 3, 6, 8, 4, 1, 5, 7, 9]
[0, 2, 3, 1, 8, 4, 6, 5, 7, 9]
[0, 2, 3, 1, 7, 4, 6, 5, 8, 9]
[0, 2, 3, 1, 7, 4, 6, 5, 8, 9]
[0, 2, 3, 1, 7, 4, 6, 5, 8, 9]
[0, 2, 3, 1, 7, 4, 6, 5, 8, 9]
[0, 2, 3, 1, 6, 4, 7, 5, 8, 9]
[0, 1, 3, 2, 6, 4, 7, 5, 8, 9]
[0, 1, 3, 2, 5, 4, 7, 6, 8, 9]
[0, 1, 3, 2, 5, 4, 6, 7, 8, 9]
This finished result is pretty typical that 2 items are 1 position out of order...
A lot of times it gets it perfectly and the worst I've seen it do is 4 items needing to be swapped 1 position.
Testing this dna on 100 random lists gives that this will be the average result.

**finding the dna**
To find this above sequence of dna I:
1. Created 10 sort worms with random dna
Then repeat these steps below for 1000 generations
2. "Breed" all worms each worm with every other, where every new worm gets each gene from one of its parents to make its dna.
3. Reduce this list of worms to the 5 best performers as the average root mean squared of how out of order the list is after he uses his dna on 100 random lists.
4. Add 5 more random worms to the 5 you're left with.

At the end this worm above was the best performer.
**Source Code**
import random
class creature():
    def __init__(self):
        self.dna = []
    def new(self, dnalength, listlength):
        self.dnalength = dnalength
        self.listlength = listlength
        crudelist = []
        for i in range(0, listlength-1):
            for j in range(i+1, listlength):
                crudelist.append([i,j])
        random.shuffle(crudelist)
        self.dna = crudelist[0:dnalength]
    def childof(self, a, b):
        self.dnalength = a.dnalength
        self.listlength = a.listlength
        for i in range(0, len(a.dna)):
            g = random.randint(0, 1)
            if g == 0:
                self.dna.append(a.dna[i])
            else:
                self.dna.append(b.dna[i])
    def statictest(self, numtimes, testlist):
        avep = 0
        for i in range(0, numtimes):
            testlist = self.usegenes(testlist)
            p = self.checklist(testlist)
            avep += p
        return avep*1.0 / numtimes
    def testme(self, numtimes):
        avep = 0
        for i in range(0, numtimes):
            testlist = []
            for j in range(0, self.listlength):
                testlist.append(random.random())
            testlist = self.usegenes(testlist)
            p = self.checklist(testlist)
            avep += p
        return avep*1.0 / numtimes
    def checklist(self, testlist):
        totalscore = 0
        for i in range(0, len(testlist)):
            lessthan = 0
            for j in range(0, len(testlist)):
                if testlist[j] < testlist[i]:
                    lessthan +=1
            score = (i - lessthan)**2.0
            totalscore +=score
        return totalscore**.5
    def usegenes(self, testlist):
        for j in range(0, self.dnalength):
                if testlist[self.dna[j][0]] > testlist[self.dna[j][1]]:
                    temp = testlist[self.dna[j][0]]
                    testlist[self.dna[j][0]] = testlist[self.dna[j][1]]
                    testlist[self.dna[j][1]] = temp
        return testlist
def main():
    creatures = []
    numcreatures = 400
    survivors = 5
    dnalength = 25
    listlength = 10
    numtests = 100
    generations = 3000
    testlist = []
    performance = []
    for j in range(0, listlength):
        testlist.append(random.random())
    for i in range(0, numcreatures):
        c = creature()
        c.new(dnalength, listlength)
        creatures.append(c)
    
    for i in range(0, generations):
        performance = []
        creatures2 = []
        for j in range(0, len(creatures)):
            c = creatures[j]
            performance.append([c.testme(numtests), j])
        performance = sorted(performance)
        for j in range(0, survivors):
            creatures2.append(creatures[performance[j][1]])
        for j in range(0, survivors):
            c = creature()
            c.new(dnalength, listlength)
            creatures2.append(c)
        creatures = creatures2
        max = len(creatures)
        for k in range(0, max-1):
            for l in range(k+1, max):
                c = creature()
                c.childof(creatures[k], creatures[l])
                creatures.append(c)
    print(performance)
    print(creatures[0].dna)
main()

Thursday, January 1, 2015

Limit vs. Limit graphs to analyze infinite series

f(x) = 1/x^3 as x goes to infinity will reach 0, and the integral from 1 to infinity will reach 1/2. I find it interesting to parameterize a 2 variable curve where one variable s is the function's value at t and the other r is the partial integral from 1 up to t, and make a plot of s vs. r like below.
This shows the behavior of f(x) over the entire x axis from 1 to infinity as it relates to the integral to that point.

It leads to an interesting proof of the infinite sum of geometric series... Here I plot the sum of 1/2^n up to t vs. the value of each individual term at t...
The value of the first term is 1 and the sum of just that term is of course 1, and the next term is 1/2 and the sum of the first two terms is 1.5, and it precedes linearly all the way to a term being 0 and the sum of the infinite terms being 2. But if you know all the points lie on the same line you can use just the first two terms to derive a line that shows ultimately the infinite sum will reach the r axis at 1/(1-1/2). And generalize that to any geometric series.