5

So of course it's easy to create a domain (and from that, an array) with fixed known rank and array of sizes,

proc do_something(sizes: [1..2] int) {
  const D: domain(2) = {1..sizes[1], 1..sizes[2]};
  var arr: [D] int;
    // ...
}

But what does one do with an array of varying sizes, of runtime-determined (or at least not hardcoded-in) length?

proc do_something_2(sizes: [?sd] int) {
  const rank = sd.rank;
  var D: domain(rank); 
  var arr: [D] int; 

  writeln(arr);
}

The line var D: domain(rank); fails, as it seems to need a param rank - but even if that worked it's not clear how to set the domain afterwards; expand seems like it expands the domain in both directions.

Jonathan Dursi
  • 50,107
  • 9
  • 127
  • 158
  • It's not actually particularly important for my current problem, as I know the rank before hand. But the body of the code can be written in a rank-independent way with domain/array iterators (it's basically just a stencil application), and it would be nice to write the entire routine without reference to the rank. – Jonathan Dursi Jul 20 '18 at 14:49
  • 1
    It is the case that ranks of domains/arrays have to be known at compile-time, but in practice users have been able to write rank-independent code where they specify the rank at compile time via a `config param`. The most extensive example of this is an AMR code written by a summer intern which, as I recall, could be run as a 1D, 2D, 3D, nD, ... code. I haven't reacquainted myself with it enough to recall what patterns were used (and post a good answer to this Q), but wanted to share the link before heading out on vacation: https://github.com/chapel-lang/chapel/tree/master/test/studies/amr – Brad Jul 20 '18 at 20:23
  • 1
    Here are some presentations related to that AMR code from SIAM CSE 2011: https://chapel-lang.org/presentations/SIAM_CSE_2011/D_ClaridgeTalk1.pdf https://chapel-lang.org/presentations/SIAM_CSE_2011/E_ClaridgeTalk2.pdf – Brad Jul 20 '18 at 20:29

1 Answers1

4

You can assign a domain from a tuple of ranges:

var tup = (1..10,2..20);
var D : domain(2) = tup;

The param modifier will work. Here is an example where I take in a domain, create a domain one dimension larger, and return an array on it.

proc dimensionalExpansion( dom : domain ) {
  // Get and expand rank
  param oldRank = dom.rank;
  param newRank = oldRank+1;

  // create tuple of size newRank to store each dimensions ranges
  var ranges : newRank*range(dom.idxType, BoundedRangeType.bounded, dom.stridable);
  // copy range from domain
  for i in 1..#oldRank do ranges[i] = dom.dim(i);
  // use last range from domain as our last range
  ranges[newRank] = ranges[oldRank];

  // Create new domain from ranges tuple
  var D: domain(newRank) = ranges;
  // Create array
  var arr: [D] int;

  // Putting some arbitrary values into the array;
  for idx in D {
    arr[idx] = if newRank > 1 then idx[newRank] - idx[1] else idx; 
  }

  return arr;
}

writeln( "==================" );
writeln( dimensionalExpansion( {1..3} ) );
writeln( "==================" );
writeln( dimensionalExpansion( {1..3,1..3} ) );
writeln( "==================" );
writeln( dimensionalExpansion( {1..3,1..3,1..3} ) );

Running TIO Instance

  • Ah! Nearly there, thanks! What if rank isn't a param and is known only at run time? – Jonathan Dursi Jul 20 '18 at 20:05
  • 1
    If you're getting a rank from a domain, it's always a param (because rank is a param member of domain). But also because of that, I don't think something like `var D : domain( rand() );` is possible. – memorableusername Jul 20 '18 at 20:33
  • In my case, in general, rank is determined by the input data read in from a file, so it would be great if we could use that; but in practice I know what the rank will be. – Jonathan Dursi Jul 20 '18 at 20:47
  • Hm. This might be worth filing an issue on. Even if the param-ness of domain.rank does not change, it might provide you with some other solutions. – memorableusername Jul 20 '18 at 21:24
  • 1
    At present, the compiler needs to know the rank (i.e., it needs to be a param value) because we rely on that in order to generate efficient code. It would be possible for us (or, likely, an advanced user) to create a domain and array implementation that supported execution-time rank values, but the performance would likely suffer considerably (e.g., imagine needing to run a loop that turned out to just have just three iterations every time you wanted to compute the address of element (i,j,k)). – Brad Jul 21 '18 at 06:28
  • 1
    If the rank is one of a small set of values (say, 2, 3, or 4, as an example), another solution might be to write rank-generic code, instantiate it for a few distinct values, and then choose between those instantiations based on the dynamic value of rank? – Brad Jul 21 '18 at 06:28