Extract integers from string in Fortran - arrays

I'm using Fortran 90. I have a string declared as CHARACTER(20) :: Folds, which is assigned its value from a command line argument that looks like x:y:z where x, y, and z are all integers. I then need to pick out the numbers out of that string and to assign them to appropriate variables. This is how I tried doing it:
i=1
do j=1, LEN_TRIM(folds)
temp_fold=''
if (folds(j).neqv.':') then
temp_fold(j)=folds(j)
elseif (i.eq.1) then
read(temp_fold,*) FoldX
i=i+1
elseif (i.eq.2) then
read(temp_fold,*) FoldY
i=i+1
else
read(temp_fold,*) FoldZ
endif
enddo
When I compile this I get errors:
unfolder.f90(222): error #6410: This name has not been declared as an array or a function. [FOLDS]
[stud2#feynman vec2ascii]$ if (folds(j).neqv.':') then
syntax error near unexpected token `j'
[stud2#feynman vec2ascii]$ --------^
unfolder.f90(223): error #6410: This name has not been declared as an array or a function. [TEMP_FOLD]
[stud2#feynman vec2ascii]$ temp_fold(j)=folds(j)
syntax error near unexpected token `j'
How can I extract those numbers?

You can use the index intrinsic function to locate the position in the string of the first colon, say i. Then use an internal read to read the integer xfrom the preceding sub-string: read (string (1:i-1), *) x. Then apply this procedure to the sub-string starting at i+1 to obtain y. Repeat for z.
P.S. Are your error messages from bash rather than a Fortran compiler?

With folds a character variable, to access a substring one needs a (.:.). That is, to access the single character with index j: folds(j:j).
Without this, the compiler thinks that folds must be either an array (which it isn't) or a function (which isn't what you want). This is what is meant by:
This name has not been declared as an array or a function.
But in terms of then solving your problem, I second the answer given by #M.S.B. as it is more elegant. Further, with the loop as it is (with the (j:j) correction in both folds and temp_fold) you're relying on each x, y, and z being single digit integers. This other answer is much more general.

Related

Error in Matlab Coder: Index exceeds array dimensions

I am trying to convert .m script to C++ using MATLAB Coder.
function P=r_p(1,var1,var3)
p=[[3,7]
[10,15]
[6,19]
[21,19]
[43,11]
[969,2]
[113,9]
[43,59]
[21,15]
[6,15]
[10,18]
[3,15]];
tmax=sum(p(:,1))+41;
coder.varsize('x');
x=ones(9,11).*[0:10:100]; % getting error in this line: [9x11]~=[1x11]. Since size of x is varying in for loop, so i should tell coder that it is variable size, So I used Varsize
for t=11:tmax
a1=(rand-0.5)*1;
a9=(rand-0.5)*1.25;
a2=(rand-0.5)*1.5;
a8=(rand-0.5)*1.75;
a3=(rand-0.5)*2.0;
a7=(rand-0.5)*2.25;
a4=(rand-0.5)*2.5;
a6=(rand-0.5)*2.75;
a5=(rand-0.5)*3;
x(1,t+1)=x(1,t)+a1;
if x(1,t+1)<(100-var1) || x(1,t+1)>(100+var1) % loop 1: x(1,11)+a1 value is is writing to x(1,12) So coder gives error "Index exceeds array dimensions. Index value 12 exceeds valid range [1-11] of array x".
x(1,t+1)=x(1,t); % In matlab it works fine, but coder throws error.
end
end
My question is Let say loop 1,
x(1,12)= x(1,11)+a1 In matlab this assignment works fine, but when converting it is throwing error " Index exceeds array dimensions. Index value 12 exceeds valid range [1-11] of array x" As I declared x as variable size coder should assign x(1,11)+a1 value to x(1,12) but it is not doing, instead throwing error. Why?
Since t is looping for 1289, if I specify bounds for x like
coder.varsize('x',[1290,1290],[0,0]) then Coder gives error in other part of the code i.e dimensions doesn't match. Ofcourse it should because dimension of x doesn't match with [ones(12,9)p(1,2)/9;(P_1s+var3/100P_1s.*randn(size(P_1s))/2)/9;zeros(30,9)].
is declaring x as variable size is correct step or not? if yes then what should be the work around for "index exceeds array dimensions error"
Please Let me know, what am I missing to convert it to C++ code
MATLAB Coder doesn't support 2 things you're using here: implicit expansion and growing arrays by assigning past the end of a dimension.
For implicit expansion, you can use:
x=bsxfun(#times,ones(9,11),[0:10:100]);
Assigning past the end of an array in MATLAB will grow the array. That's an error in Coder. There are 2 ways to overcome this:
Allocate your array to have the right number of elements up front
Use concatenation to grow an array: x = [x, newColumn]
In this example, you know tmax so I'd suggest just changing the allocation of x to have the right number of columns up front:
% Current initial value
x=bsxfun(#times,ones(9,11),[0:10:100]);
% Extra columns - please check my upper bound value
x=[x, zeros(9,tmax)];

Setting array size from command line arguments

I know that in Fortran I can declare an array of a number N of elements if N is declared as a parameter before (and so defined to some value).
On the other hand I know I can get a program to accept arguments from the command line with the use of the subroutine get_command_arg.
My question is:
Can I somehow declare an array of a number of elements given by a command when calling the program from the command line?
I'm looking for something like the command line:
./main -30
where main.f03 would begin with something like:
integer, parameter :: N = get_command_arg(1)
real :: x(N) ...
I'm trying not to define the arrays as allocatable.
There are certain languages where you can initialize variables and named constants from command line (like chapel), but Fortran is not one of them.
You say "I am trying not to define the arrays as allocatable." but that is the problem. You simply have to. There is no other way.
Your code
integer, parameter :: N = get_command_arg(1)
real :: x(N) ...
is illegal for several reasons.
You cannot put GET_COMMAND_ARGUMENT() into a constant expression because it is not among allowed functions. It does not return compile-time constant values. And parameter initializers must be set at the compile time.
GET_COMMAND_ARGUMENT() is a subroutine, not a function. It can return more stuff, not just the value, but also the length and status. It is not pure and the Fortran standard is trying to use only pure functions. Other things, like RANDOM_NUMBER(), are subroutines. It is a good style to follow in your own programs too.
The only way in Fortran to create arrays that change from run to run is to make the array allocatable or pointer. There are also automatic arrays for local arrays.
You can do it this way without allocatables. You just have to pass the size (after converting it to an integer) into a subroutine. But really, I see no reason not to use allocatables for something like this.
program main
implicit none
integer :: n,arg_len,istat
character(len=100) :: arg
call get_command_argument(1,value=arg,status=istat)
if (istat/=0) error stop 'error: cannot read first arg'
read(arg,'(I100)',iostat=istat) n
if (istat/=0) error stop 'error: first arg not an integer'
call real_main(n)
contains
subroutine real_main(n)
integer,intent(in) :: n
integer,dimension(n) :: ival
ival = 1
write(*,*) ival
end subroutine real_main
end program main
Example use:
> ./main 1
1
> ./main 2
1 1
> ./main 3
1 1 1

Slicing Multidimensional Array by a variable

I am writing a method which accepts a two dimensional array of doubles and an int row number as parameters and returns the highest value of the elements in the given row.
it looks like this:
function getHighestInRow(A, i)
return(maximum(A[:i,:]))
end
the issue i am having is when i slice the array with
A[:i,:]
I get an argument error because the :i makes i get treated differently.
the code works in the other direction with
A[:,i,:]
Is there a way to escape the colon? so that i gets treated as a variable after a colon?
You're doing something strange with the colon. In this case you're using the symbol :i not the value of i. Just getHighestInRow(A,i) = maximum(A[i,:]) should work.
Edit: As Dan Getz said in the comment on the question, getHighestInRow(A,i) = maximum(#view A[i,:]) is more efficient, though, as the slicing will allocate a temporary unnecessary array.

Fortran Array Splice Initialization

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.

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.

Resources