Based on the number of operations, finding out the recurrence relation!
a = N;
var = 0;
while (a > 1)
{
var = var + a;
num = 2 * var;
a = a / 2;
}
I think that the the recurrence relaton that will be formed is: (Assignment operations are to be not counted)
T(n)= (from a=1 to N)Σ(3)
Am I right??
Now using this recurrence relation, how to find its complexity.
What you want to do is find how many times this operation is called, so consider this: after each call a is divided by 2, so if M = N/2 then T(M) = T(N) - 1.
Now, each iteration of this loop divides N again so you get the following:
T(N) = T(N/2) + 1 = ... = k + T(N/(2^k))
The stop condition is this: a>1 so you need to check when N/(2^k) <= 1
N/2^k = 1 -> log (n) = k
So T(N) = log(n) + T(1) = log(n)
This is the answer in 'big O' notation.
Empirical approach:
First reduce the "educational noise" from the code by simplifying it and add an iteration counter (c). Then look at the result (N,count) and after a while you see, that 2 ^ count = N for all N in [1,2,4,8,16,..].
So the complexity Compl(loop) = O(log_2(N)).
let rec loop a c =
match a with
| x when x > 1 ->
let a1 = a / 2
loop a1 (c+1)
| _ -> (a,c)
// after staring at the result of the computation we came up with this theory:
let theory n = int (System.Math.Log10(float n) / System.Math.Log10(2.0))
[1..64]
|> List.map (fun a -> a,loop a 0, theory a)
|> List.map (fun (a0,(a,c),aa) -> a0,c,aa)
Data:
[(1, 0, 0); (2, 1, 1); (3, 1, 1); (4, 2, 2); (5, 2, 2); (6, 2, 2); (7, 2, 2);
(8, 3, 3); (9, 3, 3); (10, 3, 3); (11, 3, 3); (12, 3, 3); (13, 3, 3);
(14, 3, 3); (15, 3, 3); (16, 4, 4); (17, 4, 4); (18, 4, 4); (19, 4, 4);
(20, 4, 4); (21, 4, 4); (22, 4, 4); (23, 4, 4); (24, 4, 4); (25, 4, 4);
(26, 4, 4); (27, 4, 4); (28, 4, 4); (29, 4, 4); (30, 4, 4); (31, 4, 4);
(32, 5, 5); (33, 5, 5); (34, 5, 5); (35, 5, 5); (36, 5, 5); (37, 5, 5);
(38, 5, 5); (39, 5, 5); (40, 5, 5); (41, 5, 5); (42, 5, 5); (43, 5, 5);
(44, 5, 5); (45, 5, 5); (46, 5, 5); (47, 5, 5); (48, 5, 5); (49, 5, 5);
(50, 5, 5); (51, 5, 5); (52, 5, 5); (53, 5, 5); (54, 5, 5); (55, 5, 5);
(56, 5, 5); (57, 5, 5); (58, 5, 5); (59, 5, 5); (60, 5, 5); (61, 5, 5);
(62, 5, 5); (63, 5, 5); (64, 6, 6)]
The recurrence relation is:
T(1) = a
T(n) = b + T(n/2)
The first part comes from the case where the loop variable equals 1, in which case only the comparison at the top of the loop executes. The second line comes from the constant amount of work done in the loop body, b, plus the time to execute the loop with the updated loop variable value.
The first few terms are:
n T
1 a
2 a + b
4 a + 2b
8 a + 3b
Based on this we can guess the general form:
T(n) = a + b log n
Proving that is left as an exercise; but you can just plug it in to the recurrence relation to see that it satisfies the requirements.
The asymptotic complexity is logarithmic.
Related
Given an ndarray:
np.array(
(
(1, 2, 3, 3, 2),
(4, 5, 4, 3, 2),
(1, 1, 1, 1, 1),
(0, 0, 0, 0, 0),
(0, 2, 3, 4, 0),
)
)
extract the mean of the values bounded by a rectangle with coordinates: (1, 1), (3, 1), (1, 3), (3, 3).
The extracted region of the array would be:
5, 4, 3,
1, 1, 1,
0, 0, 0,
And the mean would be ~1.666666667
import numpy as np
arr = np.array(
(
(1, 2, 3, 3, 2),
(4, 5, 4, 3, 2),
(1, 1, 1, 1, 1),
(0, 0, 0, 0, 0),
(0, 2, 3, 4, 0),
)
)
mean = arr[1:4, 1:4].mean()
According to the Algorithm Design Manual Sec 14.4, there are two paradigms to constructing permutations:
Ranking/Unranking
Incremental Change
I'm not grasping the section and I would appreciate an alternative explanation. Can you elaborate on the two with examples?
Ranking/Unranking
A particular ranking of a permutation associates an integer with a particular ordering of all the permutations of a set of distinct items. For our purposes the ranking will assign integers 0..(n!-1) to an ordering of all the permutations of the integers 0..(n-1).
Rank({2, 1, 0, 3}) = 17
Unranking is the inverse process: given a rank r obtain the permutation.
Unrank(17) = {2, 1, 0, 3}
Therefore, rank and unrank functions must be inverses of each other, that is, there exists a bijection.
permutation p = Unrank(Rank(p), n)
For example, the permutations of the digits zero to 3 arranged lexicographically have the following rank:
PERMUTATION RANK
(0, 1, 2, 3) -> 0
(0, 1, 3, 2) -> 1
(0, 2, 1, 3) -> 2
(0, 2, 3, 1) -> 3
(0, 3, 1, 2) -> 4
(0, 3, 2, 1) -> 5
(1, 0, 2, 3) -> 6
(1, 0, 3, 2) -> 7
(1, 2, 0, 3) -> 8
(1, 2, 3, 0) -> 9
(1, 3, 0, 2) -> 10
(1, 3, 2, 0) -> 11
(2, 0, 1, 3) -> 12
(2, 0, 3, 1) -> 13
(2, 1, 0, 3) -> 14
(2, 1, 3, 0) -> 15
(2, 3, 0, 1) -> 16
(2, 3, 1, 0) -> 17
(3, 0, 1, 2) -> 18
(3, 0, 2, 1) -> 19
(3, 1, 0, 2) -> 20
(3, 1, 2, 0) -> 21
(3, 2, 0, 1) -> 22
(3, 2, 1, 0) -> 23
Incremental Change
Incremental change methods work by defining the next and previous operations to transform one permutation into another, typically by swapping two elements. The tricky part is to schedule the swaps so that permutations do not repeat until all of them have been generated. The output picture below gives an ordering of the six permutations of {1,2,3} using a single swap between successive permutations.
References
https://rosettacode.org/wiki/Permutations/Rank_of_a_permutation
https://en.wikipedia.org/wiki/Factorial_number_system#Permutations
https://computationalcombinatorics.wordpress.com/2012/09/10/ranking-and-unranking-of-combinations-and-permutations/
So, I have the following array (structured as Array{Tuple{Int,Float64,Int,Int},1} but it can also be an Array of Arrays) and where the first element of the tuple is an ID and the second is a number indicating a cost. What i want to do is to group by ID and then take the cost difference between the cheapest and the second cheapest cost for such ID, if there is no second cost, the cost difference should be typemax(Float64) -firstcost. Regarding the third and fourth elements of the Tuple, I want to keep those of the firstcost (or minimum cost in that sense).
Example of what I have
(1, 223.2, 2, 2)
(1, 253.2, 3, 2)
(2, 220.0, 4, 6)
(3, 110.0, 1, 4)
(3, 100.0, 3, 8)
Example of what I want:
(1, 30.0, 2, 2)
(2, typemax(Float64)-220.0, 4, 6)
(3,10.0, 3, 8)
This is one way of doing it:
A = [(1, 223.2, 2, 2), (1, 253.2, 3, 2), (2, 220.0, 4, 6), (3, 110.0, 1, 4), (3, 100.0, 3, 8)]
function f(a)
aux(b::Vector) = (b[1][1], (length(b) == 1 ? typemax(Float64) : b[2][2]) - b[1][2], b[1][3:4]...)
sort([aux(sort(filter(x -> x[1] == i, a))) for i in Set(map(first, a))])
end
#show f(A)
There's SplitApplyCombine.jl, which implements (unsurprisingly) a split-apply-combine logic like that found in DataFrames. This is an example where I would stay away from simple one-liners / short solution and write things out more explicitly in the interest of making the code readable and understandable if someone else (or you yourself in a few months time!) reads it:
julia> tups = [(1, 223.2, 2, 2)
(1, 253.2, 3, 2)
(2, 220.0, 4, 6)
(3, 110.0, 1, 4)
(3, 100.0, 3, 8)]
5-element Array{Tuple{Int64,Float64,Int64,Int64},1}:
(1, 223.2, 2, 2)
(1, 253.2, 3, 2)
(2, 220.0, 4, 6)
(3, 110.0, 1, 4)
(3, 100.0, 3, 8)
julia> using SplitApplyCombine
julia> function my_fun(x) # function to apply
if length(x) == 1
return (x[1][1], typemax(Float64) - x[1][2], x[1][3], x[1][4])
else
return (x[1][1], -diff(sort(getindex.(x, 2), rev = true)[1:2]), x[1][4])
end
end
my_fun (generic function with 1 method)
julia> [my_fun(x) for x in group(first, tups)] # apply function group wise
3-element Array{Tuple{Int64,Any,Int64,Vararg{Int64,N} where N},1}:
(2, Inf, 4, 6)
(3, [10.0], 4)
(1, [30.0], 2)
If performance is a concern you might want to think about my_fun and do some profiling to see if and how you can improve it - the only thing I've done here is to use diff to subtract the first from the second element of the sorted array to avoid sorting twice.
I have a 5 dimensional array want to do a calculation for each field and depending on the result fill each field either with 'true' or 'false'. Now I am wondering if there is a fast way of doing so without using 5 'nested' loops.
Thanks for your help
Edit:
Sorry that the question wasn't clear. I need to do calculations with 5 different variables and I have check each possible combination.
My current approach is this:
while i<10
while j<10
while k < 10
while l<10
while m <10
#some calculation which returns true or false
A[i,j,k,l,m]=f(i, j, k, l, m);
m+=1;
end
l+=1;
end
k +=1;
end
j+=1;
end
i+=1;
end
where A is my array. Now I am wondering if there is a more efficient way of doing this.
Sorry, I hope it is more clarified now.
You can use CartesianIndices function for example like this:
julia> x = Array{Tuple}(undef, 2,2,2,2,2);
julia> for idx in CartesianIndices(x)
x[idx] = Tuple(idx)
end
julia> x
2×2×2×2×2 Array{Tuple,5}:
[:, :, 1, 1, 1] =
(1, 1, 1, 1, 1) (1, 2, 1, 1, 1)
(2, 1, 1, 1, 1) (2, 2, 1, 1, 1)
[:, :, 2, 1, 1] =
(1, 1, 2, 1, 1) (1, 2, 2, 1, 1)
(2, 1, 2, 1, 1) (2, 2, 2, 1, 1)
[:, :, 1, 2, 1] =
(1, 1, 1, 2, 1) (1, 2, 1, 2, 1)
(2, 1, 1, 2, 1) (2, 2, 1, 2, 1)
[:, :, 2, 2, 1] =
(1, 1, 2, 2, 1) (1, 2, 2, 2, 1)
(2, 1, 2, 2, 1) (2, 2, 2, 2, 1)
[:, :, 1, 1, 2] =
(1, 1, 1, 1, 2) (1, 2, 1, 1, 2)
(2, 1, 1, 1, 2) (2, 2, 1, 1, 2)
[:, :, 2, 1, 2] =
(1, 1, 2, 1, 2) (1, 2, 2, 1, 2)
(2, 1, 2, 1, 2) (2, 2, 2, 1, 2)
[:, :, 1, 2, 2] =
(1, 1, 1, 2, 2) (1, 2, 1, 2, 2)
(2, 1, 1, 2, 2) (2, 2, 1, 2, 2)
[:, :, 2, 2, 2] =
(1, 1, 2, 2, 2) (1, 2, 2, 2, 2)
(2, 1, 2, 2, 2) (2, 2, 2, 2, 2)
The code stores in an entry `x[a,b,c,d,e]` a tuple `(a,b,c,d,e)`.
You can do the same kind of operations as you'd do on a 1-Dimensional matrix.
julia> A = rand(4,4,4,4,4);^C
julia> for (i, v) in enumerate(A)
if v > 0.5
A[i] = 0
end
end
Also, somthing like:
julia>map!(x->x>.5, A, A)
Also if the original Array is of some type other than Bool I'd suggest you use a different matrix to assign the result values for type stability.
I have two arrays fListU and fListD both of which contain 4-tuples. Specifically:
fListU = [(2, 1, 1, 0), (2, 5, 5, 0), (5, 4, 10, 0), (6, 1, 5, 0), (6, 5, 7, 0)]
fListD = [(1, 4, 0, 4), (3, 4, 0, 4), (5, 4, 0, 6)]
Now I want to put together these into one array, with the condition that when the first two items of the tuples are equal, then the third and fourth items of two lists should be added. In this case, the result I am looking for is
fList = [(2, 1, 1, 0), (2, 5, 5, 0), (5, 4, 10, 6), (6, 1, 5, 0),
(6, 5, 7, 0), (1, 4, 0, 4), (3, 4, 0, 4)]
where (5, 4, 10, 0) and (5, 4, 0, 6) are combined to (5, 4, 10, 6).
This is what I tried.
ALLOCATE (fList((n-1)**2,4))
fList = 0
p = 1 ! p signifies the position in fList.
DO k = 1, ((n-1)**2), 1 ! k is the index for fListD
DO l = 1, ((n-1)**2), 1 ! l is the index for fListU
IF ( ALL (fListU(l,1:2) == fListD(k,1:2)) ) THEN
fList(p,1:2) = fListU(l,1:2)
fList(p,3) = fListU(l,3)
fList(p,4) = fListD(k,4)
ELSE
fList(p,:) = fListU(l,:)
p = p+1
fList(p,:) = fListD(k,:)
p = p+1
END IF
END DO
END DO
This is not producing what I want. What would be the problem?
I'm not sure how you are reading in fListU and fListD. One thing that you need to realise is that in Fortran (other than most other programming languages), the first index of a multi-dimensional array is the fastest changing. That's why the way you read the data in is so important: If you read the data in sequentially, or use reshape, then the second element you read in will be in position (2, 1), not (1, 2) as you might expect.
So I strongly suggest to have the shape of fListU as (4, 5), not (5, 4), and consequently address the first two elements of a tuple as flist(1:2, p).
Here's a possible solution that knows the lengths of the two input arrays.
The output will still contain another line of all zeros, because I haven't programmed it to get the size of the output array right (instead it just uses the sum of the sizes of the input arrays).
program Combine_List_Simple
implicit none
integer, dimension(:, :), allocatable :: fListU, fListD, fList
integer :: u_size, d_size
integer :: u_index, d_index, f_index
u_size = 5
allocate(fListU(4, u_size))
fListU = reshape((/2, 1, 1, 0, 2, 5, 5, 0, 5, 4, 10, 0, &
6, 1, 5, 0, 6, 5, 7, 0/), (/4, u_size/))
d_size = 3
allocate(fListD(4, d_size))
fListD = reshape((/1, 4, 0, 4, 3, 4, 0, 4, 5, 4, 0, 6/), &
(/4, d_size/))
allocate(fList(4, u_size + d_size))
flist(:, 1:u_size) = fListU(:, :)
flist(:, u_size+1:) = 0
f_index = u_size+1
d_loop : do d_index = 1, d_size
do u_index = 1, u_size
if (all(fListD(1:2, d_index) == fList(1:2, u_index))) then
fList(4, u_index) = fListD(4, d_index)
cycle d_loop
end if
end do
fList(:, f_index) = fListD(:, d_index)
f_index = f_index+1
end do d_loop
write(*, '(4I4)') fList
end program Combine_List_Simple
This code also assumes that the 4th element of all tuples in fListU and the 3rd element of all tuples in fListD is zero. But your code seems to assume that as well. Also it assumes that the combination of 1st and 2nd elements of the tuples are unique in each of the input arrays.
First, I completely copy the contents of fListU into fList. Then I loop over fListD, and compare it to the first entries in fList, because that's where the contents of fListU are. If it finds a match, it updates only the 4th element of the tuple, and then cycles the loop of the fListD array.
Only if it doesn't find a match will it reach the end of the inner loop, and then append the tuple to fList.