Selecting k*k subarray from p*p*n array in Fortran - select

I have a ppn array in Fortran, and I want to extract k*k subarray from that bigger array. I tried like this, but not sure does it work:
do i=1,p
vp(i)=i
end do
help=y(1:p,t)*vp
do t = 1, n
A(1:k,1:k,t) = B(pack(help,help>0), pack(help,help>0), t)
end do
where y contains values 0 and 1, 1 meaning that row/column is wanted to subarray. Does that work, and if not, how that same thing could be archieved? Thanks.

If I understand what you want to do, here is an example program that extracts selected columns and rows, but not using much array notation.
program test
integer, parameter :: Adim = 2
integer, parameter :: Bdim = 3
integer, dimension (Adim,Adim) :: A
integer, dimension (Bdim,Bdim) :: B
logical, dimension (Bdim) :: good_row = [.true., .false., .true.]
logical, dimension (Bdim) :: good_col = [.false., .true., .true.]
integer :: i, j, ia, ja, ib, jb
if (count (good_row) /= Adim .or. count (good_col) /= Adim) then
write (*, *) 'selection arrays not setup correctly.'
stop
end if
do i=1, Bdim
do j=1, Bdim
B (i,j) = i + i*j**2 ! test values
end do
end do
do i=1, Bdim
write (*, *) (B (i, j), j=1, Bdim)
end do
ia = 0
do ib=1, Bdim
if (good_row (ib)) then
ia = ia + 1
ja = 0
do jb=1, Bdim
if (good_col (jb)) then
ja = ja + 1
!write (*, *) ia, ja, ib, jb
A(ia,ja) = B(ib,jb)
end if
end do
end if
end do
write (*, *)
do i=1, Adim
write (*, *) (A (i, j), j=1, Adim)
end do
stop
end program test

Solution two, using array operations at the vector (1D array) level -- replace the main loop with:
ia = 0
do ib=1, Bdim
if (good_row (ib)) then
ia = ia + 1
A (ia,:) = pack (B(ib,:), good_col)
end if
end do
Solution three, fully using array operations:
program test
integer, parameter :: Adim = 2
integer, parameter :: Bdim = 3
integer, dimension (Adim,Adim) :: A
integer, dimension (Bdim,Bdim) :: B
logical, dimension (Bdim,Bdim) :: mask
integer :: i, j
mask (1,:) = [.false., .true., .true.]
mask (2,:) = .false.
mask (3,:) = [.false., .true., .true.]
do i=1, Bdim
do j=1, Bdim
B (i,j) = i + i*j**2 ! test values
end do
end do
do i=1, Bdim
write (*, *) (B (i, j), j=1, Bdim)
end do
A = reshape ( pack (B, mask), [Adim, Adim] )
write (*, *)
do i=1, Adim
write (*, *) (A (i, j), j=1, Adim)
end do
stop
end program test

Not sure if these fragments of non-code are any use to you but;
Don't forget the array sectioning features of Fortran.
Don't forget that you can use vector subscripts to get array sections, for example, you might select elements of a vector v like this:
v( (/1, 3, 6, 5, 10 /) )
Vector subscripting can be applied to arrays of rank greater than 1. It would hurt my head to figure out your subscripting requirements this way, but you might want to try it.

Yes it should work, and you even do not need the do t = ... loop
program main
integer,dimension(3,3,2):: a
integer,dimension(4,4,2):: b
integer,dimension(4):: y
integer,dimension(4):: idx
integer:: i,j,k
y = (/ 1 , 0 , 1 , 1 /)
idx = (/ (i,i=1,4) /)
b(:,:,:)=reshape((/((((i+10*j+100*k),i=1,4),j=1,4),k=1,2)/),(/4,4,2/))
a(:,:,:) = b( pack(idx,y>0) , pack(idx,y>0) , :)
print '(A2/,(4I4))','b=',b
print '(A2/,(3I4))','a=',a
end
compiled with gfortran 4.2.3 correctly gives me
b=
111 112 113 114
121 122 123 124
131 132 133 134
141 142 143 144
211 212 213 214
221 222 223 224
231 232 233 234
241 242 243 244
a=
111 113 114
131 133 134
141 143 144
211 213 214
231 233 234
241 243 244
You could also use
k = count( y> 0)
a(1:k,1:k,:) = b( pack(idx,y>0) , pack(idx,y>0) , :)
Or think using LOGICAL .true. and .false. instead of 1 and 0...
program main
integer,dimension(3,3,2):: a
integer,dimension(4,4,2):: b
logical,dimension(4):: y
integer,dimension(4):: idx
integer:: i,j,k
idx = (/ (i,i=1,4) /)
y = idx /= 2
b(:,:,:)=reshape((/((((i+10*j+100*k),i=1,4),j=1,4),k=1,2)/),(/4,4,2/))
k = count( y )
a(1:k,1:k,:) = b( pack(idx,y) , pack(idx,y) , :)
print '(A2/,(4I4))','b=',b
print '(A2/,(3I4))','a=',a
end

Related

parameter passing strategy in a semi-C code

it's a problem in my assignment.
Following code written in semi-C language. Set parameter passing type for f, g and h functions in order to have 29, 34 and 43 at the end of execution.for instance, for acquiring 29 we have to use call-by-value in f,g and h . but I don't know what should I do for 34 and 43?
f(x) {return g(2*x);}
g(x) {let y = 1 in {h(y); return x + y + x;}}
h(x) {x = x + 5; return 0}
main() {printf(f(7));}

Reverse mapping indices in matlab

I have a such index vector which maps the cells.
For example (1 -> 310),(2 -> 910),....(1024 -> 67)
It maps the 8*8 cell(eg:1st cell) of image to 8*8 cell(eg:310th cell).
I have 1024 8*8 cells and I want to reverse this process to get their first indices.
I mean, after this mapping It reorder to the basic order.
(eg: 310th cell comes to 1th and 910th cell comes to 2).
Anyone can help?
yeah sure ,I write my program, for example I have these image blocks for an image.
% dividing of main image to 8*8 blocks:
U = floor(M1/8);
V = floor(M2/8);
I_div = cell(U,V);
K = 1; L = 1;
for u = 1:U
for v = 1:V
I_div{u,v} = I2(K:K+7,L:L+7);
I_div_DCT{u,v} = dct2(I_div{u,v}); %%% the main blocks
L = L + 8;
end
K = K + 8;
L = 1;
end
a=reshape(I_div_DCT',[],1)';
b=cell(1,1024);
for i=1:1024
b(i)=a(index(i));
end
%%% index is the 1*1024 array, something like this:
%%% 1 2 3 4 5 6 7 8 ....
%%% 367 910 274 308 275 429 403 276 ....
if the first image block be a(1,1)=[8*8 double]; after implementing b(i)=a(index(i)) it goes to the 367th [8*8]block and for example The 787th [8*8]block comes to the first block,(just a simple mapping).
I want to bring back this blocks into their original indeices after implementing my changes!
Suppose you have a forward map
fMap = [367, 910, 274, 308, 275, 429, 403, 276, ...
Such that index k is mapped to fMap( k ).
Now you war the "inverse" map that will map fMap(k) back to k.
Or in other words k == revMap( fMap( k ) ).
For simplicity I'll assume fMap is a permutation. then
revMap( fMap ) = 1:n
A small example:
>> fMap
fMap =
1 4 5 3 2
>> rMap( fMap ) = 1:5
rMap =
1 5 4 2 3

matlab: convert a string of hex values to a decimal value?

I wrote functions to convert 100,000 hex strings to values, but it takes 10 seconds to perform on the whole array. Does Matlab have a function to do this, so that it is faster, ... ie: less than 1 second for the array?
function x = hexstring2dec(s)
[m n] = size(s);
x = zeros(1, m);
for i = 1 : m
for j = n : -1 : 1
x(i) = x(i) + hexchar2dec(s(i, j)) * 16 ^ (n - j);
end
end
function x = hexchar2dec(c)
if c >= 48 && c <= 57
x = c - 48;
elseif c >= 65 && c <= 70
x = c - 55;
elseif c >= 97 && c <= 102
x = c - 87;
end
Try using hex2dec. It should be faster much faster than looping over each character.
shoelzer's answer is obviously the best.
However, if you want to do the conversion by yourself, then you might find this useful:
Assuming s is a char matrix: all hex numbers are of the same length (zero padded if necessary) and each row has a single number. Then
ds = double( upper(s) ); % convert to double
sel = ds >= double('A'); % select A-F
ds( sel ) = ds( sel ) - double('A') + 10; % convert to 10 - 15
ds(~sel) = ds(~sel) - double('0'); % convert 0-9
% do the sum through vector product
v = 16.^( (size(s,2)-1):-1:0 );
x = s * v(:);

Modulo and remainder (Chinese remainder theorem) in MATLAB

How do I find the least possible value in Matlab, given the modulo values and its remainder values in an array? for example:
A=[ 23 90 56 36] %# the modulo values
B=[ 1 3 37 21] %# the remainder values
which leads to the answer 93; which is the least possible value.
EDIT:
Here is my code but it only seems to display the last value of the remainder array as the least value:
z = input('z=');
r = input('r=');
c = 0;
m = max(z);
[x, y] = find(z == m);
r = r(y);
f = find(z);
q = max(f);
p = z(1:q);
n = m * c + r;
if (mod(n, p) == r)
c = c + 1;
end
fprintf('The lowest value is %0.f\n', n)
Okay, so your goal is to find the smallest x that satisfies B(i) = mod(x, A(i)) for each i.
This page contains a very simple (yet thorough) explanation of how to solve your set of equations using the Chinese Remainder Theorem. So, here's an implementation of the described method in MATLAB:
A = [23, 90]; %# Moduli
B = [1, 3]; %# Remainders
%# Find the smallest x that satisfies B(i) = mod(x, A(i)) for each i
AA = meshgrid(A);
assert(~sum(sum(gcd(AA, AA') - diag(A) > 1))) %# Check that moduli are coprime
M = prod(AA' - diag(A - 1));
[G, U, V] = gcd(A, M);
x = mod(sum(B .* M .* V), prod(A))
x =
93
You should note that this algorithm works only for moduli (the values of A) which are coprime!
In your example, they are not, so this will not work for your example (I've put an assert command to break the script if the moduli are not coprime). You should try to implement yourself the full solution for non-comprime moduli!
P.S
Also note that the gcd command uses Euclid's algorithm. If you are required to implement it yourself, this and this might serve you as good references.

A Fast and Efficient way to create a matrix from a series of product

Ax, Ay, Az: [N-by-N]
B=AA (a dyadic product)
It means :
B(i,j)= [Ax(i,j);Ay(i,j);Az(i,j)]*[Ax(i,j) Ay(i,j) Az(i,j)]
B(i,j) : a 3x3 matrix.
One way to construct B is:
N=2;
Ax=rand(N); Ay=rand(N); Az=rand(N); %# [N-by-N]
t=1;
F=zeros(3,3,N^2);
for i=1:N
for j=1:N
F(:,:,t)= [Ax(i,j);Ay(i,j);Az(i,j)]*[Ax(i,j) Ay(i,j) Az(i,j)];
t=t+1; %# t is just a counter
end
end
%# then we can write
B = mat2cell(F,3,3,ones(N^2,1));
B = reshape(B,N,N)';
B = cell2mat(B);
Is there a faster way for when N is large.
Edit:
Thanks for your answer. (It's faster)
Let's put:
N=2;
Ax=[1 2;3 4]; Ay=[5 6;7 8]; Az=[9 10;11 12];
B =
1 5 9 4 12 20
5 25 45 12 36 60
9 45 81 20 60 100
9 21 33 16 32 48
21 49 77 32 64 96
33 77 121 48 96 144
Run:
??? Error using ==> mtimes
Inner matrix dimensions must agree.
If I write :P = Ai*Aj; then
B =
7 19 31 15 43 71
23 67 111 31 91 151
39 115 191 47 139 231
10 22 34 22 50 78
34 78 122 46 106 166
58 134 210 70 162 254
That is defferent from above
A(:,:,1) deffer from [Ax(1,1) Ay(1,1) Az(1,1)]
Edit:
N=100;
Me :Elapsed time is 1.614244 seconds.
gnovice :Elapsed time is 0.056575 seconds.
N=200;
Me :Elapsed time is 6.044628 seconds.
gnovice :Elapsed time is 0.182455 seconds.
N=400;
Me :Elapsed time is 23.775540 seconds.
gnovice :Elapsed time is 0.756682 seconds.
Fast!
rwong: B was not the same.
Edit:
After some modification for my application :
by gnovice codes
1st code : 19.303310 seconds
2nd code: 23.128920 seconds
3rd code: 13.363585 seconds
It seems that any function calling like ceil,ind2sub ... make thw loops slow and shoud avoid if possible.
symIndex was interesting! Thank you.
Here's a fairly simple and general implementation that uses a single for loop to perform linear indexing and avoids dealing with 3-dimensional variables or reshaping:
%# General solution:
%# ----------------
B = cell(N);
for index = 1:N^2
A = [Ax(index) Ay(index) Az(index)];
B{index} = A(:)*A;
end
B = cell2mat(B);
EDIT #1:
In response to the additional question of how to reduce the number of calculations performed for a symmetric matrix B, you could use the following modified version of the above code:
%# Symmetric solution #1:
%# ---------------------
B = cell(N);
for index = find(tril(ones(N))).' %'# Loop over the lower triangular part of B
A = [Ax(index) Ay(index) Az(index)];
B{index} = A(:)*A;
symIndex = N*rem(index-1,N)+ceil(index/N); %# Find the linear index for the
%# symmetric element
if symIndex ~= index %# If we're not on the main diagonal
B{symIndex} = B{index}; %# then copy the symmetric element
end
end
B = cell2mat(B);
However, in such a case you may get better performance (or at least simpler looking code) by foregoing the linear indexing and using two for loops with subscripted indexing like so:
%# Symmetric solution #2:
%# ---------------------
B = cell(N);
for c = 1:N %# Loop over the columns
for r = c:N %# Loop over a subset of the rows
A = [Ax(r,c) Ay(r,c) Az(r,c)];
B{r,c} = A(:)*A;
if r ~= c %# If we're not on the main diagonal
B{c,r} = B{r,c}; %# then copy the symmetric element
end
end
end
B = cell2mat(B);
EDIT #2:
The second symmetric solution can be further sped up by moving the diagonal calculation outside of the inner loop (removing the need for a conditional statement) and overwriting A with the result A(:)*A so that we can update the symmetric cell entry B{c,r} using A instead of B{r,c} (i.e. updating one cell with the contents of another appears to carry some extra overhead):
%# Symmetric solution #3:
%# ---------------------
B = cell(N);
for c = 1:N %# Loop over the columns
A = [Ax(c,c) Ay(c,c) Az(c,c)];
B{c,c} = A(:)*A;
for r = c+1:N %# Loop over a subset of the rows
A = [Ax(r,c) Ay(r,c) Az(r,c)];
A = A(:)*A;
B{r,c} = A;
B{c,r} = A;
end
end
B = cell2mat(B);
And here are some timing results for the 3 symmetric solutions using the following sample symmetric matrices Ax, Ay, and Az:
N = 400;
Ax = tril(rand(N)); %# Lower triangular matrix
Ax = Ax+triu(Ax.',1); %'# Add transpose to fill upper triangle
Ay = tril(rand(N)); %# Lower triangular matrix
Ay = Ay+triu(Ay.',1); %'# Add transpose to fill upper triangle
Az = tril(rand(N)); %# Lower triangular matrix
Az = Az+triu(Az.',1); %'# Add transpose to fill upper triangle
%# Timing results:
%# --------------
%# Solution #1 = 0.779415 seconds
%# Solution #2 = 0.704830 seconds
%# Solution #3 = 0.325920 seconds
The big speed-up for solution 3 results primarily from updating the cell contents of B with the local variable A instead of updating one cell with the contents of another. In other words, copying cell contents with operations like B{c,r} = B{r,c}; carries more overhead than I expected.
A = cat(3, Ax, Ay, Az); % [N-by-N-by-3]
F = zeros(3, 3, N^2);
for i = 1:3,
for j = 1:3,
Ai = A(:,:,i);
Aj = A(:,:,j);
P = Ai(:) .* Aj(:);
F(i,j,:) = reshape(P, [1, 1, N^2]);
end
end
%# then we can write
B = mat2cell(F,3,3,ones(N^2,1));
B = reshape(B,N,N)';
B = cell2mat(B);