Based on both Cyclomatic Complexity formulas, explain why the number of procedural nodes does not influence on cyclomatic complexity value - metrics

a. Based on both CC formulas, explain why the number of procedural
nodes does not influence CC.
b. What would happen if you had multiple stop nodes?
d. What is the effect on cyclomatic complexity of break, continue,
goto and return statements?
e. What is the effect on cyclomatic complexity of else or default
clauses in if/switch statements?
f. What is the effect on the cyclomatic complexity of a recursive
method call?
g. The total number of possible paths through a loop (for, while or
do…while) is practically infinite because it can repeat any number of
times. Why then does a loop only increase cyclomatic complexity by
one?
h. Does computational complexity (as expressed in big-O notation)
affect cyclomatic complexity?

Below given are my answers for your questions, You could correct if there is anything wrong with the given answers.
a. Based on both CC formulas, explain why the number of procedural nodes does not influence CC.
CC is measure of number of linearly independent paths through the code.
Procedural nodes can be combined together into one node hence there is only one single path through the code.no matter the number of procedural nodes cc =1. Since decision nodes d= 0 .
b. What would happen if you had multiple stop nodes?
CC measures linearly independent paths. Exit points don't ADD paths to the code, they TERMINATE paths, thus reducing CC (or in the very least, they certainly don't increase CC).
https://stackoverflow.com/a/2073485/5156517
c. Say you use the V(G) = d + 1 formula, but instead of counting switch statements you count case clauses. Is this conceptually correct? Explain why you'll arrive at the right answer, even though a case clause is not a decision node.
Conceptually goes against the formula,3 cases means 3 decisions . the default path is not counted.
d. What is the effect on cyclomatic complexity of break, continue, goto and return statements?
No effect
e. What is the effect on cyclomatic complexity of else or default clauses in if/switch statements?
No effect, else and default clauses are not counted as decision nodes.
f. What is the effect on cyclomatic complexity of a recursive method call?
no. There is only one linearly independent path to the recursive method in your example, so it wouldn't increase the cyclomatic complexity.
g. The total number of possible paths through a loop (for, while or do…while) is practically infinite, because it can repeat any number of times. Why then does a loop only increase cyclomatic complexity by one?
Because it does not increase the number of linearly independent paths.,for while do loops does not imply multiple control paths..there for it does not add to cc.only one path is added when it goes back to the starting decion node after returning from the loop every time to check the condition, thus only one single path is added.
h. Does computational complexity (as expressed in big-O notation) affect cyclomatic complexity?
Computional complexity measure resources used up , space and time taken and not the measure of the complexity of the program.

Related

Big O notation for inverse exponential algorithm

Let's say you had an algorithm which had n^(-1/2) complexity, say a scientific algorithm where one sample doesn't give much information so it takes ages to process it, but many samples to cross-reference made it faster. Would you represent that as O(n^(-1/2))? Is that even possible theoretically? Tldr can you have an inverse exponential time complexity?
You could define O(n^(-0.5)) using this set:
O(n^(-0.5)) := {g(n) : There exist positive constants c and N such that 0<=g(n)<=cn^(-0.5), for n > N}.
The function n^(-1), for example, belongs to this set.
None of the elements of the set above, however, could be a an upper bound on the running time of an algorithm.
Note that for any constant c:
if: n>c^2 then: n^(-0.5)*c < 1.
This means that your algorithm do less than one simple operation for input large enough. Since it must execute a natural number of simple operation, we have that it does exactly 0 operations - nothing at all.
A decreasing running time doesn't make sense in practice (even less if it decreases to zero). If that existed, you would find ways to add dummy elements and increase N artificially.
But most algorithm have at least O(N) complexity (whenever every data element influences the final solution); even if not, just the representation of N gets longer and longer which will eventually increase the running time (like O(Log N)).

Big O of an algorithm that relies on convergence

I'm wondering if its possible to express the time complexity of an algorithm that relies on convergence using Big O notation.
In most algorithmic analysis I've seen, we evaluate our function's rate of growth based on input size.
In the case of an algorithm that has some convergence criteria (where we repeat an operation until some defined error metric is below a threshold, or the rate at which the error metric is changing is below some threshold), how can we measure the time complexity? The number of iterations required to converge and exit that loop seems difficult to reason about since the way an algorithm converges tends to be dependent on the content of the input rather than just it's size.
How can we represent the time complexity of an algorithm that relies on convergence in Big O notation?
In order to analyse an algorithm that relies on convergence, it seems that we have to prove something about the rate of convergence.
Convergence usually has a termination condition that checks if our error metric is below some threshold:
do {
// some operation with time complexity O(N)
} while (errorMetric > 0.01) // if this is false, we've reached convergence
Generally, we seek to define something about the algorithm's manner of convergence - usually by identifying that its a function of something.
For instance, we might be able to show that an algorithm's measure of error is a function of the number of iterations so that the error = 1 / 2^i, where i is the number of iterations.
This can be re-written in terms of the number of iterations like so: iterations = log(1 / E), where E is the desired error value.
Therefore, if we have an algorithm that performs some linear operation on each iteration of the convergence loop (as in the example above), we can surmise that our time complexity is O(N * log(1 / E)). Our function's rate of growth is dependent on the amount of error we're willing to tolerate, in addition to the input size.
So, if we're able to determine some property about the behaviour of convergence, such as if its a function of the error, or size of the input, then we can perform asymptotic analysis.
Take, for example, PageRank, an algorithm called power iteration is used in its computation, which is an algorithm that approximates the dominant eigenvector of a matrix. It seems possible that the rate of convergence can be shown to be a function of the first two eigenvalues (shown in the link).
Asymptotic notations don't rely on convergence.
According to CLRS book (Introduction to Algorithms Third Edition chapter 3 page 43):
When we look at input sizes large enough to make only the order of
growth of the running time relevant, we are studying the
asymptotic efficiency of algorithms.That is, we are concerned with how the running time of an algorithm increases with he size of
the input in the limit, as the size of the input increases without
bound. Usually, an algorithm that is asymptotically more efficient
will be the best choice for all but very small inputs.
You mentioned your code (or idea) has infinitive loop and continue to satisfy the condition and you named satisfying the condition convergence but in this meaning, convergence does not related to asymptotic notations like big O, because it must finish because a necessary condition for a code to be an algorithm is that it's iterations must finish. You need to make sure iterations of your code finish, so you can tell it the algorithm and can asymptotic analysis of it.
Another thing is it's true maybe sometime a result has more running time but another has less running time. It's not about asymptotic analysis. It's best case, worst case. We can show analyse of algorithms in best case or worst case by big O or other asymptotic notations. The most reliable of them is you analyse your algorithm in worst case. Finally, for analysis your code you should describe the step of your algorithm exactly.
From math point of view, the main problem is estimation of the Rate of convergence of used approach. I am not so familiar with numerical methods for speak fluently about higher than 1 Dimensions (matrixes and tensors you probably more interested in). But ley's take other example of Equation Solving than Bisection, already estimated above as O(log(1/e)).
Consider Newton method and assume we try to find one root with accuracy e=10e-8 for all float numbers. We have square as Rate of convergence, so we have approximately 2*log(float_range/e) cycle iterations, what's means the same as Bisection algorithmic complexity O(log(range/accuracy)), if we are able to calculate the derivative for constant time.
Hope, this example has a sense for you.

How is pre-computation handled by complexity notation?

Suppose I have an algorithm that runs in O(n) for every input of size n, but only after a pre-computation step of O(n^2) for that given size n. Is the algorithm considered O(n) still, with O(n^2) amortized? Or does big O only consider one "run" of the algorithm at size n, and so the pre-computation step is included in the notation, making the true notation O(n+n^2) or O(n^2)?
It's not uncommon to see this accounted for by explicitly separating out the costs into two different pieces. For example, in the range minimum query problem, it's common to see people talk about things like an &langle;O(n2), O(1)&rangle;-time solution to the problem, where the O(n2) denotes the precomputation cost and the O(1) denotes the lookup cost. You also see this with string algorithms sometimes: a suffix tree provides an O(m)-preprocessing-time, O(n+z)-query-time solution to string searching, while Aho-Corasick string matching offers an O(n)-preprocessing-time, O(m+z)-query-time solution.
The reason for doing so is that the tradeoffs involved here really depend on the use case. It lets you quantitatively measure how many queries you're going to have to make before the preprocessing time starts to be worth it.
People usually care about the total time to get things done when they are talking about complexity etc.
Thus, if getting to the result R requires you to perform steps A and B, then complexity(R) = complexity(A) + complexity(B). This works out to be O(n^2) in your particular example.
You have already noted that for O analysis, the fastest growing term dominates the overall complexity (or in other words, in a pipeline, the slowest module defines the throughput).
However, complexity analysis of A and B will be typically performed in isolation if they are disjoint.
In summary, it's the amount of time taken to get the results that counts, but you can (and usually do) reason about the individual steps independent of one another.
There are cases when you cannot only specify the slowest part of the pipeline. A simple example is BFS, with the complexity O(V + E). Since E = O(V^2), it may be tempting to write the complexity of BFS as O(E) (since E > V). However, that would be incorrect, since there can be a graph with no edges! In those cases, you will still need to iterate over all the vertices.
The point of O(...) notation is not to measure how fast the algorithm is working, because in many specific cases O(n) can be significantly slower than, say O(n^3). (Imagine the algorithm which runs in 10^100 n steps vs. the one which runs in n^3 / 2 steps.) If I tell you that my algorithm runs in O(n^2) time, it tells you nothing about how long it will take for n = 1000.
The point of O(...) is to specify how the algorithm behaves when the input size grows. If I tell you that my algorithm runs in O(n^2) time, and it takes 1 second to run for n = 500, then you'll expect rather 4 seconds to for n = 1000, not 1.5 and not 40.
So, to answer your question -- no, the algorithm will not be O(n), it will be O(n^2), because if I double the input size the time will be multiplied by 4, not by 2.

Complexity class of Towers of Hanoi

Given a problem
Given n print every step it takes to move n disks from rode 1 to rode
2
I need to determine the complexity class of this problem with this specific task. It is clearly not in P as it is obvious that complexity of this problem is O(2^n) and we can't do better as we have to print output of exponential size. My next guess would be NP or even NP-hard but I think it can't be the case as not matter how clever the algorithm is, we can't check the exponential size output in polynomial time even on non-determinant machine. So, what's the complexity class?
The correct steps can be determined from the start without needing a trial-error search to make the right decision. Therefore this problem is not a decision problem, to which classes such as NP apply.
This is more of a function problem. The time complexity is indeed determined by the number of steps to be output, which is 2n-1, i.e. O(2n).
The corresponding class would thus be FEXPTIME-Complete, the prefixed F standing for Function, and Complete signifying that it cannot be done in less than exponential time (like P). It is analogous to the EXPTIME-Complete class for decision problems, i.e. O(2polynomial(n)).
Decision problem
There is a confusing aspect in your question: The problem statement is about printing steps, reaffirmed by "... determine the complexity class of this problem". Yet some phrases down the line, you mention "we can't check the exponential size output in polynomial time". So it seems you mix two different problems:
Generating the (correct) list of steps for a given n
Verifying the correctness given n and a list of steps.
The second is a decision problem, and in that case you would say it is in the EXPTIME-Complete class.

How to calculate "n" for different notations Big O, Omega, Litle o , Litle omega and Theta Notation

I am studying algorithms, but the calculations to find Time Complexity are not that much easy for me, it is hard to remember when to use log n, n log n, n^2, n^3, 2n, etc, my doubt is all about how to consider these input functions while computing the complexity, is their any specific way to calculate the complexity ,like using for loop take's this much complexity always and so on....?
Log(n): when you are using recursion and a tree is generated use log(n).
I mean in divide and conquer when you are diving problem into 2-halfs actually you are generating a recursive tree.
its complexity is Log(n), why ? because its a binary tree in nature and for binary tree we use Log(Base2)(n).
try yourself: suppose n=4(Elements) so log(base2)(4)=2, you divide it into equal half.
nLog(n): remember Log(n) its was division till single element. after that you start merging sorted elements that take liner time
in other words Merging of elements has complexity "n" so total complexity will be n(Merging) + Log(n)(Dividing) which is finally become nLog(n).
n^2:
when you see a problem is solved in two nested loop then Complexity is n^2.
i.e Matrix/2-D arrays they computed in 2 Loops. one loop inside the outer Loop.
n^3: oh 3-D arrays, this is for 3 nested loops. loop inside loop inside loop.
2n: thanks you did not forgot to write "2" with this "n" otherwise I forgot to explain this.
so "2" in here with "n" is constant just ignore it. why ?. because if you travel to other city by AIR. you will count only hours taken by flight not the hours consumed in reaching AIR port. I mean this is minor we remove constant.
and for "n" just remember this word "Linear" i.e Big-O(n) is linear complexity. Sadly I discovered there is no Algorithm that sort elements in Linear time. i.e just in one loop.(Single array traversal).
Things To Remember:
Nominal Time: Linear Time, Complexity Big-O(n)
Polynomial Time: Not Linear Time, Complexity Big-O[ log(n), nlog(n), n^2, n^3, n^4, n^5).
Exponential Time: 2^n, n^n i.e this problem will solve in exponential time i.e N^power(n) (These are bad bad bad, not called algorithm)
There are many links on how to roughly calculate Big O and its sibling's complexity, but there is no true formula.
However, there are guidelines to help you calculate complexity such as these presented below. I suggest reviewing as many different programs and data structures to help familiarize yourself with the pattern and just study, study, study until you get it! There is a pattern and you will see it the more you study it.
Source: http://www.dreamincode.net/forums/topic/125427-determining-big-o-notation/
Nested loops are multiplied together.
Sequential loops are added.
Only the largest term is kept, all others are dropped.
Constants are dropped.
Conditional checks are constant (i.e. 1).

Resources