0

This is a Swift Playground that shows an image of the Lorenz Attractor. I have three questions. I will consider this question answered if only the first question gets answered.

  1. It's not that fast to begin with but after about 8000-9000 iterations it gets extremely slow. Any ideas why?
  2. Why is drawRect called twice?
  3. Are there any recommended ways for decent pixel pushing performance?
// Change platform to OS X when opening Playground.
// alt + cmd + enter to show Assistant editor and see resulting image.

import Cocoa
import XCPlayground

let width = 600.0, height = 500.0

class CustomView: NSView {
    override init(frame: NSRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder);
    }

    override func drawRect(dirtyRect: NSRect) {
        lorentzAttractor()
    }

    func lorentzAttractor() {
        var x = 0.1 , y = 0.0, z = 0.0, t = 0.0
        for i in 1...4242 {
            let x1 = x + 0.01 * 10 * (y - x)
            let y1 = y + 0.01 * (x * (28 - z) - y)
            let z1 = z + 0.01 * (x * y - 2.66 * z)
            x = x1
            y = y1
            z = z1

            let phys_x = width / 2 + 12 * x
            let phys_y = 25 + 8 * z

            NSRectFill(NSMakeRect(CGFloat(phys_x), CGFloat(phys_y), 1, 1))
        }
    }
}

XCPShowView("Lorenz Attractor", CustomView(frame:
    NSRect(x: 0, y: 0, width: width, height: height)))

The Lorenz Attractor and the output of the code.

Jonas Elfström
  • 30,834
  • 6
  • 70
  • 106
  • Are you kidding? I bogged down at 2500 iterations and had to force quit Xcode! :) – matt Jan 02 '15 at 02:16
  • Though @matt's answer may end up all that you need, in general, doing a "fill rect" operation on single pixels is not how you'd do performant graphics drawing-- you can look into getting the `NSGraphicsContext` and draw directly into it. This answer (http://stackoverflow.com/a/24139701/73297) might provide some useful hints if you are interested in investigating something like that. – Ben Zotto Jan 02 '15 at 02:45
  • @BenZotto That's great advice, but I didn't even look at the code or the algorithm - so, indeed, I may not be answering the OP's question at all, ultimately. I'm just pointing out that working in a playground isn't even about performance. I pasted that OP's code into a playground, ran slower and slower for 10 seconds, and finally just ground to a halt. That's kind of different from badda-bing badda-boom in .013 seconds. :) Playgrounds have _insane_ amounts of extra overhead; they are not at all for this kind of thing. – matt Jan 02 '15 at 03:25

1 Answers1

0

The problem is that playgrounds suck. That's a technical programming term so I claim my prize, please!

Seriously, I ran your code as an actual app, and put time logging before and after the call to lorentzAttractor(), and got this:

1420165414.02522
1420165414.03103

So the whole thing ran on the order of a 100th of a second. Not awful. (EDIT: I later did a few subsequent tests, under more controlled conditions, where we were not doing this at launch, and got slightly better times, consistently about 0.013 seconds.)

Returning to my real point: do not use playgrounds for anything. They are the work of the devil. And certainly not for testing performance of anything. Playgrounds have no connection whatever with reality.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I did as you said and now I'm drawing [this](https://www.dropbox.com/s/x3wuez822rglnn5/lorenz_attractor_cocoa_swift.png?dl=0) in a split second. Thanks! – Jonas Elfström Jan 02 '15 at 22:26
  • Even though it's neither fast nor idiomatic I published it on GitHub. https://github.com/jonelf/Lorenz-Attractor – Jonas Elfström Jan 02 '15 at 23:01