Time complexity analysis of code - c

int foo(int n)
{
int x=2;
while (x<n)
{
x = x*x*x;
}
return x;
}
I need to analyze its time complexity. I noticed it reaches n much faster than just log(n). I mean, it does less steps than O(log(n)) would do. I read the answer but have no idea how they got to it: It is O(log(log(n)). Now, how do you approach such a question?

think of it as a recursive function:
f(i) = f(i-1)^3
if you expand it:
f(i) = ((f(i-k)^3)^3)[...k times] = f(i-k)^(3^k) = f(0)^(3^i)
the function grows as the power of the power... so the time (iterations) to reach a certain number (that is, calculating the inverse of the function) is the logarithm of the logarithm.
As in your example f(0) = 2, we want to know when f(i) >= n being n the input parameter (and i the number of iterations):
f(i) = 2^(3^i) >= n
3^i >= log_2(n)
i >= log_3(log_2(n))
So to reach a value of n, it takes log_3(log_2(n)) iterations (round up while dealing with integers to surpass it).
if the function would be:
f(i) = 2*f(i-1) //e.g. x=2*x
then the pattern would be:
f(i) = 2*2*[...k times]*f(i-k) = f(i-k)*(2^k) = f(0)*(2^i)
And in this case, then the inverse of the function would be a single logarithm in base 2.
My math is not very rigorous, but I hope you'll get the idea.

Think about how x changes with the number of iterations through the loop. Each time, you cube it. So after i iterations, the value will be 2 cubed, cubed again... and so on, i times. Let's use x(i) to denote this expression. Let's say x(0)=2, x(1)=23, etc (I'm using ab to mean a raised to the bth power).
We're done when x(i)>=n. How long does it take? Let's solve for i.
First, we take a log on both sides: ln(x(i))>=ln(n)
ln(x(i)) = ln(x(i-1))*3 = ln(x(i-2))*(3**2) = ... = ln(x(0))*(3**i)
(the above uses [this property][1]: ln(x**b)==ln(x)*b)
so, 3**i * 2 >=ln(n). Let's take another logarithm:
ln(3**i * 2) = ln(2) + ln(3)*i
so ln(2) + ln(3)* i >= ln(ln(n))
Now we can solve for i: i >= ( ln(ln(n))-ln(2) ) / ln(3)
We can ignore the constant factors, and we're left with the conclusion that we'll take log(log(n)) steps. That's the complexity of your algorithm.
Hopefully, breaking down all the steps like that helps.

Let
L3 = log to the base 3
L2 = Log to the base 2
Then the correct answer is O(L3(L2(n)) and NOT O(L2(L2(n)).
Start with x = x * 2. x will increase exponentially till it reaches n, thus making the time complexity O(L2(n))
Now consider x = x * x. x increases faster than the above. In every iteration the value of x jumps to the square of its previous value. Doing some simple math, here is what we get:
For x = 2
n = 4, iterations taken = 1
n = 16, iterations taken = 2
n = 256, iterations taken = 3
n = 65536, iterations taken = 4
Thus, the time complexity is O(L2(L2(n)). You can verify this by putting values above values for n.
Now coming to your problem, x = x * x * x. This will increase even faster than x = x * x. Here is the table:
For x = 2
n = 8, iterations taken = 1
n = 512, iterations taken = 2
n = (512*512*512), iterations taken = 3 and so on
If you look at this carefully, this turns out to be O(L3(L2(n)). L2(n) will get you the power of two, but since you are taking cube of x in every iteration, you will have to take log to the base 3 of it to find out the correct number of iteration taken.
So I think the correct answer is O(log-to-base-3(log-to-base-2(n))
Generalizing this, if x = x * x * x * x * .. (k times), then the time complexity is O(log-to-base-k(log-to-base-2(n)

If the code inside the while loop were
x = 2*x;
x would reach n in O(log(n)) iterations. Since you're cubing x instead of just multiplying it by a constant, you'll reach n faster.

Given
log ( A * x ) == log ( A ) + log ( x )
log ( x * x * x ) == 3 * log ( x )
So
log ( log ( x * x * x ) ) == log ( 3 * log ( x ) )
== log ( 3 ) + log ( log ( x ) )
How much faster or slower ( measured by number of iterations of the loop ) will this function be than your function?
int log_foo ( int n )
{
double log_x = log ( 2 );
const double log_n = log ( n );
while ( log_x < log_n )
{
log_x = 3 * log_x;
}
return exp ( log_x );
}
And how much faster or slower will this function be than your function?
int log_log_foo ( int n )
{
double log_log_x = log ( log ( 2 ) );
const double log_log_n = log ( log ( n ) );
const double log_3 = log ( 3 );
while ( log_log_x < log_log_n )
{
log_log_x += log_3;
}
return exp ( exp ( log_log_x ) );
}
But this function only increments log_log_x by a constant, so it's easy to work out how many iterations it does.

Let i be the number of iteration steps and x(i) the value of x after i steps. We have
x(0) = 2
x(i) = x(i-1)³
The total number of steps is the biggest i so that x(i) < n.
We have
log x(i) = log x(i-1)³
= 3·log x(i-1)
= 3·log x(i-2)³
= 3²·log x(i-2)
= 3^i·log x(0)
= 3^i·log 2
⇒ log log x(i) = log (3^i·log 2)
= log 3^i + log log 2
= i·log 3 + log log 2
The logarithm is strictly increasing, so
x(i) < n ⇔ log log x(i) < log log n
⇔ i·log 3 + log log 2 < log log n
⇔ i < (log log n - log log 2) / log 3 ∈ O(log log n)

Why not add a counter variable to count the number of iterations of the loop. Print it out just before the function returns.
Then call the function for a range of values, e.g. 3 to 1,000,000 to start with. Then plot your result using something like GNUPlot.
Then see if the graph matches a known curve.

Related

How to subdivide an array?

I want to split an array into segments by percents. For example, divide 100 elements into segments occupying [1/3,1/4,5/12], but [1/3,1/4,5/12]*100=[33.3,25,41.7], so it's necessary to adjust them to integers [33,25,42] (others like [34,24,42] or [33,26,41] are also acceptable, a wandering within 1 is not important).
Currently I use a loop to do this recursively
function x = segment(n,pct)
x = n * pct;
y = fix(x);
r = x - y;
for ii = 1 : length(r)-1
[r(ii),r(ii+1)] = deal(fix(r(ii)),r(ii+1)+r(ii)-fix(r(ii)));
end
x = y + r;
segment(100,[1/3,1/4,5/12]) gives [33,25,42].
Is there better way without recursive loop?
You can just use Adiel's comment for most of the cases, and just catch any rogue result after and correct it, only if it needs to be corrected:
function out = segmt( n , pct )
% This works by itself in many cases
out = round(n.*pct) ;
% for the other cases:
% if the total is not equal to the initial number of point, the
% difference will be affected to the largest value (to minimize the
% percentage imbalance).
delta = sum(out) - n ;
if delta ~= 0
[~,idx] = max( out ) ;
out(idx) = out(idx) - delta ;
end

How to solve logistic regression using gradient Descent?

I was solving a exercise of a online course form coursera on machine learning. The problem statement is :
Suppose that a high school has a dataset representing 40 students who were admitted to college and 40 students who were not admitted. Each ( x(i), y(i) ) training example contains a student's score on two standardized exams and a label of whether the student was admitted.
Our task is to build a binary classification model that estimates college admission chances based on a student's scores on two exams. In the training data,
a. The first column of your x array represents all Test 1 scores, and the second column represents all Test 2 scores.
b. The y vector uses '1' to label a student who was admitted and '0' to label a student who was not admitted.
I have solved it by using predefined function named fminunc. Now , i am solving it by using gradient descent but my graph of cost vs number of iteration is not conversing i.e cost function value is not decreasing with number of iteration . My theta value is also not matching with the answer that should i get.
theta value that i got :
[-0.085260 0.047703 -0.022851]
theta value that i should get (answer) :
[-16.38 0.1483 0.1589]
My source code :
clear ; close all; clc
x = load('/home/utlesh/Downloads/ex4x.txt');
y = load('/home/utlesh/Downloads/ex4y.txt');
theta = [0,0,0];
alpha = 0.00002;
a = [0,0,0];
m = size(x,1);
x = [ones(m,1) x];
n = size(x,2);
y_hyp = y*ones(1,n);
for kk = 1:100000
hyposis = 1./(1 + exp(-(x*theta')));
x_hyp = hyposis*ones(1,n);
theta = theta - alpha*1/m*sum((x_hyp - y_hyp).*x);
a(kk,:) = theta ;
end
cost = [0];
for kk = 1:100000
h = 1./(1 + exp(-(x*a(kk,:)')));
cost(kk,:) = sum(-y .* log(h) - (1 - y) .* log(1 - h));
end
x_axis = [0];
for kk = 1:100000
x_axis(kk,:) = kk;
end
plot(x_axis,cost);
The graph that i got looks like that of 1/x;
Please tell me where i am doing mistake . If there is anything that i misunderstood please let me know .
What I can see missing is the usage of learning rate and weights. The weights can be adjusted in two modes online and batch.
The weights should be randomly assigned values between [-0.01,0.01]. I did an exercise as a part of my HW during my Master's. Below is the snippet:
assign values to weights between [-0.01,0.01] i.e. no. of weight values will be, no. of features + 1:
weights = -.01 + 0.02 * rand(3,1);
learnRate = 0.001;
Here running the code for set number of iterations: (It converged in 100 iterations also).
while iter < 100
old_output = new_output;
delta = zeros(cols-1,1);
for t = 1:rows
input = 0;
for j = 1:cols-1
input = input + weights(j) * numericdata(t,j);
end
new_output(t) = (1 ./ (1 + exp(-input)));
for j = 1:cols-1
delta(j) = delta(j) + (numericdata(t,4)-new_output(t)) * numericdata(t,j);
end
end
#Adjusting weights (Batch Mode):
for j=1:cols-1
weights(j) = weights(j) + learnRate * (delta(j));
end
error = abs(numericdata(:,4) - new_output);
errorStr(i) = (error(:));
error = 0;
iter = iter + 1;
i = i + 1;
end
Also, I had a talk with my professor, while studying it. He said, if the dataset given has the property to converge then you will see that when you randomly run it for different number of iterations.

Count the number of elements in an array fulfilling a simple condition

I am just jumping back into R after a long time away and I am surprised by how simple some of the things are to do. I have created 3 arrays:
Xs = runif(N, min=-1, max=1);
Ys = runif(N, min=-1, max=1);
Rs = sqrt( Xs^2 + Ys^2 );
where, obviously, X and Y (together) define N points within the (-1,1) square and R is the vector defining the distances of these points.
If I want to count the number of elements in Rs which are less than or equal to 1, is there a simple inl-line command to do this?
sum( Rs <= 1 )
Rs <= 1 yields a logical vector. TRUE equals 1; FALSE equals 0.

Matlab Error A(I) = B

I am currently looking at Binomial Option Pricing. I have written the code below, which works fine, when you enter the variables in one at a time. However, entering each set of values is very tedious, and I need to be able to analyse a large set of data. I have created arrays for each of the variables. But, I keep getting the error; A(I) = B, the number of elements in B must equal I. The function is shown below.
function C = BinC(S0,K,r,sig,T,N);
% PURPOSE:
% To return the value of a European call option using the Binomial method
%-------------------------------------------------------------------------
% INPUTS:
% S0 - The initial price of the underlying asset
% K - The strike price
% r - The risk free rate of return, expressed as a decimal
% sig - The volatility of the underlying asset, expressed as a decimal
% T - The time to maturity, expressed as a decimal
% N - The number of steps
%-------------------------------------------------------------------------
dt = T/N;
u = exp(sig*sqrt(dt));
d = 1/u;
p = (exp(r*dt) - d)/(u - d);
S = zeros(N+1,1);
% Price of underlying asset at time T
for n = 1:N+1
S(n) = S0*(d^(N+1-n))*(u^(n-1));
end
% Price of Option at time T
for n = 1:N+1
C(n) = max(S(n)- K, 0);
end
% Backtrack to get option price at time 0
for i = N:-1:1
for n = 1:i
C(n) = exp(-r*dt)*(p*C(n+1) + (1-p)*C(n));
end
end
disp(C(1))
After importing my data, I entered this in to the command window.
for i=1:20
w(i)= BinC(S0(i),K(i),r(i),sig(i),T(i),N(i));
end
When I enter w, all I get back is w = []. I have no idea how I can make A(I) = B. I apologise, if this is a very silly question, but I am new to Matlab and in need of help. Thanks
Your function computes an entire vector C, but displays only C(1). This display is deceptive: it makes you think the function is returning a scalar, but it's not: it's returning the entire vector C, which you try to store into a scalar location.
The solution is simple: Change your function definition to this (rename the output variable):
function out = BinC(S0,K,r,sig,T,N);
Then at the last line of the function, remove the disp, and replace it with
out = C(1);
To verify all of this (compare with your non-working example), try calling it by itself at the command line, and examine the output.

Need some help calculating percentile

An rpc server is given which receives millions of requests a day. Each request i takes processing time Ti to get processed. We want to find the 65th percentile processing time (when processing times are sorted according to their values in increasing order) at any moment. We cannot store processing times of all the requests of the past as the number of requests is very large. And so the answer need not be exact 65th percentile, you can give some approximate answer i.e. processing time which will be around the exact 65th percentile number.
Hint: Its something to do how a histogram (i.e. an overview) is stored for a very large data without storing all of data.
Take one day's data. Use it to figure out what size to make your buckets (say one day's data shows that the vast majority (95%?) of your data is within 0.5 seconds of 1 second (ridiculous values, but hang in)
To get 65th percentile, you'll want at least 20 buckets in that range, but be generous, and make it 80. So you divide your 1 second window (-0.5 seconds to +0.5 seconds) into 80 buckets by making each 1/80th of a second wide.
Each bucket is 1/80th of 1 second. Make bucket 0 be (center - deviation) = (1 - 0.5) = 0.5 to itself + 1/80th of a second. Bucket 1 is 0.5+1/80th - 0.5 + 2/80ths. Etc.
For every value, find out which bucket it falls in, and increment a counter for that bucket.
To find 65th percentile, get the total count, and walk the buckets from zero until you get to 65% of that total.
Whenever you want to reset, set the counters all to zero.
If you always want to have good data available, keep two of these, and alternate resetting them, using the one you reset least recently as having more useful data.
Use an updown filter:
if q < x:
q += .01 * (x - q) # up a little
else:
q += .005 * (x - q) # down a little
Here a quantile estimator q tracks the x stream,
moving a little towards each x.
If both factors were .01, it would move up as often as down,
tracking the 50 th percentile.
With .01 up, .005 down, it floats up, 67 th percentile;
in general, it tracks the up / (up + down) th percentile.
Bigger up/down factors track faster but noisier --
you'll have to experiment on your real data.
(I have no idea how to analyze updowns, would appreciate a link.)
The updown() below works on long vectors X, Q in order to plot them:
#!/usr/bin/env python
from __future__ import division
import sys
import numpy as np
import pylab as pl
def updown( X, Q, up=.01, down=.01 ):
""" updown filter: running ~ up / (up + down) th percentile
here vecs X in, Q out to plot
"""
q = X[0]
for j, x in np.ndenumerate(X):
if q < x:
q += up * (x - q) # up a little
else:
q += down * (x - q) # down a little
Q[j] = q
return q
#...............................................................................
if __name__ == "__main__":
N = 1000
up = .01
down = .005
plot = 0
seed = 1
exec "\n".join( sys.argv[1:] ) # python this.py N= up= down=
np.random.seed(seed)
np.set_printoptions( 2, threshold=100, suppress=True ) # .2f
title = "updown random.exponential: N %d up %.2g down %.2g" % (N, up, down)
print title
X = np.random.exponential( size=N )
Q = np.zeros(N)
updown( X, Q, up=up, down=down )
# M = np.zeros(N)
# updown( X, M, up=up, down=up )
print "last 10 Q:", Q[-10:]
if plot:
fig = pl.figure( figsize=(8,3) )
pl.title(title)
x = np.arange(N)
pl.plot( x, X, "," )
pl.plot( x, Q )
pl.ylim( 0, 2 )
png = "updown.png"
print >>sys.stderr, "writing", png
pl.savefig( png )
pl.show()
An easier way to get the value that represents a given percentile of a list or array is the scoreatpercentile function in the scipy.stats module.
>>>import scipy.stats as ss
>>>ss.scoreatpercentile(v,65)
there's a sibling percentileofscore to return the percentile given the value
you will need to store a running sum and a total count.
then check out standard deviation calculations.

Resources