LB wrote: |
---|
Due to the Halting Problem there is no such mathematical/computational method, unless you limit the factors. Even then, though, it is still quite complex and challenging to describe in a mathematical/computational sense. |
What?
The study of algorithmic computational complexity is an
integral part of computer science. Knuth wrote huge volumes on this stuff that we still use today.
Whether or not you can get a computer to identify objects in a picture is different from analyzing the complexity of such a task -- which
can be done.
@
jumper007
Google around "algorithm analysis". One of the first links looks like a fairly good introduction:
http://discrete.gr/complexity/
Also, a good book helps:
http://www.amazon.com/dp/0262033844
The basic principle is that of
asymptotic complexity. That is, you are interested in orders of growth of related functions.
That is, we tend to toss all terms and factors that are dominated by the remaining factor. Given, for example, a linear factor and a constant factor:
lim (n)/1 = ∞ ::: the top factor dominates
n→∞
equivalently:
lim 1/(n) = 0 ::: the bottom factor dominates
n→∞
The only thing you are interested in, as a rough measure of complexity (which is the time and memory spent to compute) is the dominant term. Hence:
1 < log n < n < n log n < n²
Become comfortable with logarithms, if you aren't already.
To say we are interested in
asymptotic complexity is to say we are interested in how the algorithm behaves as n→∞.
The bounds (rate of growth) are true for functions g(n) and f(n) such that n > k, where k << n. For example, quicksort O(n log n) has superior time over insertion sort O(n²) for n > k, but for some n <= k the insertion sort will actually perform better. (We know this by experience, nothing more.) That's why a well-written quicksort will bottom out at k items (instead of 1) and perform a single insertion sort on the final sequence -- it runs
faster that way.
The magic letters you need to know are, in order from highest to lowest:
f(n) = o(g(n)) means we have a function g(n) such that f(n) < cg(n), for n > k.
f(n) = O(g(n)) means we have a function g(n) such that f(n) <= cg(n), for n > k.
f(n) = Θ(g(n)) means we have a function g(n) such that c
1g(n) <= f(n) <= c
2g(n), for n > k.
f(n) = Ω(g(n)) means we have a function g(n) such that cg(n) <= f(n), for n > k.
f(n) = ω(g(n)) means we have a function g(n) such that cg(n) < f(n), for n > k.
You will often see algorithms expressed with big-O notation because that is a tight upper bound on the algorithm (meaning it is pretty representative of the algorithm's
worst case performance). In stuff written for the hoi-poloi, you will also see big-O notation used where another Greek letter would have better been placed...
So, here's an example with merge sort. The lower bound for merging two lists, A and B (with M and N elements, respectively) is M+N-1 comparisons. (Do you know
why?)
Since both M and N are linear, we'll just take them to be the same value and write it as 2n-1 comparisons.
Since 2n (linear term) dominates 1 (constant term), we toss all but the linear term and write it as 2n.
Since 2 is a constant (again dominated by the linear factor, n) we'll just write it as n.
All done! The best case performance of merge sort is Ω(n) comparisons. Nice!
There is, of course, much more to it than that, but that should get you over the first hurdle to understanding the math behind algorithms analysis.
Oh, before I forget, rewrite recursion as a loop. :O)
Hope this helps.