
Sleep sort (2011) - olalonde
http://dis.4chan.org/read/prog/1295544154/
======
antics
Just to be 100% clear, in case anyone who is new to the field stumbles on this
thread, this is NOT breaking math or anything. This is a fun, but totally
normal result.

First of all, there are quite a few linear time sorting algorithms. Radix,
pigeonhole, and counting sort are all linear time sorting algorithms. The
popular result that any comparison-based sorting algorithm works in O(n log n)
applies _specifically_ to comparison-based sorting algorithms, and not those
like the above. So, even if you ignore the underlying mechanics of the OS
scheduler and assume sleep works "perfectly", the result would not that
unusual.

Second off, in the comments there appears to be considerable time worrying
about the technicalities of the scheduler, the nondeterministic nature of
sleep, and so on, and whether this really implies linear time bound. IMHO
these are not worth worrying about because we already have linear time sorting
algorithms. It's fine to assume the scheduler adds no significant asymptotic
cost here, even if we know differently.

Third off, remember that all of these sorting bounds assume machines of the
Von Neumann architecture. In particular, this model assumes constant time
memory and constant time comparison operations. In cases where you're
comparing really big numbers, these bounds get worse. This is easy to forget,
but worth remembering just since we're on the subject anyway.

~~~
wcrichton
This is not "linear time" in any decent sense--we shouldn't conflate the
number of elements with the size of the elements (in this case, O(max element)
is actually exponential in the input size!).

~~~
antics
This isn't really right. If the numbers can be arbitrary in size, then you
can't compare them in constant time, which means that comparison-based sorts
are quadratic.

This is directly related to my third point. Traditional analysis of sorting
algorithms assumes the Von Neumann architecture, and in particular, it assumes
constant-time comparisons.

~~~
flebron
The computational model will define what you can and cannot compare in
constant time. It is perfectly fine to say that comparing elements of
arbitrary size is a constant time operation - that's precisely what a
computational model is: an enumeration of the operations that are considered
basic.

~~~
antics
Yeah, I know.

Go read the parent again. The author claims that sorting in this case takes
time proportional to the size of largest element, and I'm saying, if it takes
time proportional to the space consumption of in the largest element
(presumably where the cost of the sort comes from), you can't define a
computational model where comparison takes constant time -- it still has to
read the digits, which we know takes linear time.

If your point is that you can define a model of computation with
contradictions in it, then you should rethink whether what you are saying here
is even relevant to the thread at all.

~~~
Retric
You can shurt circuit comparisons but that's not always going to happen.
Consider it's completly reasonable to assume long int is sorted as fast as int
on a 128 bit CPU. If nothing else it's useful to have a fairly long cycle even
if you could in theory use a 20GHz CPU that has some comparisons finish in 4
cycles and others just 1. Sure, it might be slightly faster than a 5GHz CPU
with constant time comparisons, but the added complexity is not free.

~~~
antics
I am not sure I understand your point here.

Short circuiting comparisons is still linear for integers of unbounded size.
But besides that, it's incredibly common to assume that 64-bit primitives are
done in constant time, because to the asymptotic analysis, what matters is
that the integers are _bounded_ in size. As long as it's bounded, the
asymptotic analysis here doesn't care -- you can pick any size you want, as
long as it's bounded.

One thing to keep in mind here (which it seems you are maybe confused about)
is that these bounds are _asymptotics_ of the input size generally, and have
very little to say about any particular choice of input size. 64-bit, 32-bit,
whatever, it doesn't matter, if the size of the operands is bounded, the
they're the same thing to the asymptotic analysis. As long as they're bounded,
you can say that the operations on those operands is proportional to a
constant times the (bounded) size of the operands.

The consequence of this is that when you deal with operands of _unbounded_
size, all of this asymptotic analysis goes right out the window. You can't
possibly have a meaningful comparison operator, for example, that operates in
constant time on unbounded integers.

~~~
Retric
With parrell analysis comparisons are log N operations. P1 compares N bits, P2
compares N bits, if use P1 unless it's equal then use P2.

Short circuting cuts that to log(log(N)) on average and log(N) worst case.

It's actually generally faster to compare X bytes of Vary large numbers than X
Bytes of long int's. Degenerate case being 2 numbers of x/2 bytes.

Anyway, the point is treating log(log(N)) as constant is generally reasonable
especially when N is small.

~~~
antics
The discussion is about big O, yes? This isn't really relevant to our
discussion. Parallel analysis and average case, for the purposes of the
discussion here, are fancy games you can try to play to get nice bounds, but
they do not really have any impact on the big O of these algorithms.

~~~
Retric
"You can't possibly have a meaningful comparison operator, for example, that
operates in constant time on unbounded integers."

We don't really deal with unbound integers worst case is something like
2^(2^1,000,000,000,000,000,000)) before we can't actually store them.

Even then log of log of N makes random numbers of that size practically
constant time to compare. Put another way there is less than 1 in 2^64 you
need to do more than 3 comparisons and less than one in 2^128 you need more
than 4. One for length, one for the chunk which might be just one bit and one
more for the next 64 bits. Sure that might happen, but reolistically random
input is unlikely to need many comparisons.

Stings on the other hand are more of an issue.

~~~
antics
Retric, look.

Do you realize that the whole point of asymptotic analysis is that _we do not
care_ what integers we "really" deal with? These bounds specifically deal with
sorting arbitrary data of unbounded size, and _no other assumptions_.

Do you understand? No assumption that we can use parallelism. No games with
integers you see in "real life". None of that is relevant. You can't play
games with practicalities to get a better bound. This is the general bound,
and if you fiddle with it to get something else, you are changing the scope of
the question to be something else entirely.

If you want to have a discussion about those other models, fine, but that's
not the discussion we're having.

~~~
Retric
What your talking about is a type of overly simplified model that's irrelevant
for actual computing. My point is there are other models out there. If you
actually want the fastest algorithm out there you need to design it for actual
hardware with finite data, cache, limited registers, limited ram, and sometime
aproximating a real instruction set etc.

However, by changing your assumptions you can still use O notation with more
complex models.

~~~
antics
Yes, everyone knows this. This is not helpful.

------
danso
Sadly, the somewhat lengthy Wikipedia entry for Sleep sort was deleted. Here's
archive.org's version:

[https://web.archive.org/web/20110622073615/http://en.wikiped...](https://web.archive.org/web/20110622073615/http://en.wikipedia.org/wiki/Sleep_sort)

Reading through Wikipedia's existing pages for other esoteric sorts makes me
laugh as I did when reading Hitchhiker's Guide to the Galaxy's various entries
for scientific theories (e.g. Bistromathics)...There's Bogosort, Stooge sort,
American flag sort, and my favorite, "Gnome sort", named thusly because "that
is 'how a gnome sorts a line of flower pots'"
[http://en.wikipedia.org/wiki/Gnome_sort](http://en.wikipedia.org/wiki/Gnome_sort)

~~~
chriswarbo
I like the comparison between the incredibly inefficient Bogosort:

    
    
        1) Shuffle the list.
        2) If it's sorted, halt.
        3) If it's not sorted, go to step 1.
    

and the incredibly efficient Quantum Bogosort:

    
    
        1) Shuffle the list.
        2) If it's sorted, halt.
        3) If it's not sorted, destroy the Universe.
    

According to the Many Worlds interpretation, step (1) creates multiple
Universes, each with a different ordering of the list. Step (3) ensures that,
by the anthropic principle, we must be in a Universe where the list was sorted
correctly (otherwise we wouldn't be around to observe anything).

~~~
TheSoftwareGuy
how does it destroy the universe though? I am really not very familiar with
things in the quantum world and that kind of stuff.

~~~
chriswarbo
That's an implementation detail ;)

------
shultays
Didn't saw this post before

 _I heartily disagree with all the attempts to downplay the brilliance of the
sleep sort algorithm. Many of you have missed the important point that while
traditional sorting algorithms can only utilize one core, sleep sort has the
capacity to use the full power of a massively parallel execution environment._

 _Given that you need nearly no computing in each of the threads, you can
implement them using low-power CPUs, so this is in fact a GREEN COMPUTING
algorithm._

 _Oh, and did I mention that the algorithm can also run inside a cloud...?_

 _Sure, you 're a genius!_

------
ambrop7
One should know that it is the timer scheduler of the kernel which ends up
doing the sorting. With Linux, this is probably a red-black tree[1], so
performance of sleep sort (when it works) is O(n *log(n)).

[1]
[https://www.kernel.org/doc/Documentation/timers/hrtimers.txt](https://www.kernel.org/doc/Documentation/timers/hrtimers.txt)

------
majke
With fluxcapacitor it will run in fraction of a second!

[https://github.com/majek/fluxcapacitor#basic-
examples](https://github.com/majek/fluxcapacitor#basic-examples)

$ ./fluxcapacitor examples/sleep_sort.sh 1 4 20 3 55

~~~
ambrop7
I remember a few years ago, I hacked up the Wine source code so some skiing
game would run at half speed. It totally worked :) It was even simpler than
fluxcapacitor since you don't need to hook anything but just change the
implementation of some time related functions.

------
Nimi
Pardon the shameless plug, but I've recently used a similarly unorthodox
approach for replacing the heap inside Dijkstra's algorithm, and got a speedup
- I use an array indexed by the vertices' current distances, and scan it from
start to finish.

A paper is currently making the rounds, would love to hear feedback:

[https://www.dropbox.com/s/zy1gx1azfvvqm6i/NetSciComm%20versi...](https://www.dropbox.com/s/zy1gx1azfvvqm6i/NetSciComm%20version%2C%20December%202014.pdf?dl=0)

------
angersock
For the record, in that thread, there are implementations in Bash, Erlang,
Haskell (I think), Perl, C, and Racket. It also is interspersed with
entertaining banter and unentertaining racism. So, basically, a more caustic
more technical less orderly version of HN. Think about that.

There's a reason 4chan should be considered a national...maybe not treasure,
but it's pretty awesome.

------
SwellJoe
Previous discussion:
[https://news.ycombinator.com/item?id=2657277](https://news.ycombinator.com/item?id=2657277)

Pretty sure it's been posted a couple other times, but I'm on a tablet at the
moment.

------
perlgeek
Recently I wrote about sleepsort for the Perl 6 advent calendar, mostly as a
fun topic to talk about threads, promises etc.

[http://perl6advent.wordpress.com/2014/12/23/webscale-
sorting...](http://perl6advent.wordpress.com/2014/12/23/webscale-sorting-of-
the-sleepy-kind/)

------
bluecalm
C implementation for Windows:

    
    
      #include <stdio.h>
      #include <windows.h>
      #include <process.h>
      
      void sleep_on_it(void* param)
      {
          int n = *(int*)param;
          Sleep(n);
          printf("%d ", n);
      }
      
      int main(int argc, char **argv)
      {
          int ar[argc];
          HANDLE threads[argc-1];
          for (int i = 1; i < argc; i++){
              ar[i] = atoi(argv[i]);
              threads[i-1] = (HANDLE)_beginthread(&sleep_on_it, 0,  &(ar[i]));
          }
          WaitForMultipleObjects(argc-1, threads, TRUE, INFINITE);
      }
    

Compile with gcc -std=c99 (because of VLA's it won't work in Visual Studio).

Example:

D:>sleepsort 1000 9 2 150 1 7 17 624

1 2 7 9 17 150 624 1000

------
xianshou
Radix sort, with time as the buckets...stylish.

------
taternuts
This guy makes the rounds every once in awhile it seems. Here's a
/r/dailyprogrammer thread with solutions in various languages:
[http://www.reddit.com/r/dailyprogrammer/comments/yqydh/82420...](http://www.reddit.com/r/dailyprogrammer/comments/yqydh/8242012_challenge_91_easy_sleep_sort/)

------
avodonosov
javascript version (faster):

    
    
        var input = [5, 3, 6, 3, 6, 3, 1, 4, 7];
    
        var timeAxis = [];
        // Put every element to the corresponding time point.
        // Time point would hold an array, as we can have
        // equal elements.
        for (var i = 0; i < input.length; i++) {
            elem = input[i];
            timeAxis[elem] = [elem].concat(timeAxis[elem] || []);
        }
    
        // skip all empty (UNDEFINED) time points
        // and contact all the arrays:
        var sorted = timeAxis.reduce(function (accum, cur) {
                                         return cur ? accum.concat(cur) : accum},
                                    []);
        console.log(sorted)

~~~
avodonosov
The speedup is from usage of _virtual time_, which we don't need to wait for.

------
codezero
This is my new favorite after bogosort.

I'm sad nobody has implemented my idea, rock, paper, scissors sort.

~~~
kevinwang
And what, exactly, is rock paper scissors sort?

~~~
codezero
The comparison function is a game of Rock Paper Scissors with the winner being
given the 'greater than' position. Games proceed until all items are in sorted
order :)

------
matheusbn
Do you mind if I submit a javascript version!?

[http://js.do/code/48519](http://js.do/code/48519)

[http://js.do/code/48526](http://js.do/code/48526) (Optimized milliseconds).
:)

------
logicallee
if you'd like to trade space for time, here is another sort with _no_
comparisons: [http://codepad.org/0k2Ou2Db](http://codepad.org/0k2Ou2Db)

~~~
vlad003
I don't know Perl, so I rewrote it in Python in an attempt to understand
what's going on:
[https://gist.github.com/vlad003/35105af5892cb9cc5051](https://gist.github.com/vlad003/35105af5892cb9cc5051)

I'm not storing key,value pairs for elements that don't exist (not sure what
the Perl code's doing), so it shouldn't be too bad in terms of space used.

~~~
woadwarrior01
I'm not entirely sure about this, but it looks more like Counting sort [1],
than Pigeonhole sort.

[1]:
[https://en.wikipedia.org/wiki/Counting_sort](https://en.wikipedia.org/wiki/Counting_sort)

------
veesahni
(impure) ruby implementation:

ruby -e '[3,1,2].each{|n| system("sleep #{n} && echo #{n} &")}'

