Fortran Array Splice Initialization - arrays

I'm trying to initialize an array with equal spacing between 0 and 1 in fortran.
My code is :
program test
double precision :: h
double precision, dimension(:), allocatable :: x
h = 1./11
if(.not. allocated(x)) allocate(x(10))
x(1:10) = [h:(1-h):h] (*)
end program
The error I am given is "The highest data type rank permitted is INTEGER(KIND=8)" at the stared line.
I've tried to change it with
x(1:10) = h:(1-h):h
x = h:(1-h):h
x(1:10) = (/(h:(1-h):h)/)
and various other forms with no luck.

The syntax you're using is not valid Fortran and implied DO loops can't have non-integer bounds. You want something like this:
x = h * real([(i,i=1,size(x))],kind(h))
For more information, look up "array constructors" in the standard or a textbook.
Don't use (1:10) on the left side - see https://software.intel.com/en-us/blogs/2008/03/31/doctor-it-hurts-when-i-do-this

This expression
[h:(1-h):h]
is, from a Fortran point of view, broken. It looks a bit like an array slice, but that would require integers, not reals, and ( and ) rather than the [ and ]. And it looks a bit like an array constructor, for which [ and ] are correct, but h:(1-h):h isn't.
Try this
x = REAL([(ix,ix=1,10)],real64)/11
(having declared ix to be an integer). The expression (ix,ix=1,10) is an implied do-loop and, inside the [ and ] produces an array with integers from 1 to 10. I trust the rest is obvious.
Incidentally, since the lhs of my suggested replacement is the whole of x you don't actually need to explicitly allocate it, Fortran will automatically do that for you. This is one of the differences between a whole array section, such as your x(1:10) and the whole array, x.
And if that doesn't produce the results you want let us know.

Related

Remove all the rows after an index value from an array in Fortran

I want an array to remove all the rows after a certain index value from an array in Fortran. That means that if the size of the array initially is p, it should become q, where q is the index after which everything is to be removed.
Here is the relevant bit of code:
real(8), allocatable :: circlesx(:),circlesy(:)
allocate(circlesx(n**2-n))
allocate(circlesy(n**2-n))
do i=1,n-1
do j=i+1,n
call intersect2circles(stlo(i),stla(i),distance(i),stlo(j),stla(j),distance(j),ax,ay,bx,by,flag)
if (flag==0) then
circlesx(k)=ax
circlesy(k)=ay
circlesx(k+1)=bx
circlesy(k+1)=by
k=k+2
endif
enddo
enddo
The flag basically checks if two circles intersect or not. So if there is no intersection, no values are assigned to the arrays circlesx and circlesy. The size of the arrays which I am allocating at first is the maximum number of points of intersection of n circles = n^2-n. I get a segmentation fault if I don't allocate them.
Reshape also didn't work, although I might have done something wrong there. This gave an unclassifiable statement error:-
reshape(circlesx,[ n**2-n-1 ])
I want the size of the circles arrays to change to k-2 after the loops are done
So what I need is, if n=2, so circlesx and circlesy have a size of 2, then,
circlesx=[0,0]
.
.
some calculations
.
.
circlesx=[1.2,0] ! only one value has been allocated
.
.
reshape the array accordingly
.
.
circlesx=[1.2]
Is there any way to do this in Fortran? I am using an f90 file extension and using gfortran v7.3.0
Questions around here about dynamic resizing of an array generally care about enlargening the array. That is the harder problem.1
However, the fundamental considerations are much the same. Consider
integer, allocatable :: arr(:)
allocate(arr(3))
arr = [1, 2, 3]
end
With intrinsic assignment we see from elsewhere that we could just write
integer, allocatable :: arr(:)
arr = [1, 2, 3]
end
and have arr allocated to the correct shape as part of the assignment.
We've seen this to: enlarge an array
arr = [arr, 4]
remove "bad values":
arr = PACK(arr, arr>1.and.arr<4)
Selecting just the first few elements is as simple as
arr = arr(:q)
The days where compilers require special flags to compile such code correct are slowly passing, but do (especially if using an old version) check your compiler documentation for how to ensure automatic allocation happens on intrinsic assignment.
1 Even in the days without dynamic memory allocation, one handled "shorter" arrays simply. Take a static-sized array as large as you'll ever need and do some bookkeeping around how many elements are used. In modern code you may see such artefacts when using old libraries.

How to define and access array in GNUplot?

This is rather easy question or maybe too easy question. But i tried to find the way to done these already and could not find even in GNUplot document. Might be my mistake or misunderstood something about array concept in GNUplot. My question is How to define and access array in GNUplot?
Please just provide easy example of array declaration, assign value of array over loop. i think that's enough and i think this will be useful for other people too.
If you are using Gnuplot 5.1 or superior and need a 1-d array, you simply define the array with size N, remembering that the indices go from 1 to N:
gnuplot> array A[3] #Array definition
gnuplot> A[1]=2
gnuplot> A[3]=4
gnuplot> print A[1]
2
gnuplot> print A #Print the array, with empty A[2]
[2,,4]
If you need more than one dimension or are using previous versions of Gnuplot, you can do the following:
Since there are no vector variables in previous versions of Gnuplot, two functions can be defined to get and set values to a behind the scenes variable whose name include the index. The functions are:
aGet(name, i) = value(sprintf("_%s_%i", name, i))
aSet(name, i, value) = sprintf("_%s_%i = %.16e", name, i, value)
To assign and retrieve values on the array A you do
eval aSet("A",2,3)
print aGet("A",2)
What these functions do is to access a variable called _A_2.
You can build similar function to work with matrices:
mGet(name, i, j) = value(sprintf("_%s_%i_%i", name, i, j))
mSet(name, i, j, value) = sprintf("_%s_%i_%i = %.16e", name, i, j, value)
(This answer will be obsolete with the next stable gnuplot release, as the 5.1 development tree now has native support for array variables.)
(The "splot" command in gnuplot uses the keyword "array" to define the size of NxM matrix that contains function values for a 3D plot. Nothing to do with array variables.)
Arrays like what a programmer knows from C, Pascal, Python, etc. do not exist in gnuplot today (gp5.0). They might get implemented one day, because they'd be highly useful to plot a family of curves with arbitrary (e.g. fitted) parameters.
If you are desperate about arrays in gnuplot, you can (ab)use the word() function (and other string functions) to achieve a somewhat limited substitute. It's also a bit cumbersome:
array = ""
f(a,x) = a*x
do for [i=1:5] {array = array.sprintf(" %.3f",i+rand(0)) }
print "array = ".array
set xr [0:]; set yr [0:30]
plot for [i=1:5] f(word(array,i),x) title word(array,i)." x"
This example writes a set of random numbers to a string variable named "array", and afterwards uses it to plot five linear functions that use the numbers in "array" for their slope. It's handy here that gnuplot autopromotes strings to numerics if used e.g. in an equation.
Inspired by #Karl 's answer, it looks even more like an array when putting the word function into another function:
array(n) = word("1 2 3 4 5 6 7 8 9", n)
print array(3)
This prints 3. So the indexing is one-based.
"Multiply" the array by 2:
print (b="", sum[i=1:9](b=b.(array(i)*2)." ", 0), b)
This prints 2 4 6 8 10 12 14 16 18. Here the sum function is (ab)used to loop over the array and its result is ignored.
And here is shorter, through less generic variant of #bmello's answer:
A_1=1.1; A_2=2.2; A_3=3.3
A(i) = value("A_".i)
print A(3)
For me it feels more intuitiv. The underscore _ can be seen simply as the set function. Also it is not limited to integer indices. Strings are also possible which give some dictionary-like behaviour.

Fortran equivalent to matlab find - application to slicing matrix without memory duplication

I use the command find quite a lot in matlab, and I wonder how to translate this smartly in fortran to extract a slice of an array. In matlab you can slice with either logicals or indexes, but in fortran you need indexes to slice. I'm aware of the intrinsic subroutines pack et al, but have never used them. Also, since I'm dealing with big matrices, I would like to avoid duplicating memory. I want the sliced matrix to be manipulated within a subroutine. I've read somewhere that slices of array were not duplicated. I don't know how this the slicing in done in matlab though. I'm puzzled also because in matlab some allocations are transparent to you.
I'd like to know how to reproduce the examples below, and make sure I'm not duplicating stuff in memory and that it's actually elegant to do so. Otherwise, I would forget about slicing and just send the whole matrix(since it's by reference) and loop through an index array I...
Matlab example 1: simply reproducing find
v=[1 2 3 4];
I=find(v==3);
Matlab example 2:
m=rand(4,4);
bools=logical([ 1 0 0 1]);
I=find(bools==1);
% which I could also do like:
I=1:size(m,1);
I=I(bools);
for i=1:length(I)
% here dealing with m(I(i)),:) and do some computation
% etc.
Example 3: just call a subroutine on m(I,:) , but using directly booleans for slicing
foo( m(bools, :) , arg2, arg3 )
In advance thank you for your help!
Fortran doesn't have an exact match for Matlab's find but you can generally use either where or forall, and sometimes both, to replace its functionality.
For example, given an array v such as you have in your first example, the Fortran statement
where (v==3) do_stuff
will operate only on the elements of v which are equal to 3. This doesn't get you the indices of those elements as find does, but much of the use of find is for selecting elements for having stuff done to them, and in most of those cases the where construct is applicable.
Given v as before, and an index array ix which, in Fortran, is an array of logicals like this:
[.true., .false., .false., .true.]
you can use ix, so long as it is the same shape as v, in masked array assignments such as
where (ix) v = some_value
ix doesn't have to be an array of logicals, it can be an array of any type, if it were an array of reals you might have an expression such as
where (ix>=0.0) v = some_value
I don't think that any of the current Fortran compilers make copies of arrays to implement where constructs. I'll leave you to read about the forall construct.
Don't forget, either, that you can use arrays as indices for Fortran arrays, so the expression
v([1,3]) = 0
sets elements 1 and 3 of v to 0. You can, of course, use multiple array indices if your array has rank greater than 1.
When you start using this sort of indexing to pass non-contiguous sections of an array to a sub-program, then you have to start worrying about copying into temporary arrays (if that's the sort of thing that you want to worry about). I believe that compilers may make temporary copies if you do something like
call my_subroutine(array(1:12:3, 2:12:4))
to enable the subroutine, which does not know the indices of the elements of the array section at run-time, to operate on what it 'sees' as a contiguous array.
You can use "pack" with an implied do loop:
I = pack([(j,j=1,size(v))],v==3)
Bellow, in FORTRAN CODE, is an example of a subroutine that makes the equivalent of find in matlab or scilab. In the examples below, we want to (a) find the position of the vector where the vector is equal to 22 (b) find the positions of even numbers in a vector
PROGRAM Principal
REAL*8 A(8)
INTEGER n, npos, pos(8)
n=8
A = (/ 19, 20, 21, 22, 23, 24, 25, 26 /)
! Find the positions of vector A that is equal to 22
CALL FindInVector(n,A==22,npos,pos)
WRITE(*,*) pos(1:npos)
! Find the positions of vector A that contains even numbers
CALL FindInVector(n,ABS(A/2.d0-INT(A/2.d0))<1.d-2,npos,pos)
WRITE(*,*) pos(1:npos)
END PROGRAM Principal
!________________________________________________________________
! Subroutine that find positions of a vector of logicals TF (True or False). The first npos elements contains the response.
SUBROUTINE FindInVector(n,TF,npos,pos)
! Inlet variables
INTEGER,INTENT(IN):: n ! Dimension of logical vector
LOGICAL,INTENT(IN):: TF(n) ! Logical vector (True or False)
! Outlet variables
INTEGER npos ! number of "true" conditions
INTEGER pos(n) ! position of "true" conditions
! Internal variables
INTEGER i ! counter
INTEGER v(n) ! vector of all positions
pos = 0 ! Initialize pos
FORALL(i=1:n) v(i) = i ! Enumerate all positions
npos = COUNT(TF) ! Count the elements of TF that are .True.
pos(1:npos)= pack(v, TF) ! With Pack function, verify position of true conditions
ENDSUBROUTINE FindInVector
I think a simpler version is possible, see the subroutine below. The example shows how to find the values smaller than 0.1 in array x.
program test
real, dimension(:), allocatable :: x
integer, dimension(:), allocatable :: zeros
x=[1.,2.,3.,4.,0.,5.,6.,7.,0.,8.]
call find_in_array(x<0.01,zeros)
write(*,*)zeros
contains
subroutine find_in_array(TF,res)
! Dummy arguments
logical, dimension(:), intent(in) :: TF ! logical array
integer, dimension(:), allocatable, intent(out) :: res ! positions of true
! elements
! Local arrays
integer, dimension(:), allocatable :: pos
pos=[(i,i=1,size(TF))]
!pos=[1:size(TF)] ! valid on Intel compiler
res=pack(pos,TF)
end subroutine find_in_array
end program test

Matlab array of struct : Fast assignment

Is there any way to "vector" assign an array of struct.
Currently I can
edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A.
for i=1:1000000; edges(i).weight=1.0; end;
But that is slow, I want to do something more like
edges(:).weight=[rand(1000000,1)]; //with or without the square brackets.
Any ideas/suggestions to vectorize this assignment, so that it will be faster.
Thanks in advance.
This is much faster than deal or a loop (at least on my system):
N=10000;
edge(N) = struct('weight',1.0); % initialize the array
values = rand(1,N); % set the values as a vector
W = mat2cell(values, 1,ones(1,N)); % convert values to a cell
[edge(:).weight] = W{:};
Using curly braces on the right gives a comma separated value list of all the values in W (i.e. N outputs) and using square braces on the right assigns those N outputs to the N values in edge(:).weight.
You can try using the Matlab function deal, but I found it requires to tweak the input a little (using this question: In Matlab, for a multiple input function, how to use a single input as multiple inputs?), maybe there is something simpler.
n=100000;
edges(n)=struct('weight',1.0);
m=mat2cell(rand(n,1),ones(n,1),1);
[edges(:).weight]=deal(m{:});
Also I found that this is not nearly as fast as the for loop on my computer (~0.35s for deal versus ~0.05s for the loop) presumably because of the call to mat2cell. The difference in speed is reduced if you use this more than once but it stays in favor of the for loop.
You could simply write:
edges = struct('weight', num2cell(rand(1000000,1)));
Is there something requiring you to particularly use a struct in this way?
Consider replacing your array of structs with simply a separate array for each member of the struct.
weights = rand(1, 1000);
If you have a struct member which is an array, you can make an extra dimension:
matrices = rand(3, 3, 1000);
If you just want to keep things neat, you could put these arrays into a struct:
edges.weights = weights;
edges.matrices = matrices;
But if you need to keep an array of structs, I think you can do
[edges.weight] = rand(1, 1000);
The reason that the structs in your example don't get initialized properly is that the syntax you're using only addresses the very last element in the struct array. For a nonexistent array, the rest of them get implicitly filled in with structs that have the default value [] in all their fields.
To make this behavior clear, try doing a short array with clear edges; edges(1:3) = struct('weight',1.0) and looking at each of edges(1), edges(2), and edges(3). The edges(3) element has 1.0 in its weight like you want; the others have [].
The syntax for efficiently initializing an array of structs is one of these.
% Using repmat and full assignment
edges = repmat(struct('weight', 1.0), [1 1000]);
% Using indexing
% NOTE: Only correct if variable is uninitialized!!!
edges(1:1000) = struct('weight', 1.0); % QUESTIONABLE
Note the 1:1000 instead of just 1000 when indexing in to the uninitialized edges array.
There's a problem with the edges(1:1000) form: if edges is already initialized, this syntax will just update the values of selected elements. If edges has more than 1000 elements, the others will be left unchanged, and your code will be buggy. Or if edges is a different type, you could get an error or weird behavior depending on its existing datatype. To be safe, you need to do clear edges before initializing using the indexing syntax. So it's better to just do full assignment with the repmat form.
BUT: Regardless of how you initialize it, an array-of-structs like this is always going to be inherently slow to work with for larger data sets. You can't do real "vectorized" operations on it because your primitive arrays are all broken up in to separate mxArrays inside each struct element. That includes the field assignment in your question – it is not possible to vectorize that. Instead, you should switch a struct-of-arrays like Brian L's answer suggests.
You can use a reverse struct and then do all operations without any errors
like this
x.E(1)=1;
x.E(2)=3;
x.E(2)=8;
x.E(3)=5;
and then the operation like the following
x.E
ans =
3 8 5
or like this
x.E(1:2)=2
x =
E: [2 2 5]
or maybe this
x.E(1:3)=[2,3,4]*5
x =
E: [10 15 20]
It is really faster than for_loop and you do not need other big functions to slow your program.

Function Returning an array in Fortran

It is my understanding that you can return an array from a function in Fortran, but for some reason my code is only returning the first value in the array I am asking it to return. This is the function:
function polynomialMult(npts,x,y)
integer npts
double precision x(npts), results(npts + 1), y(npts,npts)
polynomialMult = x(1:npts) + 1
end function
and this is where I'm calling it
C(1:numPoints) = polynomialMult(numPoints,x,f)
print *, C(1:numPoints)`
right now it doesn't do anything useful because I am trying to understand the syntax before I write the logic. I saw some stuff about specifying types for functions, but when I write
integer function polynomialMult(npts,x,y)
or whatever I get a compilation error.
To define a function which returns an array include the function declaration inside the function, like this:
function polynomialMult(npts,x,y)
integer npts
double precision x(npts), results(npts + 1), y(npts,npts)
! Change the next line to whatever you want
double precision, dimension(npts) :: polynomialMult
polynomialMult = x(1:npts) + 1
end function
Your declaration
integer function polynomialMult(npts,x,y)
declares that the function returns an integer. An integer, not an array of integers. I don't think the standard allows function declarations such as:
integer, dimension(10) function polynomialMult(npts,x,y)
but I could be wrong. I always use the form I showed you above.
If you have an up to date Fortran compiler you can do clever things such as return an allocated array. And I suggest you figure out array syntax. For example, your statement:
polynomialMult = x(1:npts) + 1
could more concisely be written:
polynomialMult = x + 1
since Fortran will map the scalar addition to all elements of the array x which you have declared to have only npts elements.
Passing the sizes of arrays into subroutines is very FORTRAN77 and almost always unnecessary now. Generally you either want to operate on every element in an array (as in the array syntax example) or you should let the subprogram figure out the size of the array it is dealing with.
I agree with the previous responder that the following works:
polynomialMult = x + 1
However, without knowing that polynomialMult and x are arrays, one might assume it is a scalar operation. I prefer to be obvious and do it this way:
polynomialMult(:) = x(:) + 1
I have even insisted that the coders in my group do it this way. I don't like to work hard to understand someone's code--I want it to be obvious what they are doing.

Resources