Bead sort (a.k.a Abacus sort, or Gravity sort) is a sorting algorithm that can sort a list of positive integers.
Belonging to a class of natural algorithms, It uses (/simulates) gravity to sort an input list.
The sort algorithm accomplishes this in three acts –
As simple as the 3-step description makes it seem, the algorithm doesn’t translate as easily to software.
It is usually implemented as a 2D matrix representing the abacus/beads state and beads are dropped level-by-level.
Here’s a reference implementation in python –
The above implementation uses O(n*max) storage⁽¹⁾, and has a time complexiy of O(n*max).
(n: size of the input list max: maximum element in the input list)
A O(n*max) storage efficiency is terrible for a sorting algorithm.
The time efficiency isn’t as terrible though, it can potentially outperform O(nlogn) comparison-based sort algorithms for very small numbers (i.e. max << n).
For instance, if all numbers in the input list are below 100, then the algorithm runs in almost linear time for large n.
But log(n) grows far too slow for a meaningful ‘small numbers set’ for the above algorithm to outperform O(nlogn).
For context, log₂(10⁹) ≈ 30.
However, the algorithm does have one last redeeming quality.
It yields well to parallelism.
In theory, with ‘max’ concurrent threads, each thread can independently drop the beads in their respective columns in linear time.
In this article, I outline an implementation with O(n) space, and O(n*(max-min)) time efficiency.
(n: size of the input list max: maximum element in the input list min: minimum element in the input list)
Full disclosure: I didn’t set out to improve the efficiency of bead-sort.
A random bug in a completely unrelated program pointed me towards an alternate, more efficient implementation for bead-sort.
Specifically, I was trying to print a histogram for a given set of numbers using ‘*’s for building blocks.
An input of [2,6,1,4,3] is to print the following pattern –
* * * * * * * * * * * * * * * *
The solution is simple enough –
1. There are going to be 'max' rows in the output. So iterate over max rows down to 0 2. At each row i, 2.1 Print a '*' for each a[j] (0 <= j < n) if a[j] is tall enough to reach row i (a[j] > i) 2.2 Add adequate spaces otherwise.
Below is the code for the same –
However, I missed step 2.2 in my initial solution, and ended up coding something like below –
5 sys.stdout.write('* ') if a[j] > i else None
and so when I ran it, the algorithm promptly printed
* * * * * * * * * * * * * * * *
While it was immediately obvious why this wasn’t quite the histogram output I was looking for, something else caught my eye.
The number of ‘*’s in each column were sorted in descending order.
The absence of spaces when a[j] wasn’t big enough for row ‘i’ caused the ‘*’s gravitate towards the left and fill the gaps just as in the abacus sort illustration above.
I went ahead and implemented a bead-sort solution inspired by the bug in my histogram code.
0. Initialize a temporary list, temp[], filled with 0s. 1. Iterate 'max' rows down to 0 2. At each row i, Increment temp[0..] by 1 for all a[j] greater than i. 3. After 'max' iterations, the temporary list is sorted in descending order. 3.1 Copy elements from temporary list back into the original list in reverse order to sort the input list by ascending order.
A reference python implementation of the aforementioned algorithm follows –
The above algorithm has a space efficiency of O(n) and a time efficiency of O(n*max).
While we got down the space efficiency to O(n), the time efficiency isn’t any better off.
Notice how the following line is always true for all i < ‘minimum’?
(minimum: smallest element in the input list)
15 if a[j] > i:
This means that the check can be avoided altogether by stopping the loop once i == minimum, and later incrementing all the elements in the list by ‘minimum’.
Conversely, initialize the list to [minimum] instead of 0, and iterate over rows – maximum to minimum.
Below code takes advantage of this optimization –
This optimization yields a time efficiency of O(n*(max-min)) while retaining the space efficiency of O(n) from the previous approach. Much better.
While algorithm #2 and #3 bring the space efficiency to O(n), Bead-sort still remains a terrible algorithm for sorting even with the O(n*(max-min)) time optimization at algorithm #3.
However, a time efficiency of O(n*(max-min) means it can approach linear time for numbers in a narrow range irrespective of how big the numbers themselves are.
For e.g.,
If all numbers in the input list are between 10⁹+1 to 10⁹+100, algorithm #3 has a runtime complexity of O(n * 100); With a big enough ‘n’ this will be closer to O(n).
In contrast, algorithms #1 and #2 would have a time efficiency of O(n*10⁹) for the same input.
To be fair, algorithm #1 can potentially work with negative numbers.
One way this can be accomplished is by –
1. Bring all the numbers to a baseline zero by adding a number x 2. Sort the modified list 3. Subsequently decrement all the numbers by x.
An input of [2, -2, 3] can be modified to [4, 0, 5] by adding +2 to all input numbers,
running the sort algorithm on the modified list would yield [0,4,5],
and finally, restore the original list of numbers by subtracting 2 from all, resulting in a sorted order for the original input: [-2, 2, 3]
Algorithm #3 iterates between ‘rows of beads’ from maximum down to minimum in steps of 1.
If the nature of input numbers is known in advance, the step count can be optimized to move faster.
Consider for e.g, if the input numbers are all even, the step count can be increased to 2 reducing the runtime by half.
Or, if every number in the input list, a[i] ≡ x mod 500 for some x (imagine a worker thread handling every 500th request), then a step of ‘500’ can be used.
With the step optimization outlined above, algorithm #4 can potentially work with floating point numbers when a proper step can be chosen.
e.g,
An input of [2.0, 1.5, 3.0, -0.5] can be sorted with a step of 0.5 in algorithm #4.
However, finding a meaningful step might not always be viable or might be too small (e.g, 0.0005) to be used for sorting.
While at first glance, algorithms #2, #3, and #4 appear to retain the parallel properties of #1, a closer look at the following lines reveals that updates to the temporary array needs to be synchronized and might not yield well to parallelism.
temp[k] += 1 k += 1
1. https://en.wikipedia.org/wiki/Bead_sort
2. https://www.geeksforgeeks.org/bead-sort-natural-sorting-algorithm/
3. https://demonstrations.wolfram.com/ExtendedBeadSort/
⁽¹⁾A note at the end of the wolfram’s page does mention an optimization for algorithm #1 using O(n+max) space, but it doesn’t improve the time efficiency beyond O(n*max).
]]>]]>
Hear hear. Announcement time.
I ..er.. am an ..er.. atheist.
Drum-rolls please. Oh wait, you already knew that!
So Why? (a.k.a Prelude)
Why indeed!
For a while, It had been my greatest fear that my atheism is just me taking my “being atypical in every way possible” a little too far.
Thankfully, Now I know better. Although, for what it’s worth, It might have even begun that way.
Not that it matters, anyway.
Or perhaps it were the oft-told stories of my Grandma when I was a kid, about Ramayana and Mahabharata and the like, that pushed me.
Either she was a bad story-teller or I was a very perceptive kid, but these stories always struck me as weird.
It seemed to me that the Gods, however bad, always get a free pass, but a demon or a demon-turned-human always deserves to pay for his “bad” deeds, almost always with his life. Never mind how good he had been or what had been his story.
Case in point – Ravana.
Always portrayed as a monster and an embodiment of pure evil, He deserved to die for abducting a God’s wife.
It shouldn’t matter that he treated her well, waited for her consent to wed her or didn’t so much as lay a finger on Sita or the fact that he had worked really hard to acquire God-like powers despite being born a mortal human being.
He was not born a God and he erred, Therefore he deserves what was coming.
I think I see how we share this emotion now. We are all indoctrinated to think that the Gods are rather personal to us.
He hears us, helps us and whatnot.
So naturally when a demon abducts a God’s wife, It’s considered rather personal and we empathize.
And to further drive home the point, Consider Ahalya
Notice how Indra disguises himself as Gauthama rishi and proceeds to fornicate with Ahalya (or rape, depending on whatever version you subscribe to) and apparently suffers the worst punishment of all – A curse from the all-powerful Gauthama himself (Yeah, That was sarcasm), to have Indra castrated.
Strange how that was the last we heard of that. Nobody knows if the curse really worked or if Indra managed to redeem his testicles back.
So while Indra gets to survive, Ravana has people pissing on his grave.
Seems perfectly fair to me. (Cue the sarcasm sign)
Now I know there are apologists to Indra. I’ll have them know if they should take up an argument with me, I’ll play the Devil’s Advocate (Demon’s advocate?!) for Ravana, literally.
The theme seems to recur ad infinitum in almost every mythological story.
And it all seemed rather unfair to me.
So, I once asked my Grandma – Why is Ravana considered evil despite being “nice” to Sita, while people like Indra and Shani (a God devoted to giving you a bad time because he apparently has anger issues) are still gods and worthy of worship?
She went on a totally different tangent about how she always knew I was evil. It seems, There were huge rains and thunderstorms the night I was born.
So apparently, I am part Frankenstein. Go figure.
Atleast, Something good came off the whole thing; I no longer had to listen to her ramblings.
Anyhow, in the days to come, I came to terms with the fact that everything depends on your birth (where, how and as what) and that if you don’t luck out on that, you are pretty much screwed.
Albeit, many a times, I had spent wondering/fantasizing what if I was actually born a God and didn’t know what my power was.
Okay, So I may have not been a very smart kid, after all.
But it didn’t help ease my mind.
The notion that everything you are and all that you ever will be, depends on something you can’t even control, is much too depressing.
A rather impressive quote – The trouble with the rat race is that even if you win, you’re still a rat. comes to mind.
So, At high school, I took my research to the next logical level – Spirituality.
But the more I read about the Ramana Maharshi and Ramakrishna Paramahamsa and the likes, the more it seemed to drive the point home about how helpless you really are if you aren’t at the right place at the right time.
You don’t get to be a God, You don’t get to be enlightened, You don’t attain higher consciousness.
You live for a while and then you are just born again and again unless you “improve your performance” (which you cannot if you aren’t born special).
So you are caught between not enjoying the one life you really have, because you are left wondering what horrible deeds caused you to be born again, and devoting yourself more and more to useless rituals in the hope that you attain Nirvana, eventually.
I learnt to come to terms with that notion for a little while.
Although, deep inside, None of these made a lot of sense to me. (Although, I was humble enough to think it probably might have to do with the fact that me not being the smartest cookie when it came to spirituality and god-stuff)
Yet, I, for one, was hard-pressed on celebrating life rather than “celibating” it. (I know it’s not a real word and it doesn’t even make sense, but a little poetic license, please?!)
Even if it wasn’t the right thing to do!
And then somewhere following my graduation, I guess I stumbled on to /r/atheism and listened to Richard Dawkins, George Carlin, Hitchens and James Randi talk and a few pearls like this one: If triangles had a god it would have three sides.’ – de Montesquieu.
That’s when it really dawned on me.
And here I am.
So What does it all mean?
Nothing at all. Really!
It doesn’t mean I am suddenly a different person.
It doesn’t mean my perception of *everything* has changed overnight.
It doesn’t mean I suddenly became cynical and bitter.
And it certainly doesn’t mean I have suddenly donned an ‘Holier-than-thou’ attitude towards everyone.
Being an atheist just means that I have found out something that I believed in, turned out to be wrong.
Just that.
Nothing more, nothing less.
Perhaps an analogy would help put things in perspective.
When I was in high school, I traveled by bus.
And I used to think that anytime you arrive at a traffic signal that was green, you pretty much get a pass-through at the next signal too and the one following that, as well.
But one day, I realized something. That it was stupid of me to think that.
Because whether the signal was already green or red doesn’t matter at all because the bus always leave at green.
But knowing that I was wrong on this account didn’t change my life in any any way.
Admittedly, It made me feel a little stupid.
But that was that.
Yet, Most people seem to be easily offended when you say are an atheist but think an ‘agnostic’ is somewhat less aggressive.
I guess it’s okay for them so long as you believe in some higher power, who or whatever that might be.
Infact, Bubbie takes this to a whole new level.
According to her, You don’t choose a God. The Gods choose you.
So if you are born a Hindu, You die a Hindu. No exceptions.
It doesn’t matter whether you choose to worship a God or not.
Infact, She might just have coined a new term – Hindu Atheist.
But She’s still better than most other people.
Because to her, So long as you live a good life, It doesn’t matter whether you worship everyday or not, follow religious rituals or not.
None of these matter so long as you are a good person.
And that’s the closest she can get, to being a ‘secular humanist’.
So props to her.
Nonetheless, I still enjoy going to temples.
Mostly because I find them peaceful. And sometimes, for the babes that frequent.
Okay, I lied. Mostly for the babes.
But it’s not just the local temples. I often go visiting temples far and beyond.
However, a few people are quick to ask why and what purpose does it serve?
Well, They should probably ask themselves the same questions the next time they visit a museum.
Do they expect the pieces to come alive?
One other thing that gets on my nerves, A lot of people assume you have to be open-minded about *everything* just because you are an atheist.
For a long time, I used to think that too.
Then I realized I didn’t have to.
Shamy and Putti often toy with me around this by getting me to argue about spirituality, particularly about the concept of souls.
But i am a rather close-minded bastard when it comes to arguments. A sore loser who doesn’t like to lose many.
So, I play a Devil’s Advocate often times just so I win. (Incase you thought I didn’t know how to use the phrase! )
It ain’t always about the truth, Dummy. (a.k.a Conclusion)
Because let’s face it.
Not all truths are comfortable ones.
It’s okay to create alternative realities as long as you understand they are just that – alternate realities.
For a long while, I tried really hard to subscribe to a world view as it really is.
Per this Douglas Adam’s quote –
Isn’t it enough to see that a garden is beautiful without having to believe that there are fairies at the bottom of it too?
But I guess sometimes you need to escape the Dystopian reality.
So, I guess it’s okay to believe in whatever you want if it makes you feel good about yourself.
And I suppose it’s equally important to not look down upon someone just because they believe in something that you know is wrong.
Why? Here’s why –
1. Because a lot of us believe in other stupid things anyway.
2. To a lot of people, religion is an alternate reality that makes their life seem less painful.
3. It’s kind of a dick thing to go around telling people that everything they believed their whole life is a lie.
Because it ain’t always about the truth.
Everybody has their share of uncomfortable truths.
While I can tell my religious family/friends their religion is stupid and a lie, They could very well tell me that I am a sorry pathetic shell of a man and I will never find true love again and die forever-alone.
Both unequivocal truths.
But they wouldn’t do that. Because they are bigger than that.
So, Neither would I.
Does that mean there is no line to be drawn?
Sure there is.
You see, You can believe in Star Wars and think Darth Vader can kick Lord Voldemort’s ass.
I could very well disagree with that and offer to fight you for that.
You and I could really be extremist nutheads and take out each others’ peoples too, while we are at it.
But then, We should be labeled as lunatics and be thrown into sanitariums and rightfully so.
Alternately, If I really think Lord Voldemort is “awesomer” than Darth Vader, then wouldn’t it be a lot more entertaining and do a lot more good to grab some popcorn and see *them* fighting it out than us mere mortals trying to settle it?
Yes? Bingo.
So, That’s a fairly well-reasoned argument but why the sensationalist title, You ask?
I might be a man of reason when it comes to God, But nobody said anything about me not being a drama queen, Did anyone?
And by that, I don’t mean someone who doesn’t know there are baseball metaphors for sex (I can live with that);
Nor Someone, as Ramya would call them, er.. “technologically challenged”.
But the ones, you know, that take time out to actually call people?!
The ones that are averse to being online 24×7.
The ones to whom Facebook is all but a pastime.
The ones who would think it’s a romantic gesture when you rickroll them.
It isn’t as if my fears are unfounded.
I have all but lost the fine art of face-to-face communication. (A few would argue that you cannot lose what you’ve never had, death to them all )
I have a problem reading human emotions without tilting my head to the left.
I care about people and their intricate relationships as much as I care about how individual ICs are inter-connected in my motherboard. (i.e., not at all)
Half the time I take my phone out to “call” people, I forget why and end up playing angry birds instead. Although, In my defense, It takes one less swipe to the right.
It frightens me that I might have to live in a world where “the elders” might consider it rude to have all your conversations over group-chat.
And that’s just the tip of the iceberg.
Chances are, She might get the better of my weird gadgets obsession soon and I might end up getting divorced, too.
Even if We could get past that, tempers would wear thin as detailed accounts of my escapades on buzz, twitter and FB would make as much sense to Her as retarded ramblings of a drunken lemur.
I could as well be telling her that I fell into a rabbit-hole or that I just discovered the magical world of Narnia.
Wouldn’t make the darndest of difference.
What makes it worse is the fact that I have no real skill outside of this realm.
Take me out of my life-support a.k.a the internets and I would be one fish out of its bowl.. er.. water.
While I technically wouldn’t drop dead, my neuro-physiological activities wouldn’t be much either to make any signs of protest even if you are taking me to bury me (alive).
It wouldn’t be that big of an exaggeration if I say I am more like this guy in the second panel –
I could go on about my geekdom but considering my audience, It’d be like preaching to the choir.Well, I hear ye all saying, Why don’t I stop babbling and.. er.. find a suitable girl(whatever that means) for myself.
Suffice to say, I tried. That’s all you ought to know, really.
Yet, It’s my people’s hope to cure me of my hopeless dweebism by finding me a girl.
They have kinda informally launched a community-wide search.
Now, that could just be the worst place to look for.
Not only are my options limited, ergo greatly increasing the odds of Her being largely halli-ish; But I have long since abandoned the ways of the “community”.
Considering that I am now an atheist and my Tamil’s all but forgotten ever since I was booted out of the house.
Not to mention the unholy habits I have accrued over the years.
This, assuming that I am even remotely marketable.
Or perhaps, Like the proverbial cheese, I’ll stand alone.
Infact, I was quite scared of them.
Presumably an irrational fear that stuck with after a failed effort in my graduate years.
No matter, This weekend, I set out to remedy that.
I didn’t want to read on the algorithms before implementing and decided I’d go pencil-and-paper and implement one that occurs naturally to me.
Here goes the result of that –
#!/usr/bin/python def generate_combinations_helper(lst, a, prefix, startindex, n, r): if (startindex >= n): return prefix.append(a[startindex]) if len(prefix) == r: lst.append(prefix[:]) return generate_combinations_helper(lst, a, prefix[:], startindex+1, n, r) for i in range(startindex+2, n): generate_combinations_helper(lst, a, prefix[:], i, n, r) def generate_combinations(a, n, r): combinations = [] for i in range(n, r-1, -1): curr = generate_combinations_helper (combinations, a, [], 0, i, r) a.pop(0) return combinations def main(): n = int(raw_input()) r = int(raw_input()) a = range(1, n+1) combinations = generate_combinations(a, n, r) print len(combinations) for i in combinations: print i if __name__ == "__main__": main()
Ofcourse, It generates all nCk, 0 <= k <= r to generate nCr arrangements.
So, a powerset can be constructed with r = n.
Although, I wrote a revised version, one that stores the subsets ordered by their length.
#!/usr/bin/python # Add the current subset to the powerset list ordered by size def add_to_powerset(powerset, prefix): i = len(prefix) if prefix not in powerset[i]: powerset[i].append(prefix) # Generate subsets starting with given prefix def generate_power_set_helper(powerset, a, prefix, startindex, n): if (startindex >= n): return prefix.append(a[startindex]) add_to_powerset(powerset, prefix[:]) if len(prefix) == n: return generate_power_set_helper(powerset, a, prefix[:], startindex+1, n) add_to_powerset(powerset, prefix[:]) for i in range(startindex+2, n): generate_power_set_helper(powerset, a, prefix[:], i, n) add_to_powerset(powerset, prefix[:]) # Lose the starting elements of the set, one at a time to generate subsets starting from 2,3,... etc. def generate_power_set(powerset, a, n): for i in range(n, 0, -1): generate_power_set_helper (powerset, a, [], 0, i) a.pop(0) def main(): n = int(raw_input()) a = range(1, n+1) # Initialize an empty 2D list to store subsets ordered by length powerset = [] for i in range(0, n+1): powerset.append([]) generate_power_set(powerset, a, n) for i in range(0, n+1): print powerset[i] if __name__ == "__main__": main()
And now, to the permutations.
I cheated a little here.
Generating nPr combinations proved to be a tough task, So I decided I’ll use the combinations and get an ordered rPr permutations for each combination generated.
#!/usr/bin/python # Replicate the current nP(k-1) permutations 'k' times to make room for a new element def replicate(a, k): n = len(a) for j in range(1, k): for i in range(0, n): a.append(a[i][:]) # Insert new 'number' into the current permutation arrangement nP(k-1) one 'slot' at a time def arrange(a, number, k): n = len(a) / k for j in range(0, k): for i in range (0, n): a[j*n+i].insert(j, number) # Generate all ordered arrangements(permutations) of elements in list b def permute_all(b, n): permutations = [[]] for i in range(1, n+1): replicate(permutations, i) arrange(permutations, b[i-1], i) return permutations def main(): n = int(input()) a = range(1, n+1) permutations = permute_all(a, n) permutations.sort() for i in permutations: print i if __name__ == "__main__": main()
#!/usr/bin/python def generate_permutations(a, n, r): # Generate unordered arrangements first combinations = generate_combinations(a, n, r) # for each unordered arrangement of length r in nCr, generate rPr ordered arrangements (permutations) permutations = [] for combination in combinations: permutations_rr = permute_all(combination, r) for permutation in permutations_rr: permutations.append(permutation) return permutations def main(): n = int(raw_input()) r = int(raw_input()) a = range(1, n+1) permutations = generate_permutations(a, n, r) print len(permutations) for i in permutations: print i if __name__ == "__main__": main()
Now, to the arduous task of translating this to Haskell.
]]>In fact this time around, I started with a Haskell implementation and went on to translate to Python just for kicks.
Suffice to say, I am very pleased with myself.
import Char
import List
names = [<List of names from problem specification>]
{- For each string s in list, Calculate sum of the characters’ alpha positions -}
sumChars :: [String] -> [Int]
sumChars [] = []
sumChars (x:xs) =
(foldl (\acc ltr -> acc + (ord(ltr)-ord(‘A’) + 1)) 0 x) : sumChars xs
main = do
let sortedNames = sort(names)
let zippedSumAndIndex = zip [1 .. length(sortedNames)] (sumChars sortedNames)
let total = foldl (\x y -> x + fst(y) * snd(y)) 0 zippedSumAndIndex
print total
Long story short. Gurumaata has initiated a new activity, One that she believes will help us mere mortals know better about each other. The social networks after all, are so chock full of baloney and reek of egotistical trumpets.
As to the activity itself, All one has to do is write a blog post mentioning 7 things about himself/herself and tag 7 of their friends who are to follow suit.
What might seem like a “pyramid scheme” (it differs because you can tag anyone any number of times; otherwise all the same, all the same ;)) or even a chain letter of sorts at first, it might actually be a difficult thing to write. (Pavya didn’t mention that if I write this entry and tag 7 others, unexpected windfall might come my way or that I’ll find the love of my life; Neither did he imply that failing to comply would mean a bird would shit on my head in my own room or that I’d resign my job and sit at home for no apparent reason :D)
Nonetheless, To pen such a thing is challenging indeed. And boy, Do I love writing-challenges! (These 50 wordlist essays I have written are proof that I do :D)
Without further ado, Here are the 7 things about myself –
Oh. And one more thing.. (Shame on all of you who couldn’t catch that meme :P)
Given that I am a Metallica fan, I couldn’t resist but writing this – [In honor of all those who made me go through this ordeal]
You labelled me
I’ll label you
So I dub thee unforgiven.The Unforgiven, Metallica.
After all,
Tag : WordPress :: Label : Blogger
So, With the infinite wisdom vested in me, I hereby tag thee all – Chetu, Ramya, Preeti, Shilpa, Pavya, Vim and Gurumaata (why should only we suffer? :P).
You may now rise..
And commence writing.
]]>This content is password protected. To view it please enter your password below:
]]>
This content is password protected. To view it please enter your password below:
]]>
This content is password protected. To view it please enter your password below:
]]>