High-Resolution Mandelbrot in Obfuscated Python

September 26, 2011

Here’s a followup to last month’s post about Penrose Tiling in Obfuscated Python.

The Mandelbrot set is a traditional favorite among authors of obfuscated code. You can find obfuscated code in C, Perl, Haskell, Python and many other languages. Nearly all examples render the Mandelbrot set as ASCII art.

The following Python script, on the other hand, begins as ASCII art:

_                                      =   (
                                        255,
                                      lambda
                               V       ,B,c
                             :c   and Y(V*V+B,B,  c
                               -1)if(abs(V)<6)else
               (              2+c-4*abs(V)**-0.4)/i
                 )  ;v,      x=1500,1000;C=range(v*x
                  );import  struct;P=struct.pack;M,\
            j  ='<QIIHHHH',open('M.bmp','wb').write
for X in j('BM'+P(M,v*x*3+26,26,12,v,x,1,24))or C:
            i  ,Y=_;j(P('BBB',*(lambda T:(T*80+T**9
                  *i-950*T  **99,T*70-880*T**18+701*
                 T  **9     ,T*i**(1-T**45*2)))(sum(
               [              Y(0,(A%3/3.+X%v+(X/v+
                               A/3/3.-x/2)/1j)*2.5
                             /x   -2.7,i)**2 for  \
                               A       in C
                                      [:9]])
                                        /9)
                                       )   )

It renders the Mandelbrot set as a full-color, anti-aliased, 1500×1000 image. Click to enlarge:

No third-party libraries are required — just pure Python. However, it will only run on Python 2.5 – 2.7; Python 3 is not supported. The output file is written to M.bmp, in Windows bitmap format.

It runs very slowly, taking about 18 minutes on my 1.86 GHz Core 2 Duo (or 9 minutes using PyPy). With some modifications, it’s possible to make this code run up to 20 times faster. However, doing so requires sacrificing either code size or image quality.

If you’re willing to leave the script running for a few hours, you can increase the image resolution on line 8. (Just make sure the width is divisible by 4.) The resulting detail is quite nice. Here are some 1:1 pixel excerpts from an image rendered at 7200×4800:

The entire 7200×4800 image is too large to share here, but it’s perfect for making prints. So that’s what I did! Notice the Python script superimposed in the lower-left corner. Is this the first poster to include its own source code?

If this kind of thing gives you kicks, you can order your own print (or a coffee mug) at CafePress.

38 Comments

  • Reply renzio on September 26, 2011

    Now do a script which generates a svg file

    • Reply Vlofgren on September 26, 2011

      Mandelbrot Fractals are inherently raster-oriented. An SVG representation would be woefully inefficient. Something like a Koch Snowflake, on the other hand, would be quite easy to represent as an SVG.

      • Reply Adrian Petrescu on September 26, 2011

        I think he was joking. I’m pretty sure an SVG of the Mandelbrot set would have an infinite size (since I don’t think SVG is able to compute it on-the-fly).

      • Reply Frankie Robertson on September 26, 2011

        It may be a reasonable format for a trace of the boundaries of an estimate of the Mandelbrot set however.

  • Reply Ian Hawkins on September 26, 2011

    Simply brilliant,I love it

  • Reply Mark on September 26, 2011

    Awesome. Am running one now to have printed up on canvas.

  • Reply Nick Coghlan on September 26, 2011

    Very cool!

    What would it take to port to Python 3.2? Change the string literal to a b’BM’ bytes literal and change the ‘/’ operations to ‘//’?

    • Reply Jeff Preshing on September 26, 2011

      Here are the necessary changes for Python 3.2:

      • On line 11, change 'BM' to b'BM' so that it’s valid to concatenate the result of struct.pack.
      • On line 11, change or to and since write now returns an integer.
      • Each element of the tuple returned by the lambda expression on line 12 must be converted to int, to satisfy the stricter type checking of struct.pack. (The original call to pack is technically invalid, but works in Python 2 anyway.)
  • Reply debrice on September 26, 2011

    Maybe sharing the large version through bittorrent would allow everybody to see it

  • Reply ormaaj on September 26, 2011

    ASCII-art obfuscated program in the shape of the boundary of the Mandelbrot set which takes an argument of coordinates, and generates a new ASCII-art program zoomed by some factor on those coords which takes new coords to generate new programs ad infinitum.

  • Reply Alex on September 26, 2011

    Very cool, but how can you change the color from blue, to say some other color, or maybe change any of the other colors?

  • Reply Lauro on September 27, 2011

    Ran some tests with CPython 2.6 from Ubuntu 10.10 64bits and PyPy 1.6 pre-built on a Core 2 Duo @2.8Ghz MacBook Pro. Image size was 7500×5000.

    CPython: 2h46m
    PyPy: 54m

  • Reply Ywen on September 28, 2011

    OR we could achieve it twice as fast if we notice that it is… _symmetric_!

    • Reply Jeff Preshing on September 28, 2011

      Yep, tried that! But every implementation increased code size, which ran counter to my goal of achieving the best image quality with the smallest code.

  • Reply Ywen on September 28, 2011

    I achieved a 15,000×10,000 generation.
    Trying 35,556×20,000 to get a 16/9 format……..
    It doesn’t work for higher resolutions because the code apparently uses packed 1-byte integers.

  • Reply Tony "pyTony" Veijalainen on September 30, 2011

    I would not say this code pyTonyc but it is funny in it’s way. If you want to do reasonable fast Mandelbrot with Python you may grab Shedskin and try my example code Mandelbrot, also found in little different form in DaniWeb code snippets: http://www.daniweb.com/software-development/python/code/371844. At least it is more interactive.

  • Reply Jose M Balaguer on October 4, 2011

    ERROR: It gives a “SyntaxError: invalid syntax” in line 6 !!!

    (I’m using Python 2.3, on Windows XP)

  • Reply dnuske on October 4, 2011

    estas pasado

  • Reply urcindalo on October 5, 2011

    Thanks for the code. I was amazed at first glance and in love at first run… hahaha

    Generating now a 9999×6666 (to respect original ASCII art) on my Intel Core2 Quad CPU Q8300 @ 2.50GHz running a 64 bit Gentoo Linux box with python 2.7.1. I’ll let you know the approximate processing time.

    • Reply Jeff Preshing on October 5, 2011

      Hi urcindalo. I should have mentioned it in the article, but the code requires the width to be a multiple of 4 — otherwise, the BMP data will have invalid alignment.

  • Reply Xzibit on October 5, 2011

    Yo dawg, I heard you like Mandelbrot so I put a Mandlebrot in your Mandlebrot so you can render it while you render it.

  • Reply Danny on November 3, 2011

    I’m trying to run this and the thumbnail seems to update properly, but when I try to view the image in Picture Manager it simply loads a red x, when I open it in MS Paint I get an error: “A Sharing violation occurred while accessing ”Desktop\M.bmp.” any thoughts as to the problem?

  • Reply Danny on November 3, 2011

    OK, so now it works. . . Seems that python still had a hold on the file and wouldn’t allow it to be accessed. Once I ran a new python script it released the file and I could view it properly.

    COOL!

  • Reply Jordan on December 18, 2011

    How can I get up and running with generating BMPs like this? I don’t really want to use PIL. Just something basic, like coloring pixels.

  • Reply Jimmy on January 8, 2012

    I would love if you would make a blog post explaining this and providing the obfuscated like you did for the penrose tiling.

    • Reply Grayson Carroll on February 8, 2012

      I second the comment requesting an explanation similar to the penrose code you worked on,
      I got a lot out of that. If you could give us some hints on the actual process of obfuscation, that could be
      very useful as well.

  • Reply naren on November 13, 2012

    This is surprising and brilliant…. love it

  • Reply Peter Boothe on December 18, 2012

    Very cool!

    This is at least the second poster to contain its own source code, though. ;)

  • Reply Kee on December 24, 2012

    Very interesting code. I’ve started to re-engineer the code above to the more readable format and see that author used many non-obvious python tricks in the code like:

    (lambda: ‘do_something’)()

    Very nice work, hope to see some other interesting realizations.

  • Reply Micha on February 14, 2013

    Hi,
    I would like to test the Python script but I can“t find the link. Can anyone tell me, where I can find the script?

    Thanks in advance.

  • Reply Mark on March 29, 2013

    Hi Jeff, really original work. Loved it! I still can’t work it out but it ran fine.

  • Reply Chenna on April 9, 2013

    Hi Jeff,
    I don’t know about this ASCII art. Can you please email me the actual code. Thanks a lot.

Leave a Reply