<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6549773495273813421</id><updated>2011-07-31T01:17:54.840+03:00</updated><category term='install'/><category term='firefox'/><category term='just kidding'/><category term='angst'/><category term='numpy'/><category term='emacs'/><category term='python'/><category term='clojure'/><category term='windows'/><category term='pygame'/><category term='music'/><category term='computer art'/><category term='perlin'/><category term='sort'/><title type='text'>Base 127</title><subtitle type='html'>Random ramblings of a software developer</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-4222629440168218714</id><published>2010-02-01T00:37:00.003+02:00</published><updated>2010-02-01T00:43:59.663+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='angst'/><title type='text'>My love/hate relationship with Firefox</title><content type='html'>Firefox is shit, yet it is still the best browser. Let me explain.&lt;br /&gt;&lt;br /&gt;Why can't even a simple copy &amp;amp; paste of bookmarks actually &lt;span style="font-weight: bold;"&gt;work&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Take this picture.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_lHQAgZVeApE/S2YGrMp9-cI/AAAAAAAAABI/59vdrt0mKTQ/s1600-h/scrot.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 218px;" src="http://2.bp.blogspot.com/_lHQAgZVeApE/S2YGrMp9-cI/AAAAAAAAABI/59vdrt0mKTQ/s320/scrot.png" alt="" id="BLOGGER_PHOTO_ID_5433037339670477250" border="0" /&gt;&lt;/a&gt;If I click "cut" Firefox hangs indefinitely. They can't even make the core features work right? It's just a bit over 1k bookmarks. This would be laughable if it didn't make me want to cry.&lt;br /&gt;&lt;br /&gt;Yet: Firefox is the only browser that can handle tagging effortlessly. Maybe I should take another look into Chrome if it supports proper tagging and searching yet.&lt;br /&gt;&lt;br /&gt;You will take one dimensional, flat, tagged bookmark list out of my cold, bloody, dead hands.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-4222629440168218714?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/4222629440168218714/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=4222629440168218714' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/4222629440168218714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/4222629440168218714'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2010/02/my-lovehate-relationship-with-firefox.html' title='My love/hate relationship with Firefox'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_lHQAgZVeApE/S2YGrMp9-cI/AAAAAAAAABI/59vdrt0mKTQ/s72-c/scrot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-306838423122797240</id><published>2009-10-16T02:28:00.007+03:00</published><updated>2009-10-26T04:27:52.782+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='just kidding'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='numpy'/><title type='text'>Python &gt; Clojure ;)</title><content type='html'>Lau Jensen &lt;a href="http://blog.bestinclass.dk/index.php/2009/10/brians-functional-brain/"&gt;posted&lt;/a&gt; about Clojure implementation of Brian's Brain.&lt;br /&gt;Later, he &lt;a href="http://blog.bestinclass.dk/index.php/2009/10/python-vs-clojure-evolving/"&gt;posted&lt;/a&gt; about how Clojure is better than Python.&lt;br /&gt;Well, here's my Python version of Brian's Brain that's a lot faster and more compact, although irrevocably obfuscated.&lt;br /&gt;&lt;br /&gt;Update: Removed most of code repetition and made it a bit more readable.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import numpy&lt;br /&gt;import pygame&lt;br /&gt;from pygame.locals import *&lt;br /&gt;&lt;br /&gt;foow, fooh = 200,200&lt;br /&gt;fooscale = 2&lt;br /&gt;&lt;br /&gt;pygame.init()&lt;br /&gt;screen = pygame.display.set_mode((foow * fooscale, fooh * fooscale), DOUBLEBUF)&lt;br /&gt;pygame.surfarray.use_arraytype("numpy")&lt;br /&gt;&lt;br /&gt;#--- tarr: 0 = dead, 1 = dying, 2 = living&lt;br /&gt;tarr = numpy.random.randint(0,2,(foow,fooh)) * 2&lt;br /&gt;&lt;br /&gt;grr = numpy.zeros((foow*fooscale,fooh*fooscale,3))&lt;br /&gt;run = True&lt;br /&gt;&lt;br /&gt;while run:&lt;br /&gt;    #--- count living neighbours (living means it has integer value of 2) &lt;br /&gt;    zuba = numpy.zeros((foow,fooh))&lt;br /&gt;    for loc in [1, -1, foow, -foow, foow-1, foow+1, -foow-1, -foow+1]:&lt;br /&gt;        zuba[:,:] += (numpy.roll(tarr, loc) == 2)&lt;br /&gt;&lt;br /&gt;    #--- logic. if cell has two neighbours and is dead, create new cell &lt;br /&gt;    tarr = numpy.where((zuba==2)&amp;(tarr==0), 3, tarr)&lt;br /&gt;    &lt;br /&gt;    #--- make new cells living cells, living cells dying cells, dying cells dead.&lt;br /&gt;    tarr = numpy.where((tarr&gt;0), tarr-1, 0)&lt;br /&gt;&lt;br /&gt;    #--- render&lt;br /&gt;    grr[::fooscale,::fooscale,0] = tarr * 120&lt;br /&gt;    grr[:,:,1] = grr[:,:,0] # G = R&lt;br /&gt;    grr[:,:,2] = grr[:,:,0] # B = R&lt;br /&gt;    &lt;br /&gt;    grr[1::fooscale,::fooscale,:] = grr[::fooscale,::fooscale,:]&lt;br /&gt;    grr[:,1::fooscale,:] = grr[:,::fooscale,:]&lt;br /&gt;    &lt;br /&gt;    pygame.surfarray.blit_array(screen, grr)&lt;br /&gt;    events = pygame.event.get()&lt;br /&gt;    for event in events:&lt;br /&gt;        if event.type == QUIT:&lt;br /&gt;            run = False&lt;br /&gt;&lt;br /&gt;    pygame.display.flip()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-306838423122797240?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/306838423122797240/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=306838423122797240' title='1 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/306838423122797240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/306838423122797240'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/10/python-clojure.html' title='Python &gt; Clojure ;)'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-7645386424718990151</id><published>2009-10-15T22:58:00.003+03:00</published><updated>2009-10-16T03:31:58.738+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Emacs shortcuts</title><content type='html'>C-y paste&lt;br /&gt;C-w cut&lt;br /&gt;M-w copy&lt;br /&gt;M-space start/end select&lt;br /&gt;C-_ undo and redo&lt;br /&gt;&lt;br /&gt;C-v page down&lt;br /&gt;M-v page up&lt;br /&gt;M-n row down&lt;br /&gt;M-p row up&lt;br /&gt;M-f word forward&lt;br /&gt;M-b word backward&lt;br /&gt;C-a/C-e go to start/end of row&lt;br /&gt;C-home/C-end go to start/end of file&lt;br /&gt;&lt;br /&gt;C-x C-c quit&lt;br /&gt;C-x C-s save&lt;br /&gt;C-x C-w save as&lt;br /&gt;C-x C-f open&lt;br /&gt;&lt;br /&gt;M-x slime start Slime(clojure) environment&lt;br /&gt;C-c C-k compile and run&lt;br /&gt;&lt;br /&gt;C-x b select buffer&lt;br /&gt;C-x &amp;lt;left&amp;gt; prev buffer&lt;br /&gt;C-x &amp;lt;right&amp;gt; next buffer&lt;br /&gt;&lt;br /&gt;C-x 1 show only current window&lt;br /&gt;C-x 2 split horizontally -&lt;br /&gt;C-x 3 split vertically |&lt;br /&gt;right mouse button on window bar closes window&lt;br /&gt;&lt;br /&gt;M-x color-theme-select select color theme (slightly bugged in win32)&lt;br /&gt;&lt;br /&gt;C-z suspend Emacs&lt;br /&gt;C-c I inspect class&lt;br /&gt;M-. jump to definition&lt;br /&gt;&lt;br /&gt;plugins:&lt;br /&gt;&lt;br /&gt;clojure-mode&lt;br /&gt;color-theme&lt;br /&gt;ido-switch-to-buffer&lt;br /&gt;winner-undo&lt;br /&gt;C-x r w / C-x r j&lt;br /&gt;elscreen&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-7645386424718990151?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/7645386424718990151/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=7645386424718990151' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/7645386424718990151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/7645386424718990151'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/10/emacs-shortcuts.html' title='Emacs shortcuts'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-1023278344014721552</id><published>2009-08-29T22:11:00.011+03:00</published><updated>2009-08-30T13:22:05.591+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='install'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Emacs, Clojure and Windows</title><content type='html'>How to: Latest Clojure in Windows Vista (and others) with EmacsW32&lt;br /&gt;&lt;br /&gt;Plan A:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Download EmacsW32 and install it from: &lt;a href="http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl"&gt;http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl&lt;/a&gt;. You need to set HOME environment variable to point to your home directory. Note: the path is case sensitive! Otherwise Emacs will write all its stuff into users AppData directory. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Install ELPA, copy the following to *scratch* buffer in Emacs:&lt;blockquote&gt;  (let ((buffer (url-retrieve-synchronously&lt;br /&gt;  "http://tromey.com/elpa/package-install.el")))&lt;br /&gt;(save-excursion&lt;br /&gt;(set-buffer buffer)&lt;br /&gt;(goto-char (point-min))&lt;br /&gt;(re-search-forward "^$" nil 'move)&lt;br /&gt;(eval-region (point) (point-max))&lt;br /&gt;(kill-buffer (current-buffer))))&lt;/blockquote&gt;Place cursor right at the end of the last parentheses and press CTRL-j, which will run the code.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;M-x means press ALT-x in Emacs, write the text after it, and press enter. Tab completion works. Try package- to find out different commands.&lt;br /&gt;M-x package-install&lt;br /&gt;clojure-mode (press enter)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;At this point you need to install Git. Best way to do this in Windows Vista seems to be msysgit at this point. One could also install Git through Cygwin, but installing Cygwin just for Git seems a bit too much work.&lt;br /&gt;msysgit is found here: &lt;a href="http://code.google.com/p/msysgit/downloads/list"&gt;http://code.google.com/p/msysgit/downloads/list&lt;/a&gt;. Use the full installer.&lt;br /&gt;Personally I don't click Windows integration on, because it throws crap into my context menu, which is supremely annoying.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Download and install Apache Ant. Set it into your path. This includes downloading and extracting the archive, setting ANT_HOME to Ant root, Ant bin directory into PATH, and JAVA_HOME pointing to JDK root (if you haven't already).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;M-x clojure-install. This will take a while as it downloads everything required from Git repositories and compiles them. I used c:/code/clj as my Clojure installation root.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Add (clojure-slime-config "PATH") to your .emacs config file, where PATH is the path to your Clojure installation, which you specified during M-x clojure-install.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Optionally you can M-x package-install paredit for some additional lispy goodness.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Read up some documentation on Emacs, SLIME and Clojure. Happy hacking!&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;tab&gt;&lt;your&gt;&lt;your&gt;The installation might still have some warts which can be fixed by editing .emacs. Add the following to the end:&lt;pre&gt;(clojure-slime-config "c:/code/clj")&lt;br /&gt;(add-hook 'slime-connected-hook (lambda () (require 'clojure-mode)))&lt;/pre&gt;&lt;br /&gt;I don't like the toolbar so (tool-bar-mode -1) removes that.&lt;br /&gt;&lt;br /&gt;Additionally, you might want to include additional libraries into Java classpath, which can be done by writing the following into .emacs configuration file, before package-initialize:&lt;pre&gt;(setq swank-clojure-extra-classpaths (list "c:/code/java/libs/swt/swt.jar" "c:/more/java/libs/foo.jar"))&lt;/pre&gt;&lt;br /&gt;Plan B: Install Clojure Box, which uses Clojure 1.0.0&lt;br /&gt;&lt;/your&gt;&lt;/your&gt;&lt;/tab&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-1023278344014721552?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/1023278344014721552/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=1023278344014721552' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/1023278344014721552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/1023278344014721552'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/08/emacs-clojure-and-windows.html' title='Emacs, Clojure and Windows'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-968199042140688056</id><published>2009-08-29T19:07:00.005+03:00</published><updated>2009-08-30T19:48:05.126+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><title type='text'>Making some sweet music with Clojure</title><content type='html'>Just launch up the Clojure REPL and write:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(import '(javax.sound.midi MidiSystem Synthsizer MidiChannel Instrument))&lt;br /&gt;(def #^Synthesizer synth (MidiSystem/getSynthesizer))&lt;br /&gt;(.open synth)&lt;br /&gt;(def mc (.getChannels synth))&lt;br /&gt;(def instr (.. synth getDefaultSoundbank getInstruments)&lt;br /&gt;(.loadInstrument synth (get instr 76))&lt;br /&gt;(.noteOn (get mc 4) 60 200)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's damn simple to use Java libraries from the REPL, and damn fun.&lt;br /&gt;Up next: Sequencing music in the REPL. (for which I have to write some actual code)&lt;br /&gt;&lt;br /&gt;If you're having problems with the code you might be missing the audiobank from JRE/lib/audio. (System/getProperty "java.home") and check if soundbank.gm is found under those directories.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-968199042140688056?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/968199042140688056/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=968199042140688056' title='1 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/968199042140688056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/968199042140688056'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/08/making-some-sweet-music-with-clojure.html' title='Making some sweet music with Clojure'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-1632066878796215159</id><published>2009-06-01T00:59:00.005+03:00</published><updated>2009-06-01T01:47:37.781+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><category scheme='http://www.blogger.com/atom/ns#' term='numpy'/><title type='text'>Matching Python built-in sort() speed with Numpy</title><content type='html'>It's a vectorized radix sort.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import random&lt;br /&gt;import time&lt;br /&gt;import numpy&lt;br /&gt;import math&lt;br /&gt;&lt;br /&gt;print "generating data..."&lt;br /&gt;nums = [random.randint(0,100000) for _ in xrange(10000000)]&lt;br /&gt;&lt;br /&gt;print "sorting"&lt;br /&gt;s_ti = time.time()&lt;br /&gt;q_vals = sorted(nums)&lt;br /&gt;e_ti = time.time()&lt;br /&gt;print e_ti-s_ti&lt;br /&gt;&lt;br /&gt;print "vectorized radix sort"&lt;br /&gt;npy_nums = numpy.array(nums, dtype=numpy.uint32)&lt;br /&gt;&lt;br /&gt;s_ti = time.time()&lt;br /&gt;&lt;br /&gt;mask = numpy.array(1)&lt;br /&gt;npy_max = numpy.max(npy_nums)&lt;br /&gt;while mask &lt;= npy_max:&lt;br /&gt;    cond = npy_nums &amp; mask&lt;br /&gt;    npy_nums =  numpy.r_[npy_nums[cond==0], npy_nums[cond&gt;0]]&lt;br /&gt;    mask &lt;&lt;= 1&lt;br /&gt;&lt;br /&gt;e_ti = time.time()&lt;br /&gt;print e_ti-s_ti&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-1632066878796215159?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/1632066878796215159/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=1632066878796215159' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/1632066878796215159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/1632066878796215159'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/06/matching-python-built-in-sort-speed.html' title='Matching Python built-in sort() speed with Numpy'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-4688763477181044820</id><published>2009-04-05T21:17:00.001+03:00</published><updated>2009-04-05T21:18:20.528+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='numpy'/><title type='text'>Fast prime number generator</title><content type='html'>&lt;pre&gt;&lt;br /&gt;def ambi_sieve(n):&lt;br /&gt;    s = numpy.arange(3, n, 2)&lt;br /&gt;    for m in xrange(3, int(n ** 0.5), 2): &lt;br /&gt;        if s[(m-3)/2]: &lt;br /&gt;            s[(m*m-3)/2:][::m]=0&lt;br /&gt;    return numpy.r_[2, s[s&gt;0]]&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-4688763477181044820?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/4688763477181044820/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=4688763477181044820' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/4688763477181044820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/4688763477181044820'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/04/fast-prime-number-generator.html' title='Fast prime number generator'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-6943322506410438165</id><published>2009-03-22T16:36:00.002+02:00</published><updated>2009-03-22T16:39:51.302+02:00</updated><title type='text'>First thing to do after installing Ubuntu 8.10</title><content type='html'>A) Press Alt+F2 and write 'gconf-editor'&lt;br /&gt;B) Navigate to /desktop/gnome/interface and uncheck 'enable_animations'&lt;br /&gt;C) Enjoy&lt;br /&gt;&lt;br /&gt;This basically removes the insanely annoying window minimize animation that Ubuntu has as default.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-6943322506410438165?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/6943322506410438165/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=6943322506410438165' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/6943322506410438165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/6943322506410438165'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/03/first-thing-to-do-after-installing.html' title='First thing to do after installing Ubuntu 8.10'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-8568363031114100033</id><published>2009-01-24T18:14:00.015+02:00</published><updated>2009-02-07T11:23:19.026+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computer art'/><category scheme='http://www.blogger.com/atom/ns#' term='pygame'/><title type='text'>Image to ASCII art with Python</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_lHQAgZVeApE/SXtBGK-MT0I/AAAAAAAAAAM/1XE8CUk-tro/s1600-h/megan.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 162px;" src="http://2.bp.blogspot.com/_lHQAgZVeApE/SXtBGK-MT0I/AAAAAAAAAAM/1XE8CUk-tro/s320/megan.jpg" alt="" id="BLOGGER_PHOTO_ID_5294897361184378690" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Yes, it's very slow, but it's also quite cool, and a fun hack in a bit over an hour. I thought of adding error diffusion algorithm to smooth color slides, but because of so low "pixel" size, it doesn't seem worth it. Otherwise, I'm out of ideas how to match the characters better to pixels.&lt;br /&gt;&lt;br /&gt;Script works also for variable width fonts. But they look awful compared to fixed width ones.&lt;br /&gt;&lt;br /&gt;The actual script will be posted soon...&lt;br /&gt;&lt;br /&gt;Update 1: Trying to use proper latin-1 character set in Pygame seems to be more difficult than previously anticipated. Full algorithm and funtionality: 1 hour, finetuning and debugging: 10 hours.&lt;br /&gt;&lt;br /&gt;Update 2: Working script&lt;br /&gt;&lt;br /&gt;Update 3: The whole thing grew a bit too large and complex for simple pasting. So I put it at Google Code. &lt;a href="http://code.google.com/p/pyascii/"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now supports numpy, SMP and variable width fonts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-8568363031114100033?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/8568363031114100033/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=8568363031114100033' title='0 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/8568363031114100033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/8568363031114100033'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2009/01/image-to-ascii-art-with-python.html' title='Image to ASCII art with Python'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_lHQAgZVeApE/SXtBGK-MT0I/AAAAAAAAAAM/1XE8CUk-tro/s72-c/megan.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6549773495273813421.post-2313840373166311868</id><published>2008-06-14T16:53:00.012+03:00</published><updated>2009-02-21T13:51:17.654+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pygame'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='perlin'/><title type='text'>Messing around with Python 2D arrays</title><content type='html'>So I wrote a simple script to render some Perlin noise. It's a fast hack, lot's of redundant code. It works and also shows that Python is kinda slow when dealing with large 2-dimensional arrays. &lt;s&gt;Of course using linked lists as arrays is a bad idea.&lt;/s&gt; (I later learned that access by index for Python lists is O(1)). So what I'm going to do here is to try out Numpy to optimize my code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; Some benchmarking of my original script and Manu's numpy version. Thanks, Manu!&lt;br /&gt;Original script: 42.360 seconds&lt;br /&gt;&lt;div  style="overflow: auto; width: 100%; height: 300px;font-size:11px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import random&lt;br /&gt;import math&lt;br /&gt;&lt;br /&gt;import pygame&lt;br /&gt;from pygame.locals import *&lt;br /&gt;&lt;br /&gt;class GFX():&lt;br /&gt;    def __init__(self):&lt;br /&gt;        pygame.init()&lt;br /&gt;&lt;br /&gt;        self.display_flags = DOUBLEBUF&lt;br /&gt;        rect = self.width, self.height = 640, 480&lt;br /&gt;    &lt;br /&gt;        if pygame.display.mode_ok(rect, self.display_flags):&lt;br /&gt;            self.screen = pygame.display.set_mode(rect, self.display_flags)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def linear_interp(a, b, x):&lt;br /&gt;    return a * (1 - x) + b * x&lt;br /&gt;&lt;br /&gt;def cosine_interp(a, b, x):&lt;br /&gt;    f = (1 - math.cos(x * math.pi)) * 0.5&lt;br /&gt;    return a * (1 - f) + b * f&lt;br /&gt;&lt;br /&gt;def cubic_interp(v0, v1, v2, v3, x):&lt;br /&gt;    p = (v3 - v2) - (v0 - v1)&lt;br /&gt;    Q = (v0 - v1) - p&lt;br /&gt;    R = v2 - v0&lt;br /&gt;    S = v1&lt;br /&gt;&lt;br /&gt;    return P * x ** 3 + Q * x ** 2 + R * x + S&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Arr:&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.arr = None&lt;br /&gt;  &lt;br /&gt;    def size(self, w, h):&lt;br /&gt;        # Sanity checks&lt;br /&gt;        if w &gt; 400 or h &gt; 400:&lt;br /&gt;            raise Exception("Array size too large.")&lt;br /&gt;      &lt;br /&gt;        self.arr = [[0] * w for i in range(h)]&lt;br /&gt;  &lt;br /&gt;    def noise(self, w, h):&lt;br /&gt;        # Sanity checks&lt;br /&gt;        if w &gt; 400 or h &gt; 400:&lt;br /&gt;            raise Exception("Array size too large.")&lt;br /&gt;      &lt;br /&gt;        print "noise"&lt;br /&gt;     &lt;br /&gt;        # Create 2D array&lt;br /&gt;        self.arr = [[0] * w for i in range(h)]&lt;br /&gt;     &lt;br /&gt;        # Fill it with noise&lt;br /&gt;        for i in range(h):&lt;br /&gt;            for j in range(w):&lt;br /&gt;                r = random.random()&lt;br /&gt;                self.arr[i][j] = r &lt;br /&gt;     &lt;br /&gt;    def smooth(self, ite):&lt;br /&gt;        print "smooth"&lt;br /&gt;     &lt;br /&gt;        h = len(self.arr)&lt;br /&gt;        w = len(self.arr[0])&lt;br /&gt;      &lt;br /&gt;        for ps in range(ite):&lt;br /&gt;            x, y = 0, 0&lt;br /&gt;       &lt;br /&gt;        for i in self.arr:&lt;br /&gt;            for j in i:&lt;br /&gt;                lp = self.arr[(x - 1) % w][y]&lt;br /&gt;                rp = self.arr[(x + 1) % h][y]&lt;br /&gt;                up = self.arr[x][(y - 1) % h]&lt;br /&gt;                dp = self.arr[x][(y + 1) % h]&lt;br /&gt;                mp = self.arr[x][y]&lt;br /&gt;         &lt;br /&gt;                self.arr[x][y] = (lp + rp + up + dp + mp) / 5&lt;br /&gt;      &lt;br /&gt;                x += 1&lt;br /&gt;            x = 0&lt;br /&gt;            y += 1&lt;br /&gt;     &lt;br /&gt;    def normalize(self):&lt;br /&gt;        print "normalize"&lt;br /&gt;     &lt;br /&gt;        h = len(self.arr)&lt;br /&gt;        w = len(self.arr[0])&lt;br /&gt;        x, y = 0, 0&lt;br /&gt;     &lt;br /&gt;        max = 0&lt;br /&gt;        min = 1&lt;br /&gt;        # Find min and max&lt;br /&gt;        for i in self.arr:&lt;br /&gt;            for j in i:&lt;br /&gt;                val = self.arr[x][y]&lt;br /&gt;                if val &gt; max: &lt;br /&gt;                    max = val&lt;br /&gt;                if val &lt; min:&lt;br /&gt;                    min = val&lt;br /&gt;     &lt;br /&gt;                x += 1&lt;br /&gt;            x = 0&lt;br /&gt;            y += 1&lt;br /&gt;     &lt;br /&gt;        x, y = 0, 0&lt;br /&gt;        mult = 1 / (max - min)&lt;br /&gt;        for i in self.arr:&lt;br /&gt;            for j in i:&lt;br /&gt;                self.arr[x][y] -= min&lt;br /&gt;                self.arr[x][y] *= mult&lt;br /&gt;                x += 1&lt;br /&gt;            x = 0&lt;br /&gt;            y += 1&lt;br /&gt;     &lt;br /&gt;        return self.arr&lt;br /&gt;     &lt;br /&gt;     &lt;br /&gt;    def add(self, arr2):&lt;br /&gt;        w = len(self.arr)&lt;br /&gt;        h = len(self.arr[0])&lt;br /&gt;      &lt;br /&gt;        x, y = 0, 0&lt;br /&gt;        for j in self.arr:&lt;br /&gt;            for i in j:&lt;br /&gt;                self.arr[x][y] += arr2.arr[x][y]&lt;br /&gt;        &lt;br /&gt;                x += 1&lt;br /&gt;            x = 0&lt;br /&gt;            y += 1&lt;br /&gt;     &lt;br /&gt;    def div(self, val):&lt;br /&gt;        x, y = 0, 0&lt;br /&gt;        for j in self.arr:&lt;br /&gt;            for i in j:&lt;br /&gt;                self.arr[x][y] /= val&lt;br /&gt;        &lt;br /&gt;                x += 1&lt;br /&gt;            x = 0&lt;br /&gt;            y += 1&lt;br /&gt;     &lt;br /&gt;    def cosine_resize(self, mult):&lt;br /&gt;        # Sanity checks&lt;br /&gt;        if len(self.arr) * mult &gt; 400:&lt;br /&gt;            raise Exception("Array size too large (tried resizing).")&lt;br /&gt;      &lt;br /&gt;        print "linear resize"&lt;br /&gt;     &lt;br /&gt;        h = len(self.arr)&lt;br /&gt;        w = len(self.arr[0])&lt;br /&gt;      &lt;br /&gt;        w2 = w * mult&lt;br /&gt;        h2 = h * mult&lt;br /&gt;     &lt;br /&gt;        arr_new = [[0] * w2 for i in range(h2)]&lt;br /&gt;     &lt;br /&gt;        x, y = 0, 0&lt;br /&gt;        for i in self.arr:&lt;br /&gt;            for j in i:&lt;br /&gt;                p0 = self.arr[x][y]&lt;br /&gt;                p1 = self.arr[(x + 1) % w][y]&lt;br /&gt;                p2 = self.arr[x][(y + 1) % h]&lt;br /&gt;                p3 = self.arr[(x + 1) % w][(y + 1) % h]&lt;br /&gt;        &lt;br /&gt;                for ny in range(mult):&lt;br /&gt;                    for nx in range(mult):&lt;br /&gt;                        v0 = cosine_interp(p0, p1, float(nx) / mult)&lt;br /&gt;                        v1 = cosine_interp(p2, p3, float(nx) / mult)&lt;br /&gt;                        arr_new[x * mult + nx][y * mult + ny] = cosine_interp(v0, v1, float(ny) / mult)&lt;br /&gt;        &lt;br /&gt;                x += 1&lt;br /&gt;            x = 0&lt;br /&gt;            y += 1&lt;br /&gt;     &lt;br /&gt;        self.arr = arr_new&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;def render_arr(screen, arc):&lt;br /&gt;    print "render"&lt;br /&gt;    x, y = 0, 0&lt;br /&gt; &lt;br /&gt;    arr = arc.arr&lt;br /&gt; &lt;br /&gt;    size = len(arr)&lt;br /&gt;    for i in range(screen.get_height()):&lt;br /&gt;        for j in range(screen.get_width()):&lt;br /&gt;            val = arr[x % size][y % size]&lt;br /&gt;   &lt;br /&gt;            if val &gt; 1:&lt;br /&gt;                val = 1&lt;br /&gt;            if val &lt; 0:&lt;br /&gt;                val = 0&lt;br /&gt;   &lt;br /&gt;            val = int(val * 255)&lt;br /&gt;            val = val % 256&lt;br /&gt;   &lt;br /&gt;            color = (val, val, val)&lt;br /&gt;            screen.set_at((x, y), color)&lt;br /&gt;   &lt;br /&gt;            x += 1&lt;br /&gt;        x = 0&lt;br /&gt;        y += 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;gfx = GFX()&lt;br /&gt;&lt;br /&gt;run = 1&lt;br /&gt;clock = pygame.time.Clock()&lt;br /&gt;&lt;br /&gt;pw, ph = 256, 256&lt;br /&gt;depth = 5&lt;br /&gt;&lt;br /&gt;arr = []&lt;br /&gt;farr = Arr()&lt;br /&gt;farr.size(pw, ph)&lt;br /&gt;&lt;br /&gt;# Generate perlin noise&lt;br /&gt;for i in range(depth):&lt;br /&gt;    arr.append(Arr())&lt;br /&gt; &lt;br /&gt;    d = 2 ** i&lt;br /&gt; &lt;br /&gt;    arr[-1].noise(pw / d, ph / d)&lt;br /&gt;    arr[-1].smooth(3)&lt;br /&gt;    arr[-1].cosine_resize(d)&lt;br /&gt;    arr[-1].div(2 ** (depth - i))&lt;br /&gt;&lt;br /&gt;    farr.add(arr[-1])&lt;br /&gt;&lt;br /&gt;farr.normalize()&lt;br /&gt;render_arr(gfx.screen, farr)&lt;br /&gt;&lt;br /&gt;while run:&lt;br /&gt;    events = pygame.event.get()&lt;br /&gt;&lt;br /&gt;    for event in events:&lt;br /&gt;        if event.type == QUIT:&lt;br /&gt;            run = 0&lt;br /&gt;&lt;br /&gt;    pygame.display.flip()&lt;br /&gt;&lt;br /&gt;    clock.tick(60)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Numpy: &lt;b&gt;00.639 seconds!&lt;/b&gt;&lt;br /&gt;&lt;div  style="overflow: auto; width: 100%; height: 300px;font-size:11px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import random&lt;br /&gt;import math&lt;br /&gt;import time&lt;br /&gt;import numpy&lt;br /&gt;&lt;br /&gt;import pygame&lt;br /&gt;from pygame.locals import *&lt;br /&gt;&lt;br /&gt;class GFX():&lt;br /&gt;    def __init__(self):&lt;br /&gt;        pygame.init()&lt;br /&gt;&lt;br /&gt;        self.display_flags = DOUBLEBUF&lt;br /&gt;        rect = self.width, self.height = 256, 256&lt;br /&gt;    &lt;br /&gt;        if pygame.display.mode_ok(rect, self.display_flags):&lt;br /&gt;            self.screen = pygame.display.set_mode(rect, self.display_flags)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def linear_interp(a, b, x):&lt;br /&gt;    return a * (1 - x) + b * x&lt;br /&gt;&lt;br /&gt;def cosine_interp(a, b, x):&lt;br /&gt;    f = (1 - math.cos(x * math.pi)) * 0.5&lt;br /&gt;    return a * (1 - f) + b * f&lt;br /&gt;&lt;br /&gt;def cubic_interp(v0, v1, v2, v3, x):&lt;br /&gt;    p = (v3 - v2) - (v0 - v1)&lt;br /&gt;    Q = (v0 - v1) - p&lt;br /&gt;    R = v2 - v0&lt;br /&gt;    S = v1&lt;br /&gt;&lt;br /&gt;    return P * x ** 3 + Q * x ** 2 + R * x + S&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Arr:&lt;br /&gt;    def __init__(self, w, h):&lt;br /&gt;        self.arr = numpy.zeros((w, h), float)&lt;br /&gt;  &lt;br /&gt;    def size(self, w, h):&lt;br /&gt;        # Sanity checks&lt;br /&gt;        if w &gt; 400 or h &gt; 400:&lt;br /&gt;            raise Exception("Array size too large.")&lt;br /&gt;      &lt;br /&gt;        self.arr = [[0] * w for i in range(h)]&lt;br /&gt;  &lt;br /&gt;    def noise(self, w, h):&lt;br /&gt;        # Sanity checks&lt;br /&gt;        if w &gt; 400 or h &gt; 400:&lt;br /&gt;            raise Exception("Array size too large.")&lt;br /&gt;      &lt;br /&gt;        print "noise"&lt;br /&gt;     &lt;br /&gt;        # Create 2D array&lt;br /&gt;        self.arr = numpy.random.random_sample((w, h))&lt;br /&gt;     &lt;br /&gt;    def smooth(self, ite):&lt;br /&gt;        print "smooth"&lt;br /&gt;&lt;br /&gt;        for i in range(ite):&lt;br /&gt;            soften = numpy.array(self.arr)&lt;br /&gt;&lt;br /&gt;            soften[1:,:] += self.arr[:-1,:]&lt;br /&gt;            soften[0,:] += self.arr[-1,:]&lt;br /&gt;&lt;br /&gt;            soften[:-1,:] += self.arr[1:,:]&lt;br /&gt;            soften[-1,:] += self.arr[0,:]&lt;br /&gt;&lt;br /&gt;            soften[:,1:] += self.arr[:,:-1]&lt;br /&gt;            soften[:,0] += self.arr[:,-1]&lt;br /&gt;&lt;br /&gt;            soften[:,:-1] += self.arr[:,1:]&lt;br /&gt;            soften[:,-1] += self.arr[:,0]&lt;br /&gt;&lt;br /&gt;            self.arr = soften / 5&lt;br /&gt;     &lt;br /&gt;    def normalize(self):&lt;br /&gt;        print "normalize"&lt;br /&gt;     &lt;br /&gt;        self.arr = (self.arr - self.arr.min()) / (self.arr.max() - self.arr.min()) &lt;br /&gt;     &lt;br /&gt;        return self.arr&lt;br /&gt;     &lt;br /&gt;     &lt;br /&gt;    def add(self, arr2):&lt;br /&gt;        self.arr += arr2.arr&lt;br /&gt;     &lt;br /&gt;    def div(self, val):&lt;br /&gt;        self.arr /= val&lt;br /&gt;     &lt;br /&gt;    def cosine_resize(self, mult):&lt;br /&gt;        # Sanity checks&lt;br /&gt;        if len(self.arr) * mult &gt; 400:&lt;br /&gt;            raise Exception("Array size too large (tried resizing).")&lt;br /&gt;      &lt;br /&gt;        print "linear resize"&lt;br /&gt;        w, h = self.arr.shape&lt;br /&gt;        w2, h2 = w*mult, h*mult&lt;br /&gt;&lt;br /&gt;        arr_new = numpy.zeros((w2, h2), float)&lt;br /&gt;        p0 = numpy.copy(self.arr)&lt;br /&gt; &lt;br /&gt;        p1 = numpy.zeros((w, h), float) &lt;br /&gt;        p1[:-1, :] = self.arr[1:, :]  &lt;br /&gt;        p1[-1, :] = self.arr[0, :]&lt;br /&gt;&lt;br /&gt;        p2 = numpy.zeros((w, h), float)   &lt;br /&gt;        p2[:, :-1] = self.arr[:, 1:]  &lt;br /&gt;        p2[:, -1] = self.arr[:, 0]&lt;br /&gt;&lt;br /&gt;        p3 = numpy.zeros((w, h), float)&lt;br /&gt;        p3[:-1, :-1] = self.arr[1:, 1:]&lt;br /&gt;        p3[-1, :] = self.arr[0, :]&lt;br /&gt;        &lt;br /&gt;        p3[:, -1] = self.arr[:, 0]&lt;br /&gt;        &lt;br /&gt;        for nx in range(mult):&lt;br /&gt;            v0 = linear_interp(p0, p1, float(nx)/mult)&lt;br /&gt;            v1 = linear_interp(p2, p3, float(nx)/mult)&lt;br /&gt;            for ny in range(mult):&lt;br /&gt;                arr_new[nx::mult, ny::mult] = linear_interp(v0, v1, float(ny)/mult)&lt;br /&gt;            &lt;br /&gt;        self.arr = arr_new&lt;br /&gt;&lt;br /&gt;gfx = GFX()&lt;br /&gt;&lt;br /&gt;run = 1&lt;br /&gt;clock = pygame.time.Clock()&lt;br /&gt;&lt;br /&gt;# run through 10 times for benchmarking purposes&lt;br /&gt;t0 = pygame.time.get_ticks()&lt;br /&gt;for it in xrange(10):&lt;br /&gt;    pw, ph = 256, 256&lt;br /&gt;    depth = 5&lt;br /&gt;&lt;br /&gt;    farr = Arr(pw, ph)&lt;br /&gt;    &lt;br /&gt;    # Generate perlin noise&lt;br /&gt;    for i in range(depth):&lt;br /&gt;        d = 2 ** i&lt;br /&gt;        &lt;br /&gt;        arr = Arr(pw,ph)&lt;br /&gt;        arr.noise(pw/d, ph/d)&lt;br /&gt;        arr.smooth(3)&lt;br /&gt;        arr.cosine_resize(d)&lt;br /&gt;        arr.div(2.**(depth-i))&lt;br /&gt;&lt;br /&gt;        farr.add(arr)&lt;br /&gt;&lt;br /&gt;    farr.normalize()&lt;br /&gt;&lt;br /&gt;pygame.surfarray.use_arraytype("numpy")&lt;br /&gt;print farr.arr.shape&lt;br /&gt;&lt;br /&gt;tarr = numpy.zeros((256,256,3))&lt;br /&gt;tarr[:,:,0] = farr.arr&lt;br /&gt;tarr[:,:,1] = farr.arr&lt;br /&gt;tarr[:,:,2] = farr.arr&lt;br /&gt;&lt;br /&gt;pygame.surfarray.blit_array(gfx.screen, (tarr *256).astype(int))&lt;br /&gt; &lt;br /&gt;print "elapsed: ",pygame.time.get_ticks()-t0&lt;br /&gt;&lt;br /&gt;while run:&lt;br /&gt;    events = pygame.event.get()&lt;br /&gt;&lt;br /&gt;    for event in events:&lt;br /&gt;        if event.type == QUIT:&lt;br /&gt;            run = 0&lt;br /&gt;&lt;br /&gt;    pygame.display.flip()&lt;br /&gt;    clock.tick(60)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6549773495273813421-2313840373166311868?l=tommih.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tommih.blogspot.com/feeds/2313840373166311868/comments/default' title='Lähetä kommentteja'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6549773495273813421&amp;postID=2313840373166311868' title='1 kommenttia'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/2313840373166311868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6549773495273813421/posts/default/2313840373166311868'/><link rel='alternate' type='text/html' href='http://tommih.blogspot.com/2008/06/messing-around-with-python-2d-arrays.html' title='Messing around with Python 2D arrays'/><author><name>tommi</name><uri>http://www.blogger.com/profile/13157537066277753126</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
