Array manipulation in Fortran - arrays

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.

Related

How to convert array of connections between graph nodes into a 2D array of nodes with their connections?

Let's have an undirected graph given by vertices which are represented by adjacent nodes:
(1, 2), (1, 3), (3, 2), (4, 1), (2, 5), (4, 5) which looks like this:
The order is completely random and every connection is there only once, so if there's already (1, 2), there won't be (2, 1). I have an array int vertices[12] = {1, 2, 1, 3, 3, 2, 4, 1, 2, 5, 4, 5}. I would like to create an array where i-th index represents a node number i and the corresponding sub-array represents its neighbors, so in this case like this: int graph[5][4] = {{2, 3, 4}, {1, 3, 5}, {1, 2}, {1, 5}, {2, 4}}. I tried going through it by first looking at all the even nodes and than the odd nodes but I kept running into a problem with two same nodes. Maybe I could first order it somehow before I start assigning. What's the simplest way?

Paradigms for constructing permutations explained

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/

create an array based on grouping (and conditions) from an array

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.

How to find all unique values of arrays of integers where the array length and maximum integer value are set

I am trying to write a function which generates all unique combinations of arrays for values up to a certain number.
The function has two parameters, one parameter is the length of the array and the other is the maximum size of the integer.
F(4, 3) is a function that will generate all possible unique combinations of positive integers less than or equal to 4 in a three integer array. F(10, 100) will generate all possible unique combinations of positive integers less than or equal to 10 in a 100 integer array.
The result for F(4, 3) would start like this:
(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 1), (1, 2, 2) ... (4, 4, 4)
F(10, 10) would start like this:
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1), (1, 1, 1, 1, 1, 1, 1, 1, 1, 2), ...
(10, 10, 10, 10, 10, 10, 10, 10, 10, 10)
There are P=Max**Len arrays for F(Max, Len), and there is bijection between numbers in range 0..P-1 and arrays.
So you can just walk in the loop through all numbers in that range and represent loop counter in M-ric numeral system (counter 4(dec) corresponds to (1, 2, 1) in your first example)
Alternate way - use array as multidigit counter (like old electrical meter display with rotating cylinders). When some digit becomes Max and should be incremented, it is reset to 1 and the next digit is incremented ((1, 1, 4) => (1, 2, 1) in your example).

Finding recurrence relation and complexity

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.

Resources