Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29273 Discussions

FORTRAN equivalent to MATLAB's find and unique functions

Bob_Fratantonio
Beginner
5,878 Views
Does anyone know if there is a FORTRAN equivalent to the find and unique functions in MATLAB? I know FORTRAN does not have a built-in function, but maybe someone could point me elsewhere.

Thanks much,
Bob Fratantonio
0 Kudos
16 Replies
eos_pengwern
Beginner
5,878 Views
Quoting - Bob Fratantonio
Does anyone know if there is a FORTRAN equivalent to the find and unique functions in MATLAB? I know FORTRAN does not have a built-in function, but maybe someone could point me elsewhere.

Thanks much,
Bob Fratantonio

There are no direct equivalents to the MATLAB functions, but depending on exactly what you want to do you can often get close by using some combination of the Fortran MINLOC, MAXLOC, ALL, ANY and COUNT functions, each of which search whole vectors or arrays for elements meeting some user-specified criterion.

For example, you can locate the first non-zero element ofa vectorusing:

m=minloc(abs(B), 1, mask=abs(B).gt.0)

...wherem is an integer pointing to the required element of vector B.

Stephen.

0 Kudos
Peter
Beginner
5,878 Views
Quoting - Bob Fratantonio
Does anyone know if there is a FORTRAN equivalent to the find and unique functions in MATLAB? I know FORTRAN does not have a built-in function, but maybe someone could point me elsewhere.

Thanks much,
Bob Fratantonio

Bob,


FORTRAN by default doesn't havesuch kind of intrinsic functions. You must install numerical libraries like IMSL or NAG .I am not sure ifthere are such functions in the above mentioned libraries, howeveryou can downoad trail version and check the documentation to see if they have them.

Usually IVF proffesional edition comes with Math Kernel Library (MKL). If you have it , check MKL documentation in your hard disk which might look something like this !

C:Program Files (x86)IntelCompiler11.0�72fortranDocumentationmkl

Alternatively you can code your own functions as a last resort..!!
0 Kudos
TimP
Honored Contributor III
5,878 Views
Quoting - eos pengwern

There are no direct equivalents to the MATLAB functions, but depending on exactly what you want to do you can often get close by using some combination of the Fortran MINLOC, MAXLOC, ALL, ANY and COUNT functions, each of which search whole vectors or arrays for elements meeting some user-specified criterion.

For example, you can locate the first non-zero element ofa vectorusing:

m=minloc(abs(B), 1, mask=abs(B).gt.0)


That's a good response to the assertion that Fortran has no "built-in" (intrinsic?) functions. Maybe OP meant none of exactly equivalent functionality.
Note that the 1, argument here is optional, in case someone thinks it looks ugly.
Using minloc repeatedly on B(last+1:) to find the next non-zero element may be inefficient, at least in the case where there aren't many zeroes, but that's probably not a concern in comparison with matlab.
PACK tends to be implemented inefficiently, but may come in handy.
0 Kudos
Bob_Fratantonio
Beginner
5,877 Views
Thanks for the responses guys. I have a 2D matrix (say 23 by 24) that is filled with integer values (usually just 0,1,2,or 3). I need the indices of all of the zeros, ones, twos, and threes. I suppose calling MINLOC over and over will work, but like you guys mentioned it may not be the most efficient way to do this. This code needs to be very efficient, as it is supposed to be the replacement for the MATLAB scripts I have. I think I just need to get a little creative with the functions I have (and I do have the MKL).

Thanks,
Bob
0 Kudos
eos_pengwern
Beginner
5,877 Views
Quoting - Bob Fratantonio
Thanks for the responses guys. I have a 2D matrix (say 23 by 24) that is filled with integer values (usually just 0,1,2,or 3). I need the indices of all of the zeros, ones, twos, and threes. I suppose calling MINLOC over and over will work, but like you guys mentioned it may not be the most efficient way to do this. This code needs to be very efficient, as it is supposed to be the replacement for the MATLAB scripts I have. I think I just need to get a little creative with the functions I have (and I do have the MKL).

Thanks,
Bob

Just about anything you do in IVF, once it has been compiled in 'Release' mode, is likely to outperform MATLAB. A few months ago I ported a carefully-vectorized MATLAB application into IVF and got 10-100 fold speed increases in every part. Even where a single MATLAB function must be manually coded into a Fortran subroutine, the Fortran will normally run much more quickly when it has been compiled.

For what you describe, there are a couple of approaches. Depending on what form you need the indices in, I'd probably do something like this:

1) Define a number of logical matrices with the same dimensions as your integer matrix, e.g.

LOGICAL :: zeros(size(B,1), size(B,2)), ones(size(B,1), size(B,2)), twos(size(B,1), size(B,2)), etc.

2) Populate each matrix with 'true' or 'false' values as appropriate, viz:

zeros=(B.eq.0)
ones=(B.eq.1)
twos=(B.eq.2)
etc.

3) Use theCOUNT function to find how many of each value there are

n_zeros=COUNT(zeros)
n_ones=COUNT(ones)
n_twos=COUNT(twos)
etc.

4)Use these n_zeros etc.values to dimension arrays ready to receive the indices, and then just blast through the logical matrices with a couple of nested DO loops to record theindices at each 'true' element.



0 Kudos
eos_pengwern
Beginner
5,877 Views
Quoting - tim18(in the context of the MINLOC function)

Note that the 1, argument here is optional, in case someone thinks it looks ugly.


It definitely does look ugly, but MINLOC is a bit of an awkward function. If you used it the 'obvious' way, i.e.

i=minloc(abs(B), mask=abs(B).gt.0)

...then you'd have had to define 'i' as a single-element vector, rather than a scalar, and refer to the result as i(1). Putiing the '1' argumnet in the middle forces MINLOC to return a scalar.

The syntax of MINLOC makes it very flexible when using it on multi-dimensional matrices, but it's a pain in the neck when applying it to one-dimensional vectors!

Stephen.
0 Kudos
TimP
Honored Contributor III
5,877 Views
The standard requires the DIM=1 argument to be assumed, if omitted, when MASK is present (so says Adams, Brainerd et al. f95 version). I suppose you have to be defensive and not depend on it. Granted, the original way (up to possibly 15 years ago, with no DIM or MASK available) was awkward for rank 1.
0 Kudos
eos_pengwern
Beginner
5,877 Views
Quoting - tim18
The standard requires the DIM=1 argument to be assumed, if omitted, when MASK is present (so says Adams, Brainerd et al. f95 version). I suppose you have to be defensive and not depend on it. Granted, the original way (up to possibly 15 years ago, with no DIM or MASK available) was awkward for rank 1.

That's neat; I didn't know that. I usually use MINLOC without MASK, so the '1' has to be present.

Thanks Tim.
0 Kudos
Bob_Fratantonio
Beginner
5,877 Views
Quoting - eos pengwern

For what you describe, there are a couple of approaches. Depending on what form you need the indices in, I'd probably do something like this:

1) Define a number of logical matrices with the same dimensions as your integer matrix, e.g.

LOGICAL :: zeros(size(B,1), size(B,2)), ones(size(B,1), size(B,2)), twos(size(B,1), size(B,2)), etc.

2) Populate each matrix with 'true' or 'false' values as appropriate, viz:

zeros=(B.eq.0)
ones=(B.eq.1)
twos=(B.eq.2)
etc.

3) Use theCOUNT function to find how many of each value there are

n_zeros=COUNT(zeros)
n_ones=COUNT(ones)
n_twos=COUNT(twos)
etc.

4)Use these n_zeros etc.values to dimension arrays ready to receive the indices, and then just blast through the logical matrices with a couple of nested DO loops to record theindices at each 'true' element.




Thanks so much. This is perfect (and easier than I thought)!
0 Kudos
Peter
Beginner
5,877 Views
Quoting - eos pengwern

Just about anything you do in IVF, once it has been compiled in 'Release' mode, is likely to outperform MATLAB. A few months ago I ported a carefully-vectorized MATLAB application into IVF and got 10-100 fold speed increases in every part. Even where a single MATLAB function must be manually coded into a Fortran subroutine, the Fortran will normally run much more quickly when it has been compiled.

For what you describe, there are a couple of approaches. Depending on what form you need the indices in, I'd probably do something like this:

1) Define a number of logical matrices with the same dimensions as your integer matrix, e.g.

LOGICAL :: zeros(size(B,1), size(B,2)), ones(size(B,1), size(B,2)), twos(size(B,1), size(B,2)), etc.

2) Populate each matrix with 'true' or 'false' values as appropriate, viz:

zeros=(B.eq.0)
ones=(B.eq.1)
twos=(B.eq.2)
etc.

3) Use theCOUNT function to find how many of each value there are

n_zeros=COUNT(zeros)
n_ones=COUNT(ones)
n_twos=COUNT(twos)
etc.

4)Use these n_zeros etc.values to dimension arrays ready to receive the indices, and then just blast through the logical matrices with a couple of nested DO loops to record theindices at each 'true' element.




Talking about the Fortran vs Matlab speed, your response above is encouraging for people like me who wants to switch from Matlab to Fortran. I heardFortran is lot faster, but I think why should you waste lot of time coding in Fortran, when you have Matlab. For example 'find' and 'unique' functions really takes less than a minute to run in Matlab, but if you want to code the samein Fortran it takes atleast 10-30 mins for an expert and maybe 1-1 1/2 hour for me.

I think one can use Matlab up to certain point, whereas Fortran can be extened much further.
0 Kudos
eos_pengwern
Beginner
5,877 Views
Quoting - Peter

Talking about the Fortran vs Matlab speed, your response above is encouraging for people like me who wants to switch from Matlab to Fortran. I heardFortran is lot faster, but I think why should you waste lot of time coding in Fortran, when you have Matlab. For example 'find' and 'unique' functions really takes less than a minute to run in Matlab, but if you want to code the samein Fortran it takes atleast 10-30 mins for an expert and maybe 1-1 1/2 hour for me.

I think one can use Matlab up to certain point, whereas Fortran can be extened much further.

That's right. When I started developing the project I'm working on now,I first of all did everything in MATLAB - both the GUI and the calculation engine. This was relatively quick and easy to do, both because of the intrinsic capabilities of MATLAB and because, being an interpreted language, the 'cycle-time' when developing an algorithm is much quicker (you can even make changes to a program's source code while it is running, and see the effect of the change instantaneously). The performance, however, is not up to the job if you are doing really heavy-duty calculations, however hard you try to vecorize the code.

Currently I've got the calculation engine coded in IVF, with the MATLAB GUI still in place and calling the Fortran in a DLL. The speedup, as I said, is 10-100X. MATLAB's GUI is fairly pedestrian in terms of the controls it offers (for example, itdoesn't offer scroll windows and doing tabs is a struggle) but excellent in its data visualization capabilities. Sooner or later I will probably recode the GUI using Java or C#, but that's a low priority for now. When I do, the Fortan DLL should just transfer without any changes.
0 Kudos
Peter
Beginner
5,878 Views
Quoting - eos pengwern

That's right. When I started developing the project I'm working on now,I first of all did everything in MATLAB - both the GUI and the calculation engine. This was relatively quick and easy to do, both because of the intrinsic capabilities of MATLAB and because, being an interpreted language, the 'cycle-time' when developing an algorithm is much quicker (you can even make changes to a program's source code while it is running, and see the effect of the change instantaneously). The performance, however, is not up to the job if you are doing really heavy-duty calculations, however hard you try to vecorize the code.

Currently I've got the calculation engine coded in IVF, with the MATLAB GUI still in place and calling the Fortran in a DLL. The speedup, as I said, is 10-100X. MATLAB's GUI is fairly pedestrian in terms of the controls it offers (for example, itdoesn't offer scroll windows and doing tabs is a struggle) but excellent in its data visualization capabilities. Sooner or later I will probably recode the GUI using Java or C#, but that's a low priority for now. When I do, the Fortan DLL should just transfer without any changes.

I agree with you regarding visual capabilities of matlab. I run the code in fortran and which does 'heavy-duty calculations' and transfer the data to matlab manually to graph them. You can actually code that in Fortran but that is not worth it, you actually have to code like the matlab guys did for their graphing tools.

I tried comparing matlab vs fortran speed by solving a pde on the same computer, and as you said fortran is obviously much faster.
0 Kudos
Xj_Kong
Novice
5,878 Views

Here I have ever worked on this unique function and hope it is helpful.

subroutine Unique1DArray_D(Arr_a)
! Similar function as matlab unique to remove redundent elements.
! Author: Kong, kinaxj@gmail.com
  IMPLICIT NONE
  real*8,DIMENSION(:),allocatable::Arr_a,Arr_b
  LOGICAL,DIMENSION(:), allocatable::mask
  INTEGER,DIMENSION(:),allocatable::index_vector,indexSos
  INTEGER::i,j,num
  num=size(Arr_a);  ALLOCATE(mask(num)); mask = .TRUE.
  DO i=num,2,-1
     mask(i)=.NOT.(ANY(Arr_a(:i-1)==Arr_a(i)))
  END DO
 ! Make an index vector
  allocate(indexSos(size(PACK([(i,i=1,num)],mask))))
  ALLOCATE(index_vector(size(indexSos))); index_vector=PACK([(i,i=1,num)],mask)

  ! Now copy the unique elements of a into b
  ALLOCATE(Arr_b(size(index_vector)))
  Arr_b=Arr_a(index_vector)
  call move_alloc(Arr_b,Arr_a)
 end subroutine Unique1DArray_D

 

0 Kudos
Roman1
New Contributor I
5,878 Views

Thanks for posting this.  If you are trying to copy Matlab's unique function, then the output array should also be sorted.  What happens if you change your code to the following:

 ! MKL routine to sort array.
 call dlasrt( 'I', num, Arr_a, info )
 
 ! Since the array is already sorted, figuring out
 ! the mask is simpler.
 DO i=num,2,-1
    mask(i) = .NOT. (Arr_a(i-1)==Arr_a(i))
 END DO

 

0 Kudos
Johannes_Rieke
New Contributor III
5,878 Views

Hi all,

I googled today about cshift and found accidentally the following web page:

http://www.fortran-2000.com/rank/

There seems to be a Fortran solution equivalent to Matlab's Unique function. I didn't test it yet, but the source looks promising.

 

Many Thanks to Michel Olagnon, who is the author.

 

Best regards,

Johannes

0 Kudos
Xj_Kong
Novice
5,878 Views

Note that the algorithms for sorting and making unique are fairly different. If you need to sort your array, unique is automatically easy to be obtained. 

 

0 Kudos
Reply