Brian Dolan
Brian Dolan

Reputation: 3136

User defined function in Chapel has odd behavior .type vs .eltType

I wanted to write a concatenation function, so I came up with

proc concat(x:[], y:[]) {
  const d:int = x.size + y.size;
  var v:[1..d] x.type;

  writeln("\n d: ", d);
  writeln("\n x.domain: ", x.domain);
  writeln("\n y.domain: ", y.domain);
  var k = 1;
  for i in x.domain {
    v[k] = x[i];
    writeln("i: ", i, " k: ", k,  " x[i]: ", x[i], " v[k]: ", v[k]);
    k += 1;
  }
  for i in y.domain {
    v[k] = y[i];
    writeln("i: ", i, " k: ", k, " y[i]: ", y[i], " v[k]: ", v[k]);
    k += 1;
  }
  writeln("\n v: ", v);

  return v;
}

But it has a very odd output

var x: [1..3] real = [1.1, 2.2, 3.3],
    y: [9..11] real = [9.9, 10.10, 11.11];

var z = concat(x,y);
writeln(z);

Produces

 d: 6

 x.domain: {1..3}

 y.domain: {9..11}
i: 1 k: 1 x[i]: 1.1 v[k]: 1.1 1.1 1.1
i: 2 k: 2 x[i]: 2.2 v[k]: 2.2 2.2 2.2
i: 3 k: 3 x[i]: 3.3 v[k]: 3.3 3.3 3.3
i: 9 k: 4 y[i]: 9.9 v[k]: 9.9 9.9 9.9
i: 10 k: 5 y[i]: 10.1 v[k]: 10.1 10.1 10.1
i: 11 k: 6 y[i]: 11.11 v[k]: 11.11 11.11 11.11

 v: 1.1 1.1 1.1 2.2 2.2 2.2 3.3 3.3 3.3 9.9 9.9 9.9 10.1 10.1 10.1 11.11 11.11 11.11
1.1 1.1 1.1 2.2 2.2 2.2 3.3 3.3 3.3 9.9 9.9 9.9 10.1 10.1 10.1 11.11 11.11 11.11

This is kind of mystifying.

Upvotes: 2

Views: 70

Answers (1)

Brad
Brad

Reputation: 4043

It looks as though your code has confused .type and .eltType. Given an array variable like var A: [1..3] real;, A.type is effectively [1..3] real while A.eltType is simply real. So when you declarde:

var v:[1..d] x.type;

rather than getting the array of real values that you intended, you're actually declaring an array whose elements are themselves arrays of real values.

Then, since Chapel supports promoted assignment from a scalar to an array (e.g., A = 0.0 would be an easy way to zero out my A array above), when you're copying elements from your original arrays to v, each array element of v is storing the value in each of its positions, resulting in the triplication of the values.

Changing the declaration of v to:

var v:[1..d] x.eltType;

should give you what you want. Here's the corrected version online.

var x: [1.. 3] real = [1.1, 2.2, 3.3],
    y: [9..11] real = [9.9, 10.10, 11.11];

var z = concat( x, y );
writeln( z );

proc concat( x:[], y:[] ) {
     const d:int = x.size + y.size;
  // var   v:[1..d] x.type;    // ------------------------------------ FAIL
                               /*     d: 6
                               x.domain: {1..3}
                               y.domain: {9..11}

                               i:   1, k:   1, x[i]:    1.10, v[k]: 1.1 1.1 1.1
                               i:   2, k:   2, x[i]:    2.20, v[k]: 2.2 2.2 2.2
                               i:   3, k:   3, x[i]:    3.30, v[k]: 3.3 3.3 3.3
                               i:   9, k:   4, y[i]:    9.90, v[k]: 9.9 9.9 9.9
                               i:  10, k:   5, y[i]:   10.10, v[k]: 10.1 10.1 10.1
                               i:  11, k:   6, y[i]:   11.11, v[k]: 11.11 11.11 11.11

                               v:
                               1.1 1.1 1.1 2.2 2.2 2.2 3.3 3.3 3.3 9.9 9.9 9.9 10.1 10.1 10.1 11.11 11.11 11.11
                               1.1 1.1 1.1 2.2 2.2 2.2 3.3 3.3 3.3 9.9 9.9 9.9 10.1 10.1 10.1 11.11 11.11 11.11
                               */
     var   v:[1..d] x.eltType; // ------------------------------------ PASS
                               /*     d: 6
                               x.domain: {1..3}
                               y.domain: {9..11}

                               i:   1, k:   1, x[i]:    1.10, v[k]: 1.1
                               i:   2, k:   2, x[i]:    2.20, v[k]: 2.2
                               i:   3, k:   3, x[i]:    3.30, v[k]: 3.3
                               i:   9, k:   4, y[i]:    9.90, v[k]: 9.9
                               i:  10, k:   5, y[i]:   10.10, v[k]: 10.1
                               i:  11, k:   6, y[i]:   11.11, v[k]: 11.11

                               v:
                               1.1 2.2 3.3 9.9 10.1 11.11
                               1.1 2.2 3.3 9.9 10.1 11.11
                               */
     writeln( "\n       d: ", d );
     writeln(   "x.domain: ", x.domain );
     writeln(   "y.domain: ", y.domain );
     var k = 1;
     for i in x.domain {
         v[k] = x[i];
      // writeln("i: ", i, " k: ", k,  " x[i]: ", x[i], " v[k]: ", v[k]);
         writef( "i: %{###},", i ); writef( " k: %{###},", k ); writef( " x[i]: %{####.##},", x[i] ); writeln( " v[k]: ", v[k] );
         k += 1;
     }
     for i in y.domain {
         v[k] = y[i];
      // writeln("i: ", i, " k: ", k, " y[i]: ", y[i], " v[k]: ", v[k]);
         writef( "i: %{###},", i ); writef( " k: %{###},", k ); writef( " y[i]: %{####.##},", y[i] ); writeln( " v[k]: ", v[k] );
         k += 1;
     }
     writeln( "\nv:\n", v );

     return v;
}

( and both alternatives, side by side, left for any further experimentations )

Upvotes: 2

Related Questions