Starting to rename some of these 1-letter variables...

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@7784 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

// BLC: For certain inputs, not having a complex/real
// function can result in numerical instability.

// BLC: clean up complex arithmetic

// BLC: insert problem size computation based on memory size?

use BitOps;
use Random;
use Time;

// problem size configs
config const logN = 5;

param radix = 4;

// pseudo-random input configs
config const deterministic = false,
             seed = 314159265.0,
             arand = 1220703125.0;

// verification configs
config const epsilon = 2.0 ** -51.0,
             threshold = 16.0;

// boolean configs
config const printTiming = true;

// BLC: control printing out of error value to avoid portability issues

def main() {
  // compute problem size
  const N = 1 << logN;

  // twiddle domain and arrays
  const TwiddleDom = [0..N/4);
  var Twiddles: [TwiddleDom] complex;

  computeTwiddles(Twiddles);
  bitReverseShuffle(Twiddles);

  // problem domain and arrays
  const ProblemDom = [0..N);
  var Z, z: [ProblemDom] complex;

  // generate pseudo-random input
  if deterministic then
    fillRandom(z, seed=seed, arand=arand);
  else
    fillRandom(z);

  // conjugate input, storing result to work array
  Z = conjg(z);

  // TIMED SECTION
  var startTime = getCurrentTime();

  bitReverseShuffle(Z);
  dfft(Z, Twiddles);

  var execTime = getCurrentTime() - startTime;

  verifyResults(z, Z, execTime, Twiddles);
}

def computeTwiddles(W) {
  const n = W.numElements;
  const delta = 2.0 * atan(1.0) / n;

  W(0) = 1.0;
  W(n/2) = let x = cos(delta * n/2)
            in (x, x):complex;
  forall i in [1..n/2) {
    const x = cos(delta*i);
    const y = sin(delta*i);
    W(i)     = (x, y):complex;
    W(n - i) = (y, x):complex;
  }
}

def bitReverseShuffle(W: [?WD]) {
  const n = WD.numIndices;
  const reverse = lg(n);
  var V: [WD] W.elt_type;  // BLC: rename elt_type to remove underscore?
  // BLC: would like to use:
  //  var Perm: [i in WD] int = bitReverse(i:uint(64), numBits = reverse):int;
  var Perm: [WD] index(WD);
  [i in WD] Perm(i) = bitReverse(i, numBits = reverse);
  // BLC: would like to use:
  // V(Perm) = W;
  [i in WD] V(Perm(i)) = W(i);
  W = V;
}

// reverses numBits low-order bits of val
def bitReverse(val: ?valType, numBits = 64) {
  param mask: uint(64) = 0x0102040810204080;
  const valReverse64 = bitMatMultOr(mask, bitMatMultOr(val:uint(64), mask));
  const valReverse = bitRotLeft(valReverse64, numBits);
  return valReverse: valType;
}

def dfft(Z, W) {
  cft1st(Z, W);

  var span = radix;
  var lasti = 2;
  for i in radix..logN/2 by 2 {
    cftmd1(span, Z, W);
    span *= radix;
    lasti = i;
  }
  for i in [lasti+2..logN) by 2 {
    cftmd2(span, Z, W);
    span *= radix;
  }

  const n = Z.numElements;
  if (radix*span == n) {
    forall j in [0..span) {
      butterfly(1.0, 1.0, 1.0, Z[j..j+3*span by span]);
    }
  } else {
    forall j in [0..span) {
      var a = Z(j);
      var b = Z(j+span);
      Z(j) = a + b;
      Z(j+span) = a - b;
    }
  }
}

def verifyResults(z, Z, execTime, Twiddles) {
  const N = Z.numElements;

  // BLC: This line wants /(complex,real) to be implemented directly:
  Z = conjg(Z) / N;

  bitReverseShuffle(Z);
  dfft(Z, Twiddles);

  // BLC: need to check this against written spec
  var maxerr = max reduce sqrt((z.real - Z.real)**2 + (z.imag - Z.imag)**2);

  maxerr = maxerr / logN / epsilon;

  write(if (maxerr < threshold) then "SUCCESS" else "FAILURE");
  writeln(", error = ", maxerr);
  writeln();
  writeln("N      = ", N);
  if (printTiming) {
    writeln("Time   = ", execTime);
    const gflop = 5.0 * N * logN / 1000000000.0;
    writeln("GFlops = ", gflop / execTime);
  }
}

def cft1st(A, W) {
  const n = A.domain(1).length;
  var x0 = A(0) + A(1);
  var x1 = A(0) - A(1);
  var x2 = A(2) + A(3);
  var x3 = A(2) - A(3);

  const wk1r = W(1).real;

  A(0) = x0 + x2;
  A(2) = x0 - x2;
  A(1) = (x1.real - x3.imag, x1.imag + x3.real):complex;
  A(3) = (x1.real + x3.imag, x1.imag - x3.real):complex;

  x0 = A(4) + A(5);
  x1 = A(4) - A(5);
  x2 = A(6) + A(7);
  x3 = A(6) - A(7);
  A(4) = x0 + x2;
  A(6) = (x2.imag - x0.imag, x0.real - x2.real):complex;
  x0 = (x1.real - x3.imag, x1.imag + x3.real):complex;
  A(5) = wk1r * (x0.real - x0.imag, x0.real + x0.imag):complex;
  x0 = (x3.imag + x1.real, x3.real - x1.imag):complex;
  A(7) = wk1r * (x0.imag - x0.real, x0.imag + x0.real):complex;

  // BLC: would like to use an indefinite arithmetic array here
  // BLC: would also like to use () on both indices and zipping
  //      together of ranges
  forall j,k1 in [8..n) by 8, 1..(n-8)/8 {
    var wk2 = W(k1);
    var wk1 = W(2*k1);
    var wk3 = (wk1.real - 2* wk2.imag * wk1.imag,
               2 * wk2.imag * wk1.real - wk1.imag):complex;

    butterfly(wk1, wk2, wk3, A[j..j+3]);

    wk1 = W(2*k1+1);
    wk3 = (wk1.real - 2*wk2.real * wk1.imag,
           2*wk2.real * wk1.real - wk1.imag):complex;
    wk2 = (-wk2.imag, wk2.real): complex;
    butterfly(wk1, wk2, wk3, A[j+4..j+7]);
  }
}

def cftmd0(span, A, W) {
  var wk1r = W(1).real;
  const m = radix*span;

  forall j in [0..span) {
    butterfly(1.0, 1.0, 1.0, A[j..j+3*span by span]);
  }

  forall j in [m..m+span) {
    butterfly((wk1r, wk1r):complex, 1.0i, (-wk1r, wk1r):complex,
              A[j..j+3*span by span]);
  }
}

def cftmd1(span, A, W) {
  const m = radix*span;
  const m2 = 2*m;
  const n = A.domain(1).length;

  cftmd0(span, A, W);
  forall k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
    var wk2 = W[k1];
    var wk1 = W[2*k1];
    var wk3 = (wk1.real - 2 * wk2.imag * wk1.imag,
               2 * wk2.imag * wk1.real - wk1.imag):complex;
    for j in [k..k+span) {
      butterfly(wk1, wk2, wk3, A[j..j+3*span by span]);
    }

    wk1 = W[2*k1+1];
    wk3 = (wk1.real - 2 * wk2.real * wk1.imag,
           2 * wk2.real * wk1.real - wk1.imag):complex;

    for j in [k+m..k+m+span) {
      butterfly(wk1, (-wk2.imag, wk2.real):complex, wk3, A[j..j+3*span by span]);
    }
  }
}

def cftmd2(span, A, W) {
  var m = radix*span;
  var m2 = 2*m;
  const n = A.domain(1).length;

  cftmd0(span, A, W);
  if (m2 >= n) return;
  if (m2 >= n / 8) {
    cftmd21(span, A, W);
    return;
  }

  forall j in [0..span) {
    forall k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
      var wk2 = W[k1];
      var wk1 = W[k1 + k1];
      var wk3 = (wk1.real - 2*wk2.imag * wk1.imag,
                 2 * wk2.imag * wk1.real - wk1.imag): complex;
      butterfly(wk1, wk2, wk3, A[j+k..j+k+3*span by span]);
    }

    forall k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
      var wk2 = W[k1];
      var wk1 = W[2*k1 + 1];
      var wk3 = (wk1.real - 2*wk2.real * wk1.imag,
                 2*wk2.real * wk1.real - wk1.imag): complex;
      wk2 = (-wk2.imag, wk2.real): complex;

      butterfly(wk1, wk2, wk3, A[j+k+m..j+k+m+3*span by span]);
    }
  }
}

def cftmd21(span, A, W) {
  const n = A.domain(1).length;
  var m = radix*span;
  var m2 = 2*m;

  for k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
    var wk2 = W[k1];
    var wk1 = W[2*k1];
    var wk3 = (wk1.real - 2*wk2.imag * wk1.imag,
               2* wk2.imag * wk1.real - wk1.imag): complex;

    forall j in [k..k+span) {
      butterfly(wk1, wk2, wk3, A[j..j+3*span by span]);
    }

    wk1 = W[2*k1 + 1];
    wk3 = (wk1.real - 2*wk2.real * wk1.imag,
           2*wk2.real * wk1.real - wk1.imag): complex;
    wk2 = (-wk2.imag, wk2.real): complex;

    forall j in [k+m..k+m+span) {
      butterfly(wk1, wk2, wk3, A[j..j+3*span by span]);
    }
  }
}

def butterfly(wk1: complex, wk2: complex, wk3: complex,
              inout A:[1..radix] complex) {
  var x0 = A[1] + A[2];
  var x1 = A[1] - A[2];
  var x2 = A[3] + A[4];
  var x3 = A[3] - A[4];

  A[1] = x0 + x2;
  x0 -= x2;
  A[3] = wk2 * x0;
  x0 = (x1.real - x3.imag, x1.imag + x3.real):complex;
  A[2] = wk1 * x0;
  x0 = (x1.real + x3.imag, x1.imag - x3.real):complex;
  A[4] = wk3 * x0;
}

// BLC: For certain inputs, not having a complex/real
// function can result in numerical instability.

// BLC: clean up complex arithmetic

// BLC: insert problem size computation based on memory size?

use BitOps;
use Random;
use Time;

// problem size configs
config const logN = 5;

// pseudo-random input configs
config const deterministic = false,
             seed = 314159265.0,
             arand = 1220703125.0;

// verification configs
config const epsilon = 2.0 ** -51.0,
             threshold = 16.0;

// boolean configs
config const printTiming = true;

// BLC: control printing out of error value to avoid portability issues

def main() {
  // compute problem size
  const N = 1 << logN;

  // twiddle domain and arrays
  const TwiddleDom = [0..N/4);
  var Twiddles: [TwiddleDom] complex;

  computeTwiddles(Twiddles);
  bitReverseShuffle(Twiddles);

  // problem domain and arrays
  const ProblemDom = [0..N);
  var Z, z: [ProblemDom] complex;

  // generate pseudo-random input
  if deterministic then
    fillRandom(z, seed=seed, arand=arand);
  else
    fillRandom(z);

  // conjugate input, storing result to work array
  Z = conjg(z);

  // TIMED SECTION
  var startTime = getCurrentTime();

  bitReverseShuffle(Z);
  dfft(Z, Twiddles);

  var execTime = getCurrentTime() - startTime;

  verifyResults(z, Z, execTime, Twiddles);
}

def computeTwiddles(W) {
  const n = W.numElements;
  const delta = 2.0 * atan(1.0) / n;

  W(0) = 1.0;
  W(n/2) = let cosDeltaN = cos(delta * n/2)
            in (cosDeltaN, cosDeltaN):complex;
  forall i in [1..n/2) {
    const x = cos(delta*i);
    const y = sin(delta*i);
    W(i)     = (x, y):complex;
    W(n - i) = (y, x):complex;
  }
}

def bitReverseShuffle(W: [?WD]) {
  const n = WD.numIndices;
  const reverse = lg(n);
  var V: [WD] W.elt_type;  // BLC: rename elt_type to remove underscore?
  // BLC: would like to use:
  //  var Perm: [i in WD] int = bitReverse(i:uint(64), numBits = reverse):int;
  var Perm: [WD] index(WD);
  [i in WD] Perm(i) = bitReverse(i, numBits = reverse);
  // BLC: would like to use:
  // V(Perm) = W;
  [i in WD] V(Perm(i)) = W(i);
  W = V;
}

// reverses numBits low-order bits of val
def bitReverse(val: ?valType, numBits = 64) {
  param mask: uint(64) = 0x0102040810204080;
  const valReverse64 = bitMatMultOr(mask, bitMatMultOr(val:uint(64), mask));
  const valReverse = bitRotLeft(valReverse64, numBits);
  return valReverse: valType;
}

def dfft(A: [?AD] complex, W) {
  cft1st(A, W);

  var l = 4;
  var lasti = 2;
  for i in 4..logN/2 by 2 {
    cftmd1(l, A, W);
    l *= 4;
    lasti = i;
  }
  for i in [lasti+2..logN) by 2 {
    cftmd2(l, A, W);
    l *= 4;
  }

  const n = AD(1).length;
  if ((l << 2) == n) {
    forall j in [0..l) {
      butterfly(1.0, 1.0, 1.0, A[j..j+3*l by l]);
    }
  } else {
    forall j in [0..l) {
      var a = A(j);
      var b = A(j+l);
      A(j) = a + b;
      A(j+l) = a - b;
    }
  }
}

def verifyResults(z, Z, execTime, Twiddles) {
  const N = Z.numElements;

  // BLC: This line wants /(complex,real) to be implemented directly:
  Z = conjg(Z) / N;

  bitReverseShuffle(Z);
  dfft(Z, Twiddles);

  // BLC: need to check this against written spec
  var maxerr = max reduce sqrt((z.real - Z.real)**2 + (z.imag - Z.imag)**2);

  maxerr = maxerr / logN / epsilon;

  write(if (maxerr < threshold) then "SUCCESS" else "FAILURE");
  writeln(", error = ", maxerr);
  writeln();
  writeln("N      = ", N);
  if (printTiming) {
    writeln("Time   = ", execTime);
    const gflop = 5.0 * N * logN / 1000000000.0;
    writeln("GFlops = ", gflop / execTime);
  }
}

def cft1st(A, W) {
  const n = A.domain(1).length;
  var x0 = A(0) + A(1);
  var x1 = A(0) - A(1);
  var x2 = A(2) + A(3);
  var x3 = A(2) - A(3);

  const wk1r = W(1).real;

  A(0) = x0 + x2;
  A(2) = x0 - x2;
  A(1) = (x1.real - x3.imag, x1.imag + x3.real):complex;
  A(3) = (x1.real + x3.imag, x1.imag - x3.real):complex;

  x0 = A(4) + A(5);
  x1 = A(4) - A(5);
  x2 = A(6) + A(7);
  x3 = A(6) - A(7);
  A(4) = x0 + x2;
  A(6) = (x2.imag - x0.imag, x0.real - x2.real):complex;
  x0 = (x1.real - x3.imag, x1.imag + x3.real):complex;
  A(5) = wk1r * (x0.real - x0.imag, x0.real + x0.imag):complex;
  x0 = (x3.imag + x1.real, x3.real - x1.imag):complex;
  A(7) = wk1r * (x0.imag - x0.real, x0.imag + x0.real):complex;

  // BLC: would like to use an indefinite arithmetic array here
  // BLC: would also like to use () on both indices and zipping
  //      together of ranges
  forall j,k1 in [8..n) by 8, 1..(n-8)/8 {
    var wk2 = W(k1);
    var wk1 = W(2*k1);
    var wk3 = (wk1.real - 2* wk2.imag * wk1.imag,
               2 * wk2.imag * wk1.real - wk1.imag):complex;

    butterfly(wk1, wk2, wk3, A[j..j+3]);

    wk1 = W(2*k1+1);
    wk3 = (wk1.real - 2*wk2.real * wk1.imag,
           2*wk2.real * wk1.real - wk1.imag):complex;
    wk2 = (-wk2.imag, wk2.real): complex;
    butterfly(wk1, wk2, wk3, A[j+4..j+7]);
  }
}

def cftmd0(l, A, W) {
  var wk1r = W(1).real;
  const m = l << 2;

  forall j in [0..l) {
    butterfly(1.0, 1.0, 1.0, A[j..j+3*l by l]);
  }

  forall j in [m..m+l) {
    butterfly((wk1r, wk1r):complex, 1.0i, (-wk1r, wk1r):complex,
              A[j..j+3*l by l]);
  }
}

def cftmd1(l, A, W) {
  const m = l << 2;
  const m2 = 2*m;
  const n = A.domain(1).length;

  cftmd0(l, A, W);
  forall k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
    var wk2 = W[k1];
    var wk1 = W[2*k1];
    var wk3 = (wk1.real - 2 * wk2.imag * wk1.imag,
               2 * wk2.imag * wk1.real - wk1.imag):complex;
    for j in [k..k+l) {
      butterfly(wk1, wk2, wk3, A[j..j+3*l by l]);
    }

    wk1 = W[2*k1+1];
    wk3 = (wk1.real - 2 * wk2.real * wk1.imag,
           2 * wk2.real * wk1.real - wk1.imag):complex;

    for j in [k+m..k+m+l) {
      butterfly(wk1, (-wk2.imag, wk2.real):complex, wk3, A[j..j+3*l by l]);
    }
  }
}

def cftmd2(l, A, W) {
  var m = l << 2;
  var m2 = 2*m;
  const n = A.domain(1).length;

  cftmd0(l, A, W);
  if (m2 >= n) return;
  if (m2 >= n / 8) {
    cftmd21(l, A, W);
    return;
  }

  forall j in [0..l) {
    forall k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
      var wk2 = W[k1];
      var wk1 = W[k1 + k1];
      var wk3 = (wk1.real - 2*wk2.imag * wk1.imag,
                 2 * wk2.imag * wk1.real - wk1.imag): complex;
      butterfly(wk1, wk2, wk3, A[j+k..j+k+3*l by l]);
    }

    forall k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
      var wk2 = W[k1];
      var wk1 = W[2*k1 + 1];
      var wk3 = (wk1.real - 2*wk2.real * wk1.imag,
                 2*wk2.real * wk1.real - wk1.imag): complex;
      wk2 = (-wk2.imag, wk2.real): complex;

      butterfly(wk1, wk2, wk3, A[j+k+m..j+k+m+3*l by l]);
    }
  }
}

def cftmd21(l, A, W) {
  const n = A.domain(1).length;
  var m = l << 2;
  var m2 = 2*m;
  var m3 = 3*m;

  for k,k1 in [m2..n) by m2, 1..(n-m2)/m2 {
    var wk2 = W[k1];
    var wk1 = W[2*k1];
    var wk3 = (wk1.real - 2*wk2.imag * wk1.imag,
               2* wk2.imag * wk1.real - wk1.imag): complex;

    forall j in [k..k+l) {
      butterfly(wk1, wk2, wk3, A[j..j+3*l by l]);
    }

    wk1 = W[2*k1 + 1];
    wk3 = (wk1.real - 2*wk2.real * wk1.imag,
           2*wk2.real * wk1.real - wk1.imag): complex;
    wk2 = (-wk2.imag, wk2.real): complex;

    forall j in [k+m..k+m+l) {
      butterfly(wk1, wk2, wk3, A[j..j+3*l by l]);
    }
  }
}

def butterfly(wk1: complex, wk2: complex, wk3: complex,
              inout A:[1..4] complex) {
  var x0 = A[1] + A[2];
  var x1 = A[1] - A[2];
  var x2 = A[3] + A[4];
  var x3 = A[3] - A[4];

  A[1] = x0 + x2;
  x0 -= x2;
  A[3] = wk2 * x0;
  x0 = (x1.real - x3.imag, x1.imag + x3.real):complex;
  A[2] = wk1 * x0;
  x0 = (x1.real + x3.imag, x1.imag - x3.real):complex;
  A[4] = wk3 * x0;
}


Fix slightly incorrect chpl_comm_atomic_cmpxchg_*() parameter declaration.

[Reviewed by Sung.]

The result (5th) parameter of the chpl_comm_atomic_cmpxchg_*() functions
should be a reference (pointer) to an explicit bool(32), rather than to
a default bool.  This was causing warnings at application build time,
although because the default boolean type is 32 bits anyway, there was
no functional issue.

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@20386 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

pragma "no use ChapelStandard"
module NetworkAtomics {
  const LINENO = -1:int(32); // it'd be nice if we had something like __LINENO__

  // int(64)
  extern proc chpl_comm_atomic_get_int64(ref result:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_int64(ref desired:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_int64(ref op:int(64),
                                        l:int(32), ref obj:int(64),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_int64(ref op:int(64),
                                              l:int(32), ref obj:int(64),
                                              ref result:int(64),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_int64(ref desired:int(64),
                                          l:int(32), ref obj:int(64),
                                          ref result:int(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_int64(ref expected:int(64),
                                             ref desired:int(64),
                                             l:int(32), ref obj:int(64),
                                             ref result:bool(32),
                                             ln:int(32), fn:string);

  // int(64)
  record ratomic_int64 {
    var _v: int(64);
    inline proc read() {
      var ret: int(64);
      chpl_comm_atomic_get_int64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:int(64)) {
      var v = value;
      chpl_comm_atomic_put_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:int(64)):int(64) {
      var ret:int(64);
      var v = value;
      chpl_comm_atomic_xchg_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:int(64), desired:int(64)):bool {
      var ret:bool(32);
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_int64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:int(64), desired:int(64)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:int(64), desired:int(64)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_add_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_add_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_sub_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_sub_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_or_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_or_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_and_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_and_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_xor_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_xor_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:int(64)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:int(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_int64, b:ratomic_int64) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_int64, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_int64, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_int64, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_int64, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_int64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_int64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // int(32)
  extern proc chpl_comm_atomic_get_int32(ref result:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_int32(ref desired:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_int32(ref op:int(32),
                                        l:int(32), ref obj:int(32),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_int32(ref op:int(32),
                                              l:int(32), ref obj:int(32),
                                              ref result:int(32),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_int32(ref desired:int(32),
                                          l:int(32), ref obj:int(32),
                                          ref result:int(32),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_int32(ref expected:int(32),
                                             ref desired:int(32),
                                             l:int(32), ref obj:int(32),
                                             ref result:bool(32),
                                             ln:int(32), fn:string);

  // int32
  record ratomic_int32 {
    var _v: int(32);
    inline proc read() {
      var ret: int(32);
      chpl_comm_atomic_get_int32(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:int(32)) {
      var v = value;
      chpl_comm_atomic_put_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:int(32)):int(32) {
      var ret:int(32);
      var v = value;
      chpl_comm_atomic_xchg_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:int(32), desired:int(32)):bool {
      var ret:bool(32);
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_int32(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:int(32), desired:int(32)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:int(32), desired:int(32)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_add_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_add_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_sub_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_sub_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_or_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_or_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_and_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_and_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_xor_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_xor_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:int(32)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:int(32)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_int32, b:ratomic_int32) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_int32, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_int32, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_int32, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_int32, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_int32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_int32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // uint(64)
  extern proc chpl_comm_atomic_get_uint64(ref result:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_uint64(ref desired:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_uint64(ref op:uint(64),
                                        l:int(32), ref obj:uint(64),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_uint64(ref op:uint(64),
                                              l:int(32), ref obj:uint(64),
                                              ref result:uint(64),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_uint64(ref desired:uint(64),
                                          l:int(32), ref obj:uint(64),
                                          ref result:uint(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_uint64(ref expected:uint(64),
                                             ref desired:uint(64),
                                             l:int(32), ref obj:uint(64),
                                             ref result:bool(32),
                                             ln:int(32), fn:string);

  // uint(64)
  record ratomic_uint64 {
    var _v: uint(64);
    inline proc read() {
      var ret: uint(64);
      chpl_comm_atomic_get_uint64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:uint(64)) {
      var v = value;
      chpl_comm_atomic_put_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:uint(64)):uint(64) {
      var ret:uint(64);
      var v = value;
      chpl_comm_atomic_xchg_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:uint(64), desired:uint(64)):bool {
      var ret:bool(32);
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_uint64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:uint(64), desired:uint(64)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:uint(64), desired:uint(64)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_add_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_add_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_sub_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_sub_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_or_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_or_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_and_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_and_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_xor_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_xor_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:uint(64)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:uint(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_uint64, b:ratomic_uint64) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_uint64, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_uint64, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_uint64, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_uint64, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_uint64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_uint64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // uint(32)
  extern proc chpl_comm_atomic_get_uint32(ref result:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_uint32(ref desired:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_uint32(ref op:uint(32),
                                        l:int(32), ref obj:uint(32),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_uint32(ref op:uint(32),
                                              l:int(32), ref obj:uint(32),
                                              ref result:uint(32),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_uint32(ref desired:uint(32),
                                          l:int(32), ref obj:uint(32),
                                          ref result:uint(32),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_uint32(ref expected:uint(32),
                                             ref desired:uint(32),
                                             l:int(32), ref obj:uint(32),
                                             ref result:bool(32),
                                             ln:int(32), fn:string);

  // uint(32)
  record ratomic_uint32 {
    var _v: uint(32);
    inline proc read() {
      var ret: uint(32);
      chpl_comm_atomic_get_uint32(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:uint(32)) {
      var v = value;
      chpl_comm_atomic_put_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:uint(32)):uint(32) {
      var ret:uint(32);
      var v = value;
      chpl_comm_atomic_xchg_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:uint(32), desired:uint(32)):bool {
      var ret:bool(32);
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_uint32(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:uint(32), desired:uint(32)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:uint(32), desired:uint(32)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_add_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_add_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_sub_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_sub_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_or_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_or_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_and_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_and_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_xor_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_xor_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:uint(32)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:uint(32)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_uint32, b:ratomic_uint32) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_uint32, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_uint32, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_uint32, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_uint32, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_uint32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_uint32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // bool, implemented with int(64)
  record ratomicflag {
    var _v: int(64);
    inline proc read() {
      var ret: int(64);
      chpl_comm_atomic_get_int64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret:bool;
    }
    inline proc write(value:bool) {
      var v = value:int(64);
      chpl_comm_atomic_put_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:bool):bool {
      var ret:int(64);
      var v = value:int(64);
      chpl_comm_atomic_xchg_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret:bool;
    }
    inline proc compareExchange(expected:bool, desired:bool):bool {
      var ret:bool(32);
      var te = expected:int(64);
      var td = desired:int(64);
      chpl_comm_atomic_cmpxchg_int64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:bool, desired:bool):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:bool, desired:bool):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc testAndSet() {
      return this.exchange(true);
    }
    inline proc clear() {
      this.write(false);
    }

    inline proc waitFor(val:bool) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:int(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomicflag, b:ratomicflag) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomicflag, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomicflag, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomicflag, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomicflag, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomicflag, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomicflag, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // real(64)
  extern proc chpl_comm_atomic_get_real64(ref result:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_real64(ref desired:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_real64(ref op:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_real64(ref op:real(64),
                                                l:int(32), ref obj:real(64),
                                                ref result:real(64),
                                                ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_real64(ref op:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_real64(ref op:real(64),
                                                l:int(32), ref obj:real(64),
                                                ref result:real(64),
                                                ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_real64(ref desired:real(64),
                                           l:int(32), ref obj:real(64),
                                           ref result:real(64),
                                           ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_real64(ref expected:real(64),
                                              ref desired:real(64),
                                              l:int(32), ref obj:real(64),
                                              ref result:bool(32),
                                              ln:int(32), fn:string);

  record ratomic_real64 {
    var _v: real(64);
    inline proc read() {
      var ret: real(64);
      chpl_comm_atomic_get_real64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:real(64)) {
      var v = value;
      chpl_comm_atomic_put_real64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:real(64)):real(64) {
      var ret:real(64);
      var v = value;
      chpl_comm_atomic_xchg_real64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:real(64), desired:real(64)):bool {
      var ret:bool(32);
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_real64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:real(64), desired:real(64)):bool {
      return compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:real(64), desired:real(64)):bool {
      return compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:real(64)):real(64) {
      var v = value;
      var ret:real(64);
      chpl_comm_atomic_fetch_add_real64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:real(64)):real(64) {
      var v = value;
      chpl_comm_atomic_add_real64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:real(64)):real(64) {
      var v = value;
      var ret:real(64);
      chpl_comm_atomic_fetch_sub_real64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:real(64)):real(64) {
      var v = value;
      chpl_comm_atomic_sub_real64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:real(64)):real(64) {
      compilerError("or not definted for network atomic real");
    }
    inline proc or(value:real(64)):real(64) {
      compilerError("or not definted for network atomic real");
    }

    inline proc fetchAnd(value:real(64)):real(64) {
      compilerError("and not definted for network atomic real");
    }
    inline proc and(value:real(64)):real(64) {
      compilerError("and not definted for network atomic real");
    }

    inline proc waitFor(val:real(64)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:real(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_real64, b:ratomic_real64) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_real64, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_real64, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_real64, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_real64, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_real64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_real64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

}

pragma "no use ChapelStandard"
module NetworkAtomics {
  const LINENO = -1:int(32); // it'd be nice if we had something like __LINENO__

  // int(64)
  extern proc chpl_comm_atomic_get_int64(ref result:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_int64(ref desired:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_int64(ref op:int(64),
                                        l:int(32), ref obj:int(64),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_int64(ref op:int(64),
                                              l:int(32), ref obj:int(64),
                                              ref result:int(64),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_int64(ref op:int(64),
                                         l:int(32), ref obj:int(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_int64(ref op:int(64),
                                               l:int(32), ref obj:int(64),
                                               ref result:int(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_int64(ref desired:int(64),
                                          l:int(32), ref obj:int(64),
                                          ref result:int(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_int64(ref expected:int(64),
                                             ref desired:int(64),
                                             l:int(32), ref obj:int(64),
                                             ref result:bool,
                                             ln:int(32), fn:string);

  // int(64)
  record ratomic_int64 {
    var _v: int(64);
    inline proc read() {
      var ret: int(64);
      chpl_comm_atomic_get_int64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:int(64)) {
      var v = value;
      chpl_comm_atomic_put_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:int(64)):int(64) {
      var ret:int(64);
      var v = value;
      chpl_comm_atomic_xchg_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:int(64), desired:int(64)):bool {
      var ret:bool;
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_int64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:int(64), desired:int(64)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:int(64), desired:int(64)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_add_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_add_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_sub_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_sub_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_or_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_or_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_and_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_and_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:int(64)):int(64) {
      var v = value;
      var ret:int(64);
      chpl_comm_atomic_fetch_xor_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:int(64)):int(64) {
      var v = value;
      chpl_comm_atomic_xor_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:int(64)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:int(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_int64, b:ratomic_int64) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_int64, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_int64, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_int64, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_int64, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_int64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_int64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // int(32)
  extern proc chpl_comm_atomic_get_int32(ref result:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_int32(ref desired:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_int32(ref op:int(32),
                                        l:int(32), ref obj:int(32),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_int32(ref op:int(32),
                                              l:int(32), ref obj:int(32),
                                              ref result:int(32),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_int32(ref op:int(32),
                                         l:int(32), ref obj:int(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_int32(ref op:int(32),
                                               l:int(32), ref obj:int(32),
                                               ref result:int(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_int32(ref desired:int(32),
                                          l:int(32), ref obj:int(32),
                                          ref result:int(32),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_int32(ref expected:int(32),
                                             ref desired:int(32),
                                             l:int(32), ref obj:int(32),
                                             ref result:bool,
                                             ln:int(32), fn:string);

  // int32
  record ratomic_int32 {
    var _v: int(32);
    inline proc read() {
      var ret: int(32);
      chpl_comm_atomic_get_int32(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:int(32)) {
      var v = value;
      chpl_comm_atomic_put_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:int(32)):int(32) {
      var ret:int(32);
      var v = value;
      chpl_comm_atomic_xchg_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:int(32), desired:int(32)):bool {
      var ret:bool;
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_int32(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:int(32), desired:int(32)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:int(32), desired:int(32)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_add_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_add_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_sub_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_sub_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_or_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_or_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_and_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_and_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:int(32)):int(32) {
      var v = value;
      var ret:int(32);
      chpl_comm_atomic_fetch_xor_int32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:int(32)):int(32) {
      var v = value;
      chpl_comm_atomic_xor_int32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:int(32)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:int(32)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_int32, b:ratomic_int32) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_int32, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_int32, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_int32, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_int32, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_int32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_int32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // uint(64)
  extern proc chpl_comm_atomic_get_uint64(ref result:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_uint64(ref desired:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_uint64(ref op:uint(64),
                                        l:int(32), ref obj:uint(64),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_uint64(ref op:uint(64),
                                              l:int(32), ref obj:uint(64),
                                              ref result:uint(64),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_uint64(ref op:uint(64),
                                         l:int(32), ref obj:uint(64),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_uint64(ref op:uint(64),
                                               l:int(32), ref obj:uint(64),
                                               ref result:uint(64),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_uint64(ref desired:uint(64),
                                          l:int(32), ref obj:uint(64),
                                          ref result:uint(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_uint64(ref expected:uint(64),
                                             ref desired:uint(64),
                                             l:int(32), ref obj:uint(64),
                                             ref result:bool,
                                             ln:int(32), fn:string);

  // uint(64)
  record ratomic_uint64 {
    var _v: uint(64);
    inline proc read() {
      var ret: uint(64);
      chpl_comm_atomic_get_uint64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:uint(64)) {
      var v = value;
      chpl_comm_atomic_put_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:uint(64)):uint(64) {
      var ret:uint(64);
      var v = value;
      chpl_comm_atomic_xchg_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:uint(64), desired:uint(64)):bool {
      var ret:bool;
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_uint64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:uint(64), desired:uint(64)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:uint(64), desired:uint(64)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_add_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_add_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_sub_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_sub_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_or_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_or_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_and_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_and_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:uint(64)):uint(64) {
      var v = value;
      var ret:uint(64);
      chpl_comm_atomic_fetch_xor_uint64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:uint(64)):uint(64) {
      var v = value;
      chpl_comm_atomic_xor_uint64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:uint(64)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:uint(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_uint64, b:ratomic_uint64) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_uint64, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_uint64, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_uint64, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_uint64, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_uint64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_uint64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // uint(32)
  extern proc chpl_comm_atomic_get_uint32(ref result:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_uint32(ref desired:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_and_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_and_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_or_uint32(ref op:uint(32),
                                        l:int(32), ref obj:uint(32),
                                        ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_or_uint32(ref op:uint(32),
                                              l:int(32), ref obj:uint(32),
                                              ref result:uint(32),
                                              ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xor_uint32(ref op:uint(32),
                                         l:int(32), ref obj:uint(32),
                                         ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_xor_uint32(ref op:uint(32),
                                               l:int(32), ref obj:uint(32),
                                               ref result:uint(32),
                                               ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_uint32(ref desired:uint(32),
                                          l:int(32), ref obj:uint(32),
                                          ref result:uint(32),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_uint32(ref expected:uint(32),
                                             ref desired:uint(32),
                                             l:int(32), ref obj:uint(32),
                                             ref result:bool,
                                             ln:int(32), fn:string);

  // uint(32)
  record ratomic_uint32 {
    var _v: uint(32);
    inline proc read() {
      var ret: uint(32);
      chpl_comm_atomic_get_uint32(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:uint(32)) {
      var v = value;
      chpl_comm_atomic_put_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:uint(32)):uint(32) {
      var ret:uint(32);
      var v = value;
      chpl_comm_atomic_xchg_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:uint(32), desired:uint(32)):bool {
      var ret:bool;
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_uint32(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:uint(32), desired:uint(32)):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:uint(32), desired:uint(32)):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_add_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_add_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_sub_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_sub_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_or_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc or(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_or_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchAnd(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_and_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc and(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_and_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchXor(value:uint(32)):uint(32) {
      var v = value;
      var ret:uint(32);
      chpl_comm_atomic_fetch_xor_uint32(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc xor(value:uint(32)):uint(32) {
      var v = value;
      chpl_comm_atomic_xor_uint32(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc waitFor(val:uint(32)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:uint(32)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_uint32, b:ratomic_uint32) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_uint32, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_uint32, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_uint32, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_uint32, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_uint32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_uint32, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // bool, implemented with int(64)
  record ratomicflag {
    var _v: int(64);
    inline proc read() {
      var ret: int(64);
      chpl_comm_atomic_get_int64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret:bool;
    }
    inline proc write(value:bool) {
      var v = value:int(64);
      chpl_comm_atomic_put_int64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:bool):bool {
      var ret:int(64);
      var v = value:int(64);
      chpl_comm_atomic_xchg_int64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret:bool;
    }
    inline proc compareExchange(expected:bool, desired:bool):bool {
      var ret:bool;
      var te = expected:int(64);
      var td = desired:int(64);
      chpl_comm_atomic_cmpxchg_int64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:bool, desired:bool):bool {
      return this.compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:bool, desired:bool):bool {
      return this.compareExchange(expected, desired);
    }

    inline proc testAndSet() {
      return this.exchange(true);
    }
    inline proc clear() {
      this.write(false);
    }

    inline proc waitFor(val:bool) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:int(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomicflag, b:ratomicflag) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomicflag, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomicflag, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomicflag, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomicflag, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomicflag, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomicflag, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

  // real(64)
  extern proc chpl_comm_atomic_get_real64(ref result:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_put_real64(ref desired:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_add_real64(ref op:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_add_real64(ref op:real(64),
                                                l:int(32), ref obj:real(64),
                                                ref result:real(64),
                                                ln:int(32), fn:string);
  extern proc chpl_comm_atomic_sub_real64(ref op:real(64),
                                          l:int(32), ref obj:real(64),
                                          ln:int(32), fn:string);
  extern proc chpl_comm_atomic_fetch_sub_real64(ref op:real(64),
                                                l:int(32), ref obj:real(64),
                                                ref result:real(64),
                                                ln:int(32), fn:string);
  extern proc chpl_comm_atomic_xchg_real64(ref desired:real(64),
                                           l:int(32), ref obj:real(64),
                                           ref result:real(64),
                                           ln:int(32), fn:string);
  extern proc chpl_comm_atomic_cmpxchg_real64(ref expected:real(64),
                                              ref desired:real(64),
                                              l:int(32), ref obj:real(64),
                                              ref result:bool,
                                              ln:int(32), fn:string);

  record ratomic_real64 {
    var _v: real(64);
    inline proc read() {
      var ret: real(64);
      chpl_comm_atomic_get_real64(ret, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc write(value:real(64)) {
      var v = value;
      chpl_comm_atomic_put_real64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc exchange(value:real(64)):real(64) {
      var ret:real(64);
      var v = value;
      chpl_comm_atomic_xchg_real64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchange(expected:real(64), desired:real(64)):bool {
      var ret:bool;
      var te = expected;
      var td = desired;
      chpl_comm_atomic_cmpxchg_real64(te, td, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc compareExchangeWeak(expected:real(64), desired:real(64)):bool {
      return compareExchange(expected, desired);
    }
    inline proc compareExchangeStrong(expected:real(64), desired:real(64)):bool {
      return compareExchange(expected, desired);
    }

    inline proc fetchAdd(value:real(64)):real(64) {
      var v = value;
      var ret:real(64);
      chpl_comm_atomic_fetch_add_real64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc add(value:real(64)):real(64) {
      var v = value;
      chpl_comm_atomic_add_real64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchSub(value:real(64)):real(64) {
      var v = value;
      var ret:real(64);
      chpl_comm_atomic_fetch_sub_real64(v, this.locale.id:int(32), this._v, ret, LINENO, "NetworkAtomics.chpl");
      return ret;
    }
    inline proc sub(value:real(64)):real(64) {
      var v = value;
      chpl_comm_atomic_sub_real64(v, this.locale.id:int(32), this._v, LINENO, "NetworkAtomics.chpl");
    }

    inline proc fetchOr(value:real(64)):real(64) {
      compilerError("or not definted for network atomic real");
    }
    inline proc or(value:real(64)):real(64) {
      compilerError("or not definted for network atomic real");
    }

    inline proc fetchAnd(value:real(64)):real(64) {
      compilerError("and not definted for network atomic real");
    }
    inline proc and(value:real(64)):real(64) {
      compilerError("and not definted for network atomic real");
    }

    inline proc waitFor(val:real(64)) {
      on this do while (read() != val) do chpl_task_yield();
    }

    inline proc peek() {
      return _v;
    }
    inline proc poke(value:real(64)) {
      _v = value;
    }

    proc writeThis(x: Writer) {
      x.write(read());
    }
  }

  inline proc =(a:ratomic_real64, b:ratomic_real64) {
    a.write(b.read());
    return a;
  }
  inline proc =(a:ratomic_real64, b) {
    compilerError("Cannot directly assign network atomic variables");
    return a;
  }
  inline proc +(a:ratomic_real64, b) {
    compilerError("Cannot directly add network atomic variables");
    return a;
  }
  inline proc -(a:ratomic_real64, b) {
    compilerError("Cannot directly subtract network atomic variables");
    return a;
  }
  inline proc *(a:ratomic_real64, b) {
    compilerError("Cannot directly multiply network atomic variables");
    return a;
  }
  inline proc /(a:ratomic_real64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }
  inline proc %(a:ratomic_real64, b) {
    compilerError("Cannot directly divide network atomic variables");
    return a;
  }

}


adding compiled flag

adding compiled flag

/*
  Package of Graph-Based Semi-Supervised Learning techniques based partially
  on the work by `Subramanya and Talukdar <http://graph-ssl.wdfiles.com/local--files/blog%3A_start/graph_ssl_acl12_tutorial_slides_final.pdf>`_

  Also, see notes in the /tex folder under main.

 */
module GBSSL {
  use LinearAlgebra;

  class ModifiedAdsorptionModel {
    var vdom: domain(1),
        gdom: domain(2),
        edom: sparse subdomain(gdom),
        v: [vdom] real,
        e: [edom] real,
        directed: bool,
        A: [gdom] real,
        pcont: [vdom] real,
        pabdn: [vdom] real,
        pinj : [vdom] real,
        compiled: bool = false,
        beta: real = 1.1;

    proc fit(data: [], labels: []) {
      if !compiled {
        compile();
      }
      if data.shape[1] != data.shape[2] {
      } else {
        vdom = {1..#data.shape[1]};
        gdom = {1..#data.shape[1], 1..#data.shape[1]};
        var xd = data.domain;
        ref Xd = A.reindex(xd);
        for ij in data.domain {
          if data[ij] > 0 {
            edom += ij+(1,1);
            Xd[ij] = data[ij];
          }
        }
      }
    }

    /*
      We need three probabilities as each vertex for the MAD algo.
     */

    proc compile() {
      calculateProbs();
      compiled = true;
    }
    proc calculateProbs() {
      for v in vdom {
        var ps = cellProbabilities(v);
        pcont[v] = ps[1];
        pinj[v] = ps[2];
        pabdn[v] = ps[3];
      }
    }

    /*
     Try to take advantage of function promotion by doing this one element at a time
     Will need some expert advice.
     */
     proc cellProbabilities(i:int) {
       // Need to remove the diagonal from the expressions m and l below
       var m: real = + reduce A[i,..];
       m = m - A[i,i];
       var l = + reduce xlogx(A[i,..]);
       l = l - xlogx(A[i,i]);
       var h = max(log(m) - l / m,0);
       var c = log(beta) / (log(beta + h));
       var d = (1- c)* sqrt(h);
       var z = max(c+d, 1);
       //writeln(" cell probabilities (%n, %n, %n)".format(c/z, d/z, 1-(c+d)/z));
       return (c/z, d/z, 1-c-d);
     }
  }

   proc xlogx(x: real) {
     if x > 0.0005 {
       return x * log(x);
     } else {
       return 0;
     }
   }
}

/*
  Package of Graph-Based Semi-Supervised Learning techniques based partially
  on the work by `Subramanya and Talukdar <http://graph-ssl.wdfiles.com/local--files/blog%3A_start/graph_ssl_acl12_tutorial_slides_final.pdf>`_

  Also, see notes in the /tex folder under main.

 */
module GBSSL {
  use LinearAlgebra;

  class ModifiedAdsorptionModel {
    var vdom: domain(1),
        gdom: domain(2),
        edom: sparse subdomain(gdom),
        v: [vdom] real,
        e: [edom] real,
        directed: bool,
        A: [gdom] real,
        pcont: [vdom] real,
        pabdn: [vdom] real,
        pinj : [vdom] real,
        beta: real = 1.1;

    proc fit(data: [], labels: []) {
      if data.shape[1] != data.shape[2] {
      } else {
        vdom = {1..#data.shape[1]};
        gdom = {1..#data.shape[1], 1..#data.shape[1]};
        var xd = data.domain;
        ref Xd = A.reindex(xd);
        for ij in data.domain {
          if data[ij] > 0 {
            edom += ij+(1,1);
            Xd[ij] = data[ij];
          }
        }
      }
    }

    /*
      We need three probabilities as each vertex for the MAD algo.
     */

    proc compile() {
      calculateProbs();
    }
    proc calculateProbs() {
      for v in vdom {
        var ps = cellProbabilities(v);
        pcont[v] = ps[1];
        pinj[v] = ps[2];
        pabdn[v] = ps[3];
      }
    }

    /*
     Try to take advantage of function promotion by doing this one element at a time
     Will need some expert advice.
     */
     proc cellProbabilities(i:int) {
       // Need to remove the diagonal from the expressions m and l below
       var m: real = + reduce A[i,..];
       m = m - A[i,i];
       var l = + reduce xlogx(A[i,..]);
       l = l - xlogx(A[i,i]);
       var h = max(log(m) - l / m,0);
       var c = log(beta) / (log(beta + h));
       var d = (1- c)* sqrt(h);
       var z = max(c+d, 1);
       //writeln(" cell probabilities (%n, %n, %n)".format(c/z, d/z, 1-(c+d)/z));
       return (c/z, d/z, 1-c-d);
     }
  }

   proc xlogx(x: real) {
     if x > 0.0005 {
       return x * log(x);
     } else {
       return 0;
     }
   }
}