Data statement for Matrices - arrays

I want to use the data statement to initialize matrices in Fortran. In my opinion, one advantage of using this method is that it provides a compact way of initializing matrices. However, the way I used it in the example below resulted in an error in the calculation. Both Z1 and ZZ1 should give a matrix of size 2x1 equal to [7;13] (ZZ1 = [7;13], Z1 = [10;12]). I believe that an option such as order=(/2,1/) should be used, but I have not been able to find it. Can someone help?
program test_Multiplication
implicit none
integer :: Xp1(3,1), b1(2,1), IW1_1(2,3), Z1(2,1)
integer :: XXp1(3,1), bb1(2,1), IIW1_1(2,3), ZZ1(2,1)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! with data statement !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
data Xp1(1:3,1) &
/1, &
2, &
3/
data IW1_1(1:2,1:3) &
/1, 1, 1, &
2, 2, 2/
data b1(1:2,1) &
/1, &
1/
Z1 = matmul(IW1_1,Xp1)+b1
print*, 'Z1', Z1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! without data statement !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
XXp1 = reshape( (/1, &
2, &
3 /), &
shape(XXp1), order=(/2,1/) )
IIW1_1 = reshape( (/ 1, 1, 1, &
2, 2, 2/), &
shape(IIW1_1), order=(/2,1/) )
bb1 = reshape( (/1, &
1/), &
shape(bb1), order=(/2,1/) )
ZZ1 = matmul(IIW1_1,XXp1)+bb1
print*, 'ZZ1', ZZ1
end program test_Multiplication

#user790082,
Steve has already given your answer as a comment (Fortran uses column-major order: first index changes fastest in memory). If you must use a data statement then change your initialisation of IW1_1 to
data IW1_1(1:2,1:3) /1, 2, 1, 2, 1, 2 /
(Line continuations are a considerable distraction in this instance.)

Related

Fortran structure definition, assigning values to type [duplicate]

I want to define inside a module some constants that are shared by several subroutines, but I get many error messages when I try to compile it (with the -c command):
Error: Unexpected assignment statement in MODULE
If I use the same code in a subroutine it works.
Here's the code of the module:
module rkSetup
!High order embedded Runge-Kutta formulae, by P.J.Prince and J.R.Dormand,
!Journal of Computational and Applied Mathematics, vol. 7, 1981, pages 67-75
implicit none
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(15)
integer, parameter :: s = 13 ! number of stages
integer, parameter :: p = 8 !< Order of the method
real(dp), dimension(s) :: a !< Runge-Kutta vector of nodes
real(dp), dimension(s) :: c !< Runge-Kutta vector of weigths
real(dp), dimension(s) :: d !< Runge-Kutta vector of weigths for high order
real(dp), dimension(s,s-1) :: b !< Runge-Kutta matrix
a = (/0.0_dp, 1.0_dp/18.0_dp, 1.0_dp/12.0_dp, 1.0_dp/8.0_dp, &
5.0_dp/16.0_dp,3.0_dp/8.0_dp,59.0_dp/400.0_dp,93.0_dp/200.0_dp, &
5490023248.0_dp/9719169821.0_dp, 13.0_dp/20.0_dp, &
1201146811.0_dp/1299019798.0_dp, 1.0_dp, 1.0_dp/)
c = 0.0_dp
d = 0.0_dp
d(1) = 14005451.0_dp/335480064.0_dp
d(6:) = (/-59238493.0_dp/1068277825.0_dp, &
181606767.0_dp/758867731.0_dp, &
561292985.0_dp/797845732.0_dp, &
-1041891430.0_dp/1371343529.0_dp, &
760417239.0_dp/1151165299.0_dp, &
118820643.0_dp/751138087.0_dp, &
-528747749.0_dp/2220607170.0_dp, 1.0_dp/4.0_dp/)
c(1) = 13451932.0_dp/455176623.0_dp
c(6:12) = (/-808719846.0_dp/976000145.0_dp, &
1757004468.0_dp/5645159321.0_dp, &
656045339.0_dp/265891186.0_dp, &
-3867574721.0_dp/1518517206.0_dp, &
465885868.0_dp/322736535.0_dp, &
53011238.0_dp/667516719.0_dp, 2.0_dp/45.0_dp/)
b = 0.0_dp
b(:,1) = (/0.0_dp, 1.0_dp/18.0_dp, 1.0_dp/48.0_dp, &
1.0_dp/32.0_dp, 5.0_dp/16.0_dp, 3.0_dp/80.0_dp, &
29443841.0_dp/614563906.0_dp, 16016141.0_dp/946692911.0_dp, &
39632708.0_dp/573591083.0_dp, 246121993.0_dp/1340847787.0_dp, &
-1028468189.0_dp/846180014.0_dp, 185892177.0_dp/718116043.0_dp, &
403863854.0_dp/491063109.0_dp/)
b(3,2) = 1.0_dp/16.0_dp
b(4:5,3) = (/3.0_dp/32.0_dp, -75.0_dp/64.0_dp /)
b(5:,4) = (/75.0_dp/64.0_dp,3.0_dp/16.0_dp, &
77736538.0_dp/692538347.0_dp, 61564180.0_dp/158732637.0_dp, &
-433636366.0_dp/683701615.0_dp, -37695042795.0_dp/15268766246.0_dp, &
8478235783.0_dp/508512852.0_dp, -3185094517.0_dp/667107341.0_dp, &
-5068492393.0_dp/434740067.0_dp/)
b(6:,5) = (/3.0_dp/20.0_dp, -28693883.0_dp/1125000000.0_dp, &
22789713.0_dp/633445777.0_dp, -421739975.0_dp/2616292301.0_dp, &
-309121744.0_dp/1061227803.0_dp, 1311729495.0_dp/1432422823.0_dp, &
-477755414.0_dp/1098053517.0_dp, -411421997.0_dp/543043805.0_dp/)
b(7:,6) = (/23124283.0_dp/1800000000.0_dp, &
545815736.0_dp/2771057229.0_dp,100302831.0_dp/723423059.0_dp, &
-12992083.0_dp/490766935.0_dp,-10304129995.0_dp/1701304382.0_dp, &
-703635378.0_dp/230739211.0_dp,652783627.0_dp/914296604.0_dp/)
b(8:,7) = (/-180193667.0_dp/1043307555.0_dp, &
790204164.0_dp/839813087.0_dp, 6005943493.0_dp/2108947869.0_dp, &
-48777925059.0_dp/3047939560.0_dp, 5731566787.0_dp/1027545527.0_dp, &
11173962825.0_dp/925320556.0_dp/)
b(9:,8) = (/800635310.0_dp/3783071287.0_dp, &
393006217.0_dp/1396673457.0_dp, 15336726248.0_dp/1032824649.0_dp, &
5232866602.0_dp/850066563.0_dp, -13158990841.0_dp/6184727034.0_dp /)
b(10:,9) = (/123872331.0_dp/1001029789.0_dp, &
-45442868181.0_dp/3398467696.0_dp,-4093664535.0_dp/808688257.0_dp, &
3936647629.0_dp/1978049680.0_dp/)
b(11:,10) = (/3065993473.0_dp/597172653.0_dp, &
3962137247.0_dp/1805957418.0_dp, -160528059.0_dp/685178525.0_dp/)
b(12:,11) = (/65686358.0_dp/487910083.0_dp, &
248638103.0_dp/1413531060.0_dp/)
end module rkSetup
How can I solve this?
As per Table 2.2 in the Fortran 2008 Standard, you may not place executable statements into a module directly.
If you want to initialize this data, either (a) do it during declaration, or (b) add a dedicated subroutine that you can call to do the initialization.
(a)
real(dp), dimension(s),parameter :: a = &
(/0.0_dp, 1.0_dp/18.0_dp, 1.0_dp/12.0_dp, 1.0_dp/8.0_dp, &
5.0_dp/16.0_dp,3.0_dp/8.0_dp,59.0_dp/400.0_dp,93.0_dp/200.0_dp, &
5490023248.0_dp/9719169821.0_dp, 13.0_dp/20.0_dp, &
1201146811.0_dp/1299019798.0_dp, 1.0_dp, 1.0_dp/)
(b)
module rkSetup
!High order embedded Runge-Kutta formulae, by P.J.Prince and J.R.Dormand,
!Journal of Computational and Applied Mathematics, vol. 7, 1981, pages 67-75
implicit none
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(15)
!...
contains
subroutine init()
a = (/0.0_dp, 1.0_dp/18.0_dp, 1.0_dp/12.0_dp, 1.0_dp/8.0_dp, &
5.0_dp/16.0_dp,3.0_dp/8.0_dp,59.0_dp/400.0_dp,93.0_dp/200.0_dp, &
5490023248.0_dp/9719169821.0_dp, 13.0_dp/20.0_dp, &
1201146811.0_dp/1299019798.0_dp, 1.0_dp, 1.0_dp/)
!....
end subroutine
end module
Alexander Vogt is correct that you can define them in an initialization routine. However, if a,b,c,d are constants, the most efficient thing to do is define them as parameters. Here is an example of two ways to do this:
module params
implicit none
integer, parameter :: s = 5
! -- Initialization method 1
real, parameter :: a(s) = (/ 1.2, 3.4, &
5.6, 7.8, 9.0 /)
! -- Initialization method 2
real :: b(s)
parameter( b = (/ 1.2, 3.4, &
5.6, 7.8, 9.0 /) )
end module params
program main
use params
write(*,'(a,5f6.2)') 'a is: ', a
write(*,'(a,5f6.2)') 'b is: ', b
end program main
If you wish to set a large parameter array with more than one dimension, consider using reshape.

Fortran filter a two dimensional array

the two dimensional array I am talking about holds values such as
1 2326
1 2331
1 2328
1 2323
2 2404
2 2398
2 2401
2 2403
3 2408
3 2401
3 2408
3 2401
I want to operate on all the elements that have the same id at a time, like:
program filter_2d
integer(1000, 1000) :: my_array
integer :: id
...
print *, any(my_array(1, :), id)
end program filter_2d
any just returns true. How can i filter the rows that have (i, 1) == 2 for example?
and as a side question, should I be using arrays or just go with a custom type that has an id integer and an array to hold the rest of the values (the array is much larger irl, like 10000x10000).
The simplest way to go is a loop and an if statement:
program filter_2d
integer :: my_array(3, 3)
integer, parameter :: id = 2
my_array = reshape( [ 1, 2, 2, 2, 3, 4, 5, 6, 7 ], [3,3] )
do i=1,size(my_array,1)
if ( my_array(i,1) == id ) print *, my_array(i, :)
enddo ! i
end program filter_2d
Especially if the dimensions become larger I would use arrays instead of derived types. An OOP approach always has a computational overhead that needs to be considered.
As a rule of thumb I always use structures as simple as possible, and only choose derived types if I see no other option. This, of course, only applies to the numerics part of the code. For the organization of simulations including I/O and pre-processing it is usually beneficial to adopt an OOP paradigm.
You can also set up an index set and operate on that:
program filter_2d
integer :: my_array(3, 3)
integer, parameter :: id = 2
integer :: idx( size(my_array, 1) )
integer :: nMatch
my_array = reshape( [ 1, 2, 2, 2, 3, 4, 5, 6, 7 ], [3,3] )
nMatch = 0
do i=1,size(my_array,1)
if ( my_array(i,1) == id ) then
nMatch = nMatch + 1
idx(nMatch) = i
endif
enddo ! i
print *, my_array(idx(:nMatch),:)
end program filter_2d
This can probably be written a more elegantly, but you get the idea...

how i can eliminate the row which equal those if conditions

function prealloc()
situation=zeros(Int64,3^5,5);
i=1;
for north=0:2, south=0:2, east=0:2, west=0:2, current=0:2
situation[i,:]=[north, south, east, west, current]
if situation[i,:]=[2, 2, 2, 2, 2]
elseif situation[i,:]=[2, 2, 2, 2, 1]
elseif situation[i,:]=[2, 2, 2, 2, 0]`enter code here`
end
i+=1
end
situation
end
How can I eliminate the row which equal those if conditions from the array which called situation
First things first: the code in your question doesn't run (for several reasons). When posting code in questions, it is good form to put it in a "working example" form, where users can copy and paste it into their editor of choice and it will work without the user having to make educated guesses as to what you are actually trying to do. This is probably one reason the question has received down-votes.
With that out of the way, there are two approaches to accomplish what you are trying to do:
1) Construct your matrix without the indicated rows in the first step. Then you don't need to worry about "deleting the rows" later on. For situations as simple as the one in the question, you could just do something like this:
function prealloc()
x = zeros(Int, 3^5 - 3, 5)
i = 1
for n=0:2, s=0:2, ea=0:2, w=0:2, cur=0:2
if !([n, s, ea, w, cur] == [2, 2, 2, 2, 2] || [n, s, ea, w, cur] == [2, 2, 2, 2, 1] || [n, s, ea, w, cur] == [2, 2, 2, 2, 0])
x[i, :] = [n, s, ea, w, cur]
i += 1
end
end
return(x)
end
Notice I'm using Int, not Int64. This will not affect performance, and it means your code will run on both 32-bit and 64-bit architectures.
Another style tip. Don't use semi-colons to end lines. This is a Matlab quirk, and it is not needed in Julia.
2) As other users have suggested, you could construct the entire matrix (including the undesirable rows), and then remove them at a later point. Of course, this necessitates re-allocating the entire matrix, and so is somewhat inefficient (note, you can remove elements of vectors in place, i.e. without re-allocation, but not any arrays of dimension 2 or greater). In this case, to encourage code re-use, it makes sense to break the routine down into three separate functions. First, we allocate the entire matrix:
function prealloc1()
x = zeros(Int64,3^5,5)
i = 1
for north=0:2, south=0:2, east=0:2, west=0:2, current=0:2
x[i,:]=[north, south, east, west, current]
i += 1
end
return(x)
end
Next, we obtain a vector of indices that we wish to remove. We do this as its own step because we only want to re-allocate the matrix once, rather than re-allocating every time we find a new row we want to delete. For your situation, you could use a function like this:
function findCondition(x::Matrix{Int})
inds = Array(Int, 0)
for i = 1:size(x, 1)
if x[i, :] == [2 2 2 2 2]
push!(inds, i)
elseif x[i, :] == [2 2 2 2 1]
push!(inds, i)
elseif x[i, :] == [2 2 2 2 0]
push!(inds, i)
end
end
return(inds)
end
Notice that in my comparison statements in this function I use [2 2 2 2 2] instead of [2, 2, 2, 2, 2]. This is because the first construct is a 2-dimensional array (type Matrix) while the second is 1-dimensional (type Vector). Since x[i, :] is of type Matrix, the difference is important.
Finally, we need to re-allocate the matrix without the offending rows. As user #Matt B. suggests, this can be done with the following one-liner function:
removeIndices(x::Matrix{Int}, inds::Vector{Int}) = x[setdiff(IntSet(1:size(x, 1)), IntSet(inds)), :]
Note, applying setdiff to IntSet here is fast because by construction inds will already be sorted in ascending order.
You cannot just delete a row in Julia, the only way to do it, is to create a copy of the array without the row you want to delete. And I think that's not internally implemented and it's intentional.
So you will have to do to it manually, something like this will create a copy of situation without the row i (which is not the same as saying that it will delete row i).
situation = vcat(situation[1:i-1,:],situation[i+1:end,:])
also, this will actually change the dimensions of situation in each iteration, so be careful with that...
Also2, your loop will finish in a bounds error since eventually it will be off limits of your array, maybe you could write something like this to end your loop.
if i = length(situation)
break
else
i += 1
end
Ultimately, you can make a function delrow and call it from within your loop:
function delrow(array,row)
return vcat(array[1:row-1,:],array[row+1:end,:])
end
then call situation = delrow(situation,i)

Fortran, how to merge(unit) 2 arrays into new 1 which contents unique elements from previous

I have to compare two arrays, and get a new one as a result of comparison. Which has uncommon elements for two arrays at the same time.(prefer using reg. programming)
program arrays
implicit none
integer, parameter :: m = 5
integer i, j
integer :: a(1:5)
integer :: b(1:5)
!integer :: g(!) - new array
a=[1,2,33,44,5]
b=[3,2,44,7,33]
print *,'Check for common numbers'
forall ( i = 1:m, j =1:m, a(i) /= b(j)) ! think i need something like this
end forall
!result should be g=[1,5,3,7]
end program
I tried other method but it has mistakes in logic and get other results(think dont need it)
program try
implicit none
integer :: example(12) ! The input
integer :: res(size(example)) ! The output
integer :: k ! The number of unique elements
integer :: i, j
integer :: a(6)
integer :: b(6)
integer :: c(12)
a = [3,6,1,6,-1,2]
b = [4,5,1,-7,2,1]
forall(i=1:6)
example(i) = a(i)
end forall
forall(i=7:12)
example(i) = b(i-6)
end forall ! merge 2 arrays into 1, for searching unique combinations
k = 1
res(1) = example(1)
outer: do i=2,size(example)
do j=1,k
if (res(j) == example(i)) then
! Found a match so start looking again
cycle outer
end if
end do
! No match found so add it to the output
k = k + 1
res(k) = example(i)
end do outer
print *, example ! get 3,6,1,-1, 2, 4, 5, -7(Of course!) except 3, 6, -1, 4, 5, -7
write(*,advance='no',fmt='(a,i0,a)') 'Unique list has ',k,' elements: '
write(*,*) res(1:k)
end program try
This expression
rslt = [ PACK(arr1,ALL(SPREAD(arr1,1,SIZE(arr2))/=SPREAD(arr2,2,SIZE(arr1)),dim=1)), &
PACK(arr2,ALL(SPREAD(arr1,1,SIZE(arr2))/=SPREAD(arr2,2,SIZE(arr1)),dim=2)) ]
will, given two rank-1 integer arrays called arr1 and arr2, assign to rslt the union of the differences arr1\arr2 and arr2\arr1. Note:
Not an explicit loop in sight, but don't be surprised if the compiler generates a lot.
This expression SPREAD(arr1,1,SIZE(arr2))/=SPREAD(arr2,2,SIZE(arr1)) is duplicated so probably computed twice; for production code you'd probably want to do something about that.
That same expression consumes memory, so you'd definitely not want to duplicate it.
Sorting not required.
Me, I'd use loops.

Matrix Math with VBA (System of Linear Equations)

I'm looking for a little help performing some matrix mathematics in Excel's VBA. I've read a ton of replies that suggest using the Excel worksheet but I'm hoping to solve this within the VBA code itself.
Although my application is much larger, let's say I have a system of linear equations that I need to solve:
x1 + x2 = 8
2*x1 + 4*x2 = 100
This can be solved with the simple matrix formula A*x = B or x = A^(-1) * B where,
A = [1, 1; 2, 4]
B = [8; 100]
If you solve this, you'll find x1 = -34 and x2 = 42. In terms of the matrix, then:
X = [-34; 42]
Using Excel's worksheets alongside its MMULT and MINVERSE functions makes this easy and I've gotten it to work just fine. My problem is I'm needing to do this calculation inside a VBA function. Here's what I'm trying:
Dim A(0 To 1, 0 To 1) As Single
Dim B(0 To 0, 0 To 1) As Single
Dim X(0 To 0, 0 To 1) As Single
A(0, 0) = 1
A(1, 0) = 1
A(0, 1) = 2
A(1, 1) = 4
B(0, 0) = 8
B(0, 1) = 100
X = Application.WorksheetFunction.MMult(Application.WorksheetFunction.MInverse(A), B)
Unfortunately, the last line yields a "Compile error: can't assign to array" message. I think it's because I have to specify each element of the array one at a time, but the worksheet functions are array functions.
How do I fix this?
Two things:
The same rule applies as in actual mathematics: B must be a vertical array for matrix multiplication to be possible in your case. Declare it as
Dim B(0 To 1, 0 To 0) As Single
and initialize it accordingly. Also, just declare
Dim X As Variant
since the MMult returns a Variant array. This is what was causing your original error.

Resources