In Fortran, I have an 1D array of type real, real :: work(2*N), which represents N complex numbers. I don't have any impact of the declaration of the array.
Later I need to apply a complex conjugation on work. However, conjg(work(:)) does not work since it is of type real.
Is there a efficient way to convince the compiler to apply the conjg to my array?
The easiest approach is already in the comment by HighPerformanceMark, just multiply the elements representing the imaginary part by -1.
You can also use equivalence between a real array and a complex array. It will be just one array but viewed as both real and complex. Maybe not strictly standard conforming (not sure) but working as long as N is constant.
The equivalence is used as:
real :: work(2*N)
complex :: cwork(N)
!both work and cwork point to the same data
equivalence (work, cwork)
work = some_initial_value
!this conjugates work at the same time as cwork because they are just different names for the same array
cwork = conjg(cwork)
Use a complex variable, COMPLEX :: temp(N) and apply the conjugation to that. You can then dissect the real and complex parts and put them back into your work array by using REAL(temp) and AIMAG(temp).
Probably it is better to make your work a complex type from the outset though.
Related
Suppose I wanted to define an OCaml type of arrays of floats. This could be done as
type exampletype = Array of float. But suppose I wanted to limit this type to only include arrays of a fixed size. Would it be possible to create such a type, or in this case, would it be more effective to use an appropriately sized tuple of floats?
The OCaml array type doesn't include the size. If your arrays aren't too large you can, indeed, use tuples instead to have their sizes enforced at compile time.
It's possible to encode numbers in your OCaml types, and hence to enforce sizes at compile time. But personally I find the resulting structures to be far more trouble than they're worth. To do it nicely requires a language designed for the purpose. They're called "dependently typed" languages, so I hear. The idea is that their types can contain values (such as a specific number representing array size).
Is it possible in modern Fortran to use a vector to index a multidimensional array? That is, given, say,
integer, dimension(3) :: index = [4,6,9]
double precision, dimension(10,10,10) :: data
is there a better (more general) way to access data(4,6,9) than writing data(index(1), index(2), index(3))? It would be good not to have to hard-code the rank of the data array.
(Naively I would like to write data(index) but of course this actually means something different - subset "gathering" - requiring data to be a rank-one array itself.)
For what it's worth this is essentially the same question as multidimensional index by array of indices in JavaScript, but in Fortran instead. Unfortunately the clever answers there won't work with predefined array ranks.
No. And all the workarounds I can think of are ghastly hacks, you're better off writing a function to take data and index as arguments and spit out the element(s) you want.
You might, however, be able to use modern Fortran's capabilities for array rank remapping to do exactly the opposite, which might satisfy your wish to play fast-and-loose with array ranks.
Given the declaration
double precision, dimension(1000), target :: data
you can define a rank-3 pointer
double precision, pointer :: index_3d(:,:,:)
and then set it like this:
index_3d(1:10,1:10,1:10) => data
and hey presto, you can now use both rank-3 and rank-1 indices into data, which is close to what you want to do. I've not used this in anger yet, but a couple of simple tests haven't revealed any serious problems.
This code fragment:
real*8 a(20,5,2)
real*8 b(5)
real*8 c(20,5,2)
! define a vals ....
! define b vals ....
c(1:20, :, 1:2) = a(1:20,:,1:2)*b
won't compile because b doesn't have the same shape as a or c. I, of course, want the five values of b to match to the 5 values of the middle indices of a and c, but the Fortran compiler doesn't understand this. Is there some way to tell it what I want here? I know I could replicate b in a larger array to match the shape of a and c but that wastes memory. I could also put the whole thing in loops but for the actual code I am trying to write that will be cumbersome. Are there any other possibilities?
I think that Fortran is either preventing you shooting yourself in the foot, or, if you prefer, insisting that you be clear about what array elements you want to multiply. The expression
a(1:20,:,1:2)
is a section of 40 elements for each value of the 2nd index. It's not at all clear what the 5 elements of b are to multiply.
I suspect that you are looking for the spread function which is the one to use to 'uprank' an array. Without clarification it's kind of difficult to propose an appropriate application of spread, perhaps if you explain further you'll get a better answer than this one.
Heck, let's go ahead without clarification ...
I interpret OP's intention to be to compute the elements of c thusly:
DO ix = 1,5
c(:,ix,:) = a(:,ix,:)*b(ix)
END DO
which can be replaced by
c = a * SPREAD(SPREAD(b,dim=1,ncopies=20),dim=3,ncopies=2)
I've given this only very limited testing, the lesson is perhaps to follow #ptb's advice to stick to do loops.
Given the following code:
integer, parameter :: n = 10000
integer, parameter :: m = 3
real, dimension(:,:), allocatable :: arr
! First way
allocate(arr(n,m))
! Second way
allocate(arr(m,n))
What is the "best" way to allocate arr when there is a large difference in the two dimensions, the first way or the second way? Does it matter, or is it something that is strongly dependent on how arr will be used?
Fortran is column-major, i.e. the first dimension changes the fastest.
The optimal choice of dimensions depends on your problem:
If arr is a list of coordinates in a 3D space, and you commonly operate on these coordinates, you should probably choose the second option:
allocate(arr(m,n))
arr(:,1) = [x, y, z]
! ...
Then, you have a contiguous layout for each coordinate.
If you have three vectors with a length of n = 10000 instead (e.g. three right-hand-sides), option one would give you contiguous chunks for each vector.
In conclusion: it depends what you are trying to do.
If there is a difference, it is a minor one related to the characteristics of sequential memory access, memory fetch optimizations, and maybe caching.
Otherwise, don't worry about it. Just make the program work correctly. If somehow a few more nanoseconds of performance need to be squeezed out of it, well, there are undoubtedly better places to expend mental energy to get it.
If you are passing slices of the array to a function, then the difference matters greatly.
Is it possible in modern Fortran to use a vector to index a multidimensional array? That is, given, say,
integer, dimension(3) :: index = [4,6,9]
double precision, dimension(10,10,10) :: data
is there a better (more general) way to access data(4,6,9) than writing data(index(1), index(2), index(3))? It would be good not to have to hard-code the rank of the data array.
(Naively I would like to write data(index) but of course this actually means something different - subset "gathering" - requiring data to be a rank-one array itself.)
For what it's worth this is essentially the same question as multidimensional index by array of indices in JavaScript, but in Fortran instead. Unfortunately the clever answers there won't work with predefined array ranks.
No. And all the workarounds I can think of are ghastly hacks, you're better off writing a function to take data and index as arguments and spit out the element(s) you want.
You might, however, be able to use modern Fortran's capabilities for array rank remapping to do exactly the opposite, which might satisfy your wish to play fast-and-loose with array ranks.
Given the declaration
double precision, dimension(1000), target :: data
you can define a rank-3 pointer
double precision, pointer :: index_3d(:,:,:)
and then set it like this:
index_3d(1:10,1:10,1:10) => data
and hey presto, you can now use both rank-3 and rank-1 indices into data, which is close to what you want to do. I've not used this in anger yet, but a couple of simple tests haven't revealed any serious problems.