Since jagged arrays are not possible in Fortran, how would one implement a cartesian product of multiple variables?
Jagged arrays are supported in fortan in multiple ways, using either allocatables, or pointers, or even combinations of both. There are some restrictions, but at least the underlying support is there. The important missing features in my opinion are the ability to declare parameter constants that are jagged arrays, or to initialize them at declaration.
I don’t understand the question about cartesian products? One would normally just use a derived type. Say you want the cartesian product of a set of colors and a set of charges. You would then define a derived type and reference is as color(i)%charge(j)
for example. Or if you have objects that have those two characteristics, then you would define a derived type and reference it as particle(k)%color
and particle(k)%charge
. Or if each particle has its own cartesian product, you would define a derived type and reference it as particle(k)%color(i)%charge(j)
. There are many possibilities, depending on exactly what you want to do.
Assuming this is what you mean by “jagged arrays”, this is something I’ve done plenty of times.
type :: array_t
real, allocatable :: array(:)
end type
type(array_t), allocatable :: jagged_array(:)
jagged_array = &
[ array_t([1., 2., 3.]) &
, array_t([4.]) &
, array_t([5., 6.]) &
]
By “cartesian product” do you mean one of dyadic or tensor/Kronecker product. Here are three functions I use either separately or in conjuction. Probably a simpler way to implement these but these are part of a tensor/vector utility package I wrote several years ago and I use them for manipulating tensors etc in my structural dynamics code.
Pure Function v_dyadic_v(A,B) RESULT(dyadic)
Real(WP), Intent(IN) :: A(:), B(:)
Real(WP) :: dyadic(SIZE(A,DIM=1),SIZE(B,DIM=1))
Integer :: i
Do i=1,SIZE(A,DIM=1)
dyadic(i, :) = A(i)*B
EndDo
End Function v_dyadic_v
Pure Function T_dyadic_v(A,B) RESULT(dyadic)
Real(WP), Intent(IN) :: A(:,:), B(:)
Real(WP) :: dyadic(SIZE(A,DIM=1),SIZE(A,DIM=2), &
SIZE(B,DIM=1))
Integer :: i, j, k
Real(WP) :: bk
Do k=1,SIZE(B,DIM=1)
bk = B(k)
Do j=1,SIZE(A,DIM=2)
Do i=1,SIZE(A,DIM=1)
dyadic(i, j, k) = A(i,j)*bk
EndDo
EndDo
EndDo
End Function T_dyadic_v
Pure Function v_tridyadic(A,B,C) RESULT(tridyad)
Real(WP), Intent(IN) :: A(:), B(:), C(:)
Real(WP) :: tridyad(SIZE(A,DIM=1),SIZE(B,DIM=1), &
SIZE(C,DIM=1))
Real(WP) :: abdyad(SIZE(A,DIM=1), SIZE(B,DIM=1))
abdyad = v_dyadic_v(a,b)
tridyad = T_dyadic_v(abdyad,c)
End Function v_tridyadic
This is a good example of the missing features I mentioned above. Suppose you wanted to define a parameter constant of this jagged array structure. Everything is known at compile time, so it seems like it should be possible, but it isn’t.
Or, suppose you didn’t want it to be a constant but an initialized variable that you might want to modify later. It isn’t allowed to put those assignments on the declaration line and have a saved, initialized, variable. Even though everything is known at compile time, the only way to do this in fortran is with runtime assignments (which means there must be some kind of initialization call for the derived type, or you must constantly check and confirm before it is used that it has been allocated).
I have suggested this a few times now. I.e.
I will try and remember to write a paper to have something added to the worklist before the February meeting.
I was in a rush when I wrote the title and message. I meant to ask how to implement (1) the subsets of the items in an array given that jagged arrays are not possible and (2) the cartesian_product.
@everythingfunctional and @RonShepard have set me striaght on the fact that jagged arrays are possible, so the implementation now seems easy particularly with @everythingfunctional 's example.
The cartesain product should also be relatively straightforward.
Example subsets:
If X = [“feed”, “sing”, “ignore”]
Then its subsets would be the 8-element jagged array:
[
[ ]
[“feed”]
[“sing”]
[“ignore”]
[“feed”, “sing”]
[“feed”, “ignore”]
[“sing”, “ignore”]
[“feed”, “sing”, “ignore”]
]
If Y = [-5, -0.5, 0]
then cartesian_product(X, Y)
would be a 3x3 matrix:
[
[“feed”, -5.0], [“feed”, -0.5], [“feed”, 0.0]
[“sing”, -5.0], [“sing”, -0.5], [“sing”, 0.0]
[“ignore”, -5.0], [“ignore”, -0.5], [“ignore”, 0.0]
]