Complexity theory isn’t required to be a programmer
mortoray.com
mortoray.com
Thematically, it makes a case for complexity not being important to software development. I disagree, but stipulating that the author is correct, where does that slippery slope end? Virtually no formalized CS knowledge is required to make expert use of Microsoft Excel, which is itself an extremely important programming environment. What parts of CS does this analysis include in the requirements for development? Is it important to know how a hash function works if your language gives you a dictionary ADT? Is it important to understand the memory hierarchy if you're just shuttling things into and out of an SQL database? There's a rather large population of "Rails programmers" and "PHP programmers" that need know very little more than an "HTML programmer" does to get their job done.
But it's the specifics of the argument that really bug me. The author seems to be making a case that even if you understand complexity, it's hard to deploy it in a real application. That idea seems totally alien to me. I don't routinely analyze the complexity of a sort or a shortest-paths graph reduction, but I certainly feel like I benefit from understanding how the typical algorithms used to solve those problems scale with the size of their inputs. Simpler: any time you select a binary tree instead of a hash table for your lookup table because you realize you need range queries or sorted traversal, aren't you leaning on complexity theory?
However, I don't believe every programmer does need to understand complexity theory from a formalized perspective. I'll tie a loose analogy to a musician who cannot read sheet music, yet can still be a maestro. I think that sometimes some people just think a certain way, even if they (or others) cannot really explain it.
But I think that merely scratches the surface of a deeper issue. Bob (in his analogy) can be a perfectly serviceable programmer for many years and create many good things. But Bob may never reach his true potential because he didn't take the time to grasp the fundamental concepts about what he was telling the computer to do, or how the computer behaved when he did them.
Because Bob never truly understands computational complexity, maybe Bob never reaches his true potential.
Spot on. Not only that, having that kind of understanding has prevented me from making some really stupid programming mistakes in the past.
One may not need that to write a CRUD (or let your framework of choice do it for you) but if one goes beyond the trivial, it's good to know where one is going.
Having said that, the specific enchantments, peculiarities, poor decisions and sadistic, inconsistent choices of the different tools I use for my work take up much more time and brain power than complexity theory. The inherently complex stuff is relatively rare. What's left is the stuff that's complicated for no good reason.
Only a nominal amount. You probably only need to spend a few hours watching YouTube videos to make these sorts of decisions, or pass a phone screen. Whereas there are entire classes and textbooks that cover only complexity theory.
Software is a weird industry because the best and most famous developers tend to be the ones who make software for other developers. And those folks tend to know a ton about software engineering. But the actual folks using those tools don't need to know all that much, and they're generally the ones making all the money.
More precisely, I think that there are three types of programmers. Those who don't know the formal theory. Those who know it but don't think in terms of complexity except when they have to. And those for whom big-O is second nature.
I believe that there is great value from having someone around who falls into the third group. (That's where I'd rate myself.) But they are rare. And there is little difference in practice between people in the first and second groups. Exactly how little difference is demonstrated by the fact that people who once took CS and then work as programmers find their memories of big-O fading over time because they aren't using it.
As for where the slippery slope ends, given the choice of having a new developer be a typical CS grad versus a beginning programmer who has mastered everything in Code Complete, I'd go for the second one every time. Obviously this isn't true if you're in an area that requires CS knowledge. But for most working developers, I think it is.
> How does the algorithm perform in concurrent computing? Clearly we’d prefer an algorithm that can scale over processors to one that can’t ... Certainly there is a way to put this all together in theory, but I don’t know those details.
There are no details to know. Any time you have any parameter of any system which can grow (processors, input size, time, space, cache layers) you can describe anything depending on that parameter using asymptotic notation to get a rough estimate of its efficiency. This is not a question of complexity, just a question of how to express growth rates succinctly. Knowing how to reason about rough estimates is essential for engineers because they have to have some idea about why the thing they're building will conform to specifications at least in principle before devoting the resources to measuring it precisely.
And to reiterate: none of this has anything to do with complexity theory except that in complexity theory we happen to use asymptotic notation very heavily. The author's problem is with mathematical language being used in the workplace.
There is a rather vocal minority in this community who think that attending universities is a waste of time. These people are naturally interested in notion that things commonly taught in universities, but frequently glossed over when self-teaching or at "hacker schools", are not necessary.
No education is necessary, but that doesn’t make it devoid of value. Speaking as a US citizen, I truly believe what my country and countless others around the globe desperately need is better and accessible education, absolutely including the Arts.
The opposing viewport can likely be called anti-intellectual in fairness.
If I am hiring for a developer position, I consider at least a basic knowledge of complexity to be necessary. There are too many developers who are familiar with it for me to waste my time on ones that are not.
I am not speaking of "necessary" in a universal sense, since that would be nearly impossible to define and a useless concept even if we could. If we really get down to it, breathing isn't necessary...
However, if you want someone to pay you the high salary to be a race car driver, then you better know how to drive manual.
There are plenty of positions where people can program and do programming tasks without a great deal of depth of knowledge in terms of programming. And they can make a living doing this.
They do have driver-operated clutches, though... actually there's TWO of them, usually the bottom two paddles on the left and right of the wheel. They're only necessary when starting the car from stationary, after that the computer takes over. It's actually notoriously difficult to operate them, if you take a look at this video of Richard Hammond driving an F1 car, he takes several tries to get it moving.
http://www.youtube.com/watch?v=9773pisjCSw
Not to mention, there are other types of highly-paid race car drivers.
And we all look forward to your app being featured on http://accidentallyquadratic.tumblr.com :)
You, my good sir, are totally mistaken. O(n) is a set of functions that grow at most linearly with n, ignoring constants. O(n) is a rich mathematical notation that tells a _lot_ of things on its own. If someone tells you that something 'is' O(n) what they actually mean is that they have a function that is _an element_ of O(n). Again, a very concise and powerful statement on its own. Of course you can't say "this tree is O(n)" because a tree is not a function. That'd be like saying "this apple is dumb". Don't blame the notation, blame the user.
Mainstream infrastructure hasn't done a stellar job in seamlessly abstracting new hardware features (though compiler construction is still decent there in many regards). The one that has, isn't usually mainstream.
No, it doesn't. A given person may be, but the theory does not. It so happens that complexity theory makes heavy use of a mathematical construct, the "big-O notation", that makes it easy to ignore low-order term's impact on a process, but that is a tool it uses, not the totality of the theory.
I assure you that if you walk up to a complexity theorists and say "Your ignoring of constant factors makes your entire discipline worthless!" you're more likely to get laughed at than blow their minds.
You want to analyze the real impact of some algorithm in the face of having Big Ints and dealing with cache issues? Complexity theory is ready for you. I've seen it done. The equations get nastybig fast, but fortunately computer algebra systems can chew right them. Amusingly, in the end you end up doing something very similar to O() anyhow and just start semi-arbitrarily chopping off insignificant terms to figure out what's actually going on in the enormous expression. But this can still be a useful exercise to get a sense of where the low-order terms may be dominating, for how long, and whether there's anything useful to do about it.
Also, big-O is not the be-all, end-all of complexity theory. What a ludicrous sentiment.
That's why SQL didn't take off as a lay-person interface to databases; even though it was meant to be a system anyone could use, you can't get around the fact that you still need to know what you want and what comprises what you want. Your typical middle-manager type knows neither.
That's also why UML can't be converted to a program: if it did, it would call managers out on their inconsistent logic and the manager would just give up and make someone else do it. The fact that it doesn't compile is a feature, one that enables UML to make managers feel like they are being a part of the technical process.
It's not a technical problem, it's a cultural one.
Does it not? It can't be less than O(n) simply by the pigeonhole principle and it doesn't look like it's more than that.
For elements that have a constant/uniform size, this distinction is pointless. However, for things like strings, there can be a large variance in the size.
Applying the pigeonhole principle informs us that the radix tree has a lower bound of O(m); but remember that O(n) could be quite a bit larger than that. A radix tree works by only storing one copy of duplicated prefixes of the elements; it still has an upper-bound space complexity of O(n), but the expected complexity is lower than that.
Also, using n as the sum of the sizes of all the elements is not normal.
> If pointers are magic O(1) values
Um... pointers are O(1) size. Usually either a fixed 32 or 64 bits. > then you don't get an asymptotic size advantage.
I even said that! I specifically said that it's still O(n) upper bound, but that the expected case is lower than that.Though to be fair, I should have written Ω(m) instead of O(m) when discussing the lower bound.
> using n as the sum of the sizes of all the elements is
> not normal.
1. I didn't say it was normal; just that in this case, that's what it was referring to.2. It is though! Worded another way, n is the size of the data being stored.
If you want to talk about asymptotic growth of an algorithm, you need it defined on a machine model that supports infinite memory. Saying that pointers are special O(1) size values are a reasonable way to do that. Another way is to let them be variable size, and include that cost in your measurements. With your 64-bit pointers, you're overpaying that cost. And the transition from 32 bit pointers to 64 bit pointers is an object lesson on the real existence of this logarithmic factor that you'd like to pretend doesn't exist.
Edit: also, going with O(1) pointers, the expected asymptotic space usage doesn't mean anything without specifying the probability distribution of dictionaries involved (maybe parameterized on the size n). It's not hard to construct one that changes the outcome.
It would have been correct for the original author to have written that most collections have ϴ(n) space complexity, where radix trees only have O(n) space complexity.
It's common for people to use O when they mean ϴ or Ω. All the original statement was saying is that most collections use as much data as you put in, but some (like radix tree) can use less.
(for fun, if we don't give O(1) pointers: If I'm not mistaken, radix tree has O(m*log(m)+n), Ω(m) space-complexity, which is O(n) iff the average size of an element is ≥ log(m); which it almost certainly would be)
That's stronger than a mere "almost certainly". At least some constant fraction (dependent on the alphabet) would be of size Ω(log m) for some base also dependent on the alphabet, so the average size is also Ω(log m).
I'm not sure how you get your best case, though. It seems to me that the best case has at least Θ(m) nodes since there are m contained strings. The best case for this is each being of minimum size - which is constant size. Each node but the first has a pointer to it of size Ω(log m), so the overall minimum cost is Ω(m log m).
http://stackoverflow.com/questions/20573231/whats-the-space-...
EDIT:
Sorry, wait, I was correct all along - as I was talking about the worst case complexity! Consider the case when our alphabet is {A,B}, and I want to store the strings "A" and "B", in that case, I have to use O(n) space, as I'd need at least two nodes for the two strings.
Here the input space is a set of dictionaries. A dictionary is a finite set of strings. A subset of the input space is a set of dictionaries.
Finite subsets of the input space are finite sets of dictionaries, thus they have bounded size.
That's just a specification of an arbitrary subset of the input space.
This is my field of research, and I assure you computability theory is not a subset of it.
By that metric (and even by your own argument "the inability for algorithms"), the undecidability of the halting problem definitely fits within the complexity definition.
> imposing restrictions on the available resources is what distinguishes computational complexity from computability theory
And for the record when I say the ability of algorithms to do something I mean the class of all possible algorithms.
In any case, it's clear from your appeal-to-wikipedia that this conversation is over.
Because you are not constraining any resources.
Programming deals more with this type of design complexity for which currently no theory exists. How do quantify whether one program is more intricate then another? How do we quantify whether the functional style is less complex then an object oriented style? There's no way. Since no theory exists, it largely comes down to using intuition and design to deal with complexity. In short, no theory required, only because no theory exists (yet).
http://en.wikipedia.org/wiki/Computational_complexity_theory
I agree with you that there seems to be no foolproof way to measure the overall "software complexity" of a piece of software. There are a lot of methods proposed, but none is provably optimal or even all that useful it seems. Search "Evaluating Software Complexity Measures" by Elaine Weyuker for a somewhat dated paper discussing the topic. I would be very interested if anyone had any recommended resources on the current state-of-the-art regarding software complexity measures.
Seems to me the only way to measure complexity absolutely would be some sort of extension of the minimum description length principle -- what is the shortest way we could write the specification for the entire machine + software that runs on it. Of course this seems completely infeasible for any real world task.
I'm not saying there's one best known way to measure the complexity of a system, just that it is measurable.
I disagree. There is a logical end, so long as either of us have the capability of admitting we're wrong.
Well designed systems allow you to change one module and leave everything else alone -- O(1). Others might require a change on both sides of an interface and be potentially O(n). Still others might require you to to test far-distant parts of the system because they leak an abstraction, and be O(n^2), making them hard to add on to.
You can then characterize "difficulty of changing stuff" as the number of components increase, and it's right back to the format of a computational complexity problem.
I don't understand how the theory converts. How is it O(n^2)? How does changing and testing modules convert to this number? Describe a case thats O(n log n).
I don't see how describing an O(n log n) system sheds further light on any of this.