Subtract a vector from a matrix (row-wise) [duplicate] - loops

This question already has answers here:
Broadcast array multiplication in Fortran 90/95
(3 answers)
Closed 6 years ago.
Suppose I have a matrix A in fortran which is (n,m), and a vector B which is (1,m). I want to subtract the vector B from all rows of A without using a loop.
As of now I have only been able to do it with a loop:
PROGRAM Subtract
IMPLICIT NONE
REAL, DIMENSION(250,5) :: A
INTEGER, DIMENSION(1,5) :: B
INTEGER :: i
B(1,1) = 1
B(1,2) = 2
B(1,3) = 3
B(1,4) = 4
B(1,5) = 5
CALL RANDOM_NUMBER(A)
do i=1,250
A(i,:) = A(i,:) - B(1,:)
end do
end program
But this is very inefficient. E.g. in matlab one can do it in one line using the function reptmat.
Any suggestion on better way to do this?

You can use spread for this:
A = A - spread( B(1,:), 1, 250 )
Please note that Fortran is column-major, so B(1,:) is in general not contiguous in memory, and a temporary array is created.
[ It is in your case since you have only one column - but still worth mentioning. ]
In the same way, looping over the first index of A is inefficient.
It would probably speed things up a lot if you transposed your matrices.
Then, a loop solution might even be faster than the one using spread. (But this depends on the compiler. )

Related

Realize an array which the second dimension depends on the first argument [duplicate]

This question already has answers here:
Allocate dynamic array with interdependent dimensions
(2 answers)
Multidimensional array with different lengths
(2 answers)
Closed 1 year ago.
Suppose I have an array A[a,b]. The dimension of a is 2. When a=1, the dimension of b is 3; when a=2, the dimension of b is 6.
For example, one array A looks like
[[1,2,3]
[4,5,6,7,8,9]]
it is combined from 1*3 and 1*6. In total 9 entries, not from input.
Is there any method to define such an array in Fortran? or I need other type of data structure?
You need to provide a better description of what you want to do. With allocatable entities you can trivially achieve what you have described.
program foo
integer a, b
real, allocatable :: x(:,:)
read(*,*) a
if (a == 1 .or. a == 2) then
b = 3 * a
allocate(x(a,b))
else
stop 'Is this right?'
end if
x = 1
print *, shape(x)
end program foo

Summing along an entire array in Fortran 90 [duplicate]

This question already has an answer here:
sum only on certain dimension
(1 answer)
Closed 3 years ago.
I have an array that is of size [30,3500,7000], and would like to accumulate along the first dimension so I am left with a [3500,7000] array. I have tried the following:
Implicit None
REAL,INTENT(IN) :: datastored(30,3500,7000),emptyarray(3500,7000)
REAL,INTENT(OUT) :: summed(3500,7000)
INTEGER :: i, j, r
DO i = 1,3500
DO j = 1,7000
DO r = 1,30
summed(i,j) = emptyarray(i,j) + datastored(r,i,j)
The problem with this is that, for some reason, it will not sum along the r dimension, and the summed variable will only be the last 'r' value in datastored, basically mirroring datastored(30,i,j).
Any thoughts?
summed = sum(datastored, DIM = 1)
Check this version of the Fortran standard, item 13.7.161, which defines the instrinsic sum. The Example case (iii) is exactly what you are asking for.

Is there a quick way concat the values returned by Julia's digits() method back into it's original number? [duplicate]

This question already has answers here:
Get a number from an array of digits
(3 answers)
Closed 3 years ago.
I really like Julia's Digits function which will return an array of the individual digits that make up the input integer (See code example). My question is, once you have this array, is there an easy way to join the individual values back into the original value passed into digits?
Now, I suppose I could just take each integer's index value and multiply by it's corresponding power of 10 and modify the array in place. Then I could use sum on the array, but is there a better way to do it?
I.E
function getDigits(x)
return digits(x)
end
Julia> getDigits(1234)
4-element Array{Int64,1}:
4
3
2
1
function joinDigits(digitArray)
for i in 0:length(digitArray)-1
digitArray[i+1] = digitArray[i+1] * 10 ^ i
end
return sum(digitArray)
Julia> joinDigits([4,3,2,1])
1234
foldr((rest, msd) -> rest + 10*msd,x) is a one liner that does the same thing. It's terse, but probably not as clean as the for loop.

Extract one dimension from a multidimensional array [duplicate]

This question already has answers here:
On shape-agnostic slicing of ndarrays
(2 answers)
Closed 6 years ago.
Suppose A is multi-dimensional array (MDA) of size 3,4,5 and B is another MDA of size 3,4,5,6.
I know A(1,:,:) or B(1,:,:,:) can both extract their elements along the first dimension.
I now need to write a general program to extract the k-th dimension from a MDA without knowing its size.
For example, the MDA C has 6 dimension: 4,5,6,7,8,9 and I want an extraction C(:,:,k,:,:,:).
Sometimes, the MDA 'D' has 4 dimension: 3,4,5,6 and I want another extraction D(k,:,:,:).
That is, my problem is the numbers of colon is varying because of the dimension.
Thanks in advance
You can use string arrays to index the array dynamically:
function out = extract(arr,dim,k)
subses = repmat({':'}, [1 ndims(arr)]);
subses(dim) = num2cell(k);
out = arr(subses{:});
where dim is the dimension in which you want to select and k is an index within that dimension.
I have used a code from this answer:
https://stackoverflow.com/a/27975910/3399825

Storing multiple powers of matrices in matlab [duplicate]

This question already has answers here:
How to generate the first twenty powers of x?
(4 answers)
Closed 7 years ago.
I have 1000 matrices with dimensions 2x2.
What I now need to do is to get 30 consecutive powers of those matrices (A^2, A^3... ...A^30) and store them all.
I found a topic that suggested using bsxfun:
Vectorizing the creation of a matrix of successive powers
However, bsxfun does not work with cell arrays ("Error using bsxfun
Operands must be numeric arrays").
What can I do?
PS. A secondary question: once I have them, I want to plot 4 graphs (each corresponding to 1 of the elements of the 2x2 matrices) with 30 positions (x-axis) which will show confidence bands (16th and 84th percentile).
EDIT: Someone linked to a question that was similar to the one that I linked. From what I can understand, the question there is about a vector, not array of matrices.
Assuming your array A is 2-by-2-by-1000, here are two loops to make things work:
A = rand(2,2,1000);
K = 30;
%%
N = size(A,3);
APower = zeros(2,2,N,K);
APower(:,:,:,1) = A;
for i = 1:N
for k = 2:K
APower(:,:,i,k) = A(:,:,i)*APower(:,:,i,k-1);
%// Alternatively you could use:
%APower(:,:,i,k) = A(:,:,i)^k;
end
end
You need to replicate the matrix 30 times to do this using cellfun. For example,
a = repmat(A{1},1,30);% Select one of your A matrices
b = num2cell(1:30);
x = cellfun(#(a,b) a^b,a,b,'UniformOutput',false)
Since you need to run cellfun for each element of A another way is to use arrayfun as below.
a = A{1};
b = 1:30;
x = arrayfun(#(b) a^b,b,'UniformOutput',false)

Resources