Oops.  Wrong function signature in range.== call to ident.
This should work a bit better....

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

// ChapelRange.chpl
//

use ChapelRangeBase;

//
// range type
//
//   parameterized by:
//        1) an integral element type,
//        2) whether low and/or high bounds exist, and
//        3) whether the stride is one or not.
//
// A range can only be aligned if it is strided.  Since alignments are taken
// modulo the stride, if the stride is one, even a nonzero alignment has no effect.
// The alignment of a range is relative to the low bound if it exists, otherwise
// relative to the high bound if it exists, otherwise absolute.
//
// The type of the stride is a signed type with the same number of bits as the
// index type.  This means that for an unsigned index type, a maximal range can
// be reached in no less than two strides.
//
// Ranges are usually naturally aligned; the _unaligned flag indicates when the
// alignment has been set explicitly -- thus making it "unaligned" w.r.t. its
// natural alignment.
//
// Some ranges have ambiguous alignment -- by definition:
//  Those which lack an upper bound and have a stride less than -1; or
//  Those which lack a lower bound and have a stride greater than 1.
// Ambiguous alignment is propagated by some operations, such as striding and slicing.
// Ambiguous alignment is erased if the alignment is set explicitly.
//
// The _aligned flag is used to track whether a range has been explicitly aligned.
// Initially, all ranges are unaligned, but since they have a stride of 1
// their alignment is not ambiguous.
// When a stride is applied, we check to see if any of the above cases is created.
// If not, the _aligned flag is set indicating that the alignment for that range
// has been determined.  Further applications of the "by" operator preserve that bit.
// The _aligned bit can also be set through the application of an explicit alignment.
//

pragma "range"
record range
{
  type idxType = int;                            // element type
  param boundedType: BoundedRangeType = BoundedRangeType.bounded; // bounded or not
  param stridable: bool = false;                 // range can be strided

  var _base : rangeBase(idxType, boundedType, stridable);
  var _aligned : bool = false;

  // TODO: hilde 2011/03/31
  // This should be a pragma and not a var declaration.
  var _promotionType: idxType;                   // enables promotion

  pragma "inline" proc low return _base.low;       // public getter for low bound
  pragma "inline" proc high return _base.high;     // public getter for high bound
  pragma "inline" proc stride return _base.stride; // public getter for stride
  // public getter for alignment
  pragma "inline" proc alignment return _base.alignment;
  // public getter for the ambiguous alignment flag.
  pragma "inline" proc aligned return _aligned;

  // Returns the starting index in the sequence.
  pragma "inline" proc first return _base.first;
  // Returns the ending index.
  pragma "inline" proc last return _base.last;
  // Returns the low index, properly aligned.
  pragma "inline" proc alignedLow : idxType return _base.alignedLow;
  // Returns the high index, properly aligned.
  pragma "inline" proc alignedHigh : idxType return _base.alignedHigh;
  // Returns the number of elements in this range.
  pragma "inline" proc length return _base.length;
}

//################################################################################
//# Constructors
//#

// Declare this as constructor, so we can capture range creation.
// If it is not a constructor, then the user can still create a maximal range
// (for example) without being warned.
//
proc range.range(type idxType = int,
                 param boundedType : BoundedRangeType = BoundedRangeType.bounded,
                 param stridable : bool = false,
                 _low : idxType = 1,
                 _high : idxType = 0,
                 _stride : chpl__signedType(idxType) = 1,
                 _alignment : idxType = 0,
                 _aligned : bool = false)
{
  _base = new rangeBase(idxType, boundedType, stridable, _low, _high, _stride, _alignment);
  this._aligned = _aligned;
}

proc range.range(type idxType = int,
                 param boundedType = BoundedRangeType.bounded,
                 param stridable : bool = false,
                 _base : rangeBase(idxType, boundedType, stridable),
                 _aligned : bool = false)
{
  this._base = _base;
  this._aligned = _aligned;
}

//////////////////////////////////////////////////////////////////////////////////
// Range builders for bounded ranges
// Range builders are used by the parser to create literal ranges.
//
proc _build_range(low: int, high: int)
  return new range(idxType = int, _low = low, _high = high);
proc _build_range(low: uint, high: uint)
  return new range(uint, _low = low, _high = high);
proc _build_range(low: int(64), high: int(64))
  return new range(int(64), _low = low, _high = high);
proc _build_range(low: uint(64), high: uint(64))
  return new range(uint(64), _low = low, _high = high);

//////////////////////////////////////////////////////////////////////////////////
// Range builders for unbounded ranges
//
proc _build_range(param bt: BoundedRangeType, bound: int)
  return new range(int, bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType, bound: uint)
  return new range(uint, bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType, bound: int(64))
  return new range(int(64), bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType, bound: uint(64))
  return new range(uint(64), bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType)
  return new range(int, bt);

//################################################################################
//# Predicates
//#

// Returns true if this range has a low bound.
proc range.hasLowBound() param
  return boundedType == BoundedRangeType.bounded ||
         boundedType == BoundedRangeType.boundedLow;

// Returns true if this range has a high bound.
proc range.hasHighBound() param
  return boundedType == BoundedRangeType.bounded ||
         boundedType == BoundedRangeType.boundedHigh;

pragma "inline"
proc range.hasFirst()
  return if isAmbiguous() then false else _base.hasFirst();

pragma "inline"
proc range.hasLast()
  return if isAmbiguous() then false else _base.hasLast();

// Returns true if this range is naturally aligned, false otherwise.
// Note that this does not indicate if the range is ambiguously aligned.
pragma "inline"
proc range.isAligned()
  return _base.isAligned();

// Returns true if the alignment of this range is ambiguous.
// After a stride whose absolute value is 2 or greater is applied,
// the alignment must be positively established as evidenced by the _aligned
// flag being set to "true".
pragma "inline"
proc range.isAmbiguous()
{
  // If the range is not strided, then its alignment is unambiguously zero.
  if !stridable then return false;
  else return abs(stride) >= 2 && !aligned;
}

// Returns true if i is in this range.
pragma "inline" proc range.member(i: idxType)
{
  if this.isAmbiguous() then return false;
  return _base.member(i);
}

// Returns true if the other range is contained within this one.
pragma "inline" proc range.member(other: range(?))
{
  if this.isAmbiguous() || other.isAmbiguous() then return false;
  return _base.member(other);
}

// Returns true if this range is equivalent to the other.
// Equivalent ranges produce the same index set.
proc ==(r1: range(?), r2: range(?))
{
  // An ambiguous ranges cannot equal an unambiguous one
  //  even if all their parameters match.
  if r1.isAmbiguous() != r2.isAmbiguous() then return false;

  // As a special case, two ambiguous ranges compare equal
  // if their representations are identical.
  if r1.isAmbiguous() then return ident(r1, r2);

  return r1._base == r2._base;
}

proc !=(r1: range(?), r2: range(?))  return !(r1 == r2);

// This makes use of the fact that the default values for the
// stride and alignment fields are consistent, whether the two ranges
// being compared are stridable or not.
proc ident(r1: range(?), r2: range(?))
  where r1.idxType == r2.idxType &&
  r1.boundedType == r2.boundedType &&
  r1.stridable == r2.stridable
{
  if r1._aligned != r2._aligned then return false;
  return ident(r1._base, r2._base);
}

// If the parameters don't match, then the two ranges cannot be identical.
proc ident(r1: range(?), r2: range(?))
  return false;

//////////////////////////////////////////////////////////////////////////////////
// Bounds checking
//
// returns true if other is in bounds of this for all specified
// bounds; these functions are used to determine if an array slice is
// valid.  We break out the boundedNone case in order to permit
// unbounded ranges to slice ranges of various index types -- otherwise
// we get a compiler error in the boundsCheck function.
//

pragma "inline"
proc range.boundsCheck(other: range(?e,?b,?s))
  where b == BoundedRangeType.boundedNone
{
  if this.isAmbiguous() || other.isAmbiguous()
    then return false;

  return true;
}

pragma "inline"
proc range.boundsCheck(other: range(?e,?b,?s))
{
  if this.isAmbiguous() || other.isAmbiguous()
    then return false;

  return _base.boundsCheck(other._base);
}

pragma "inline"
proc range.boundsCheck(other: idxType)
  return member(other);

//################################################################################
//# Member functions
//#

// Moves the low bound of the range up to the next alignment point.
proc range.alignLow()
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "alignLow -- Canot be applied to a range with ambiguous alignment.");

  _base.alignLow();
  return this;
}

// Moves the high bound of the range down to the next alignment point.
proc range.alignHigh()
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "alignHigh -- Canot be applied to a range with ambiguous alignment.");

  _base.alignHigh();
  return this;
}

// Returns the ordinal of this index within the sequence described by this range.
proc range.indexOrder(i: idxType)
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "indexOrder -- Undefined on a range with ambiguous alignment.");

  return _base.indexOrder(i);
}

//////////////////////////////////////////////////////////////////////////////////
// translate the indices in this range by i
// A range can be translated even if its alignment is ambiguous.
//
pragma "inline"
proc range.translate(i: integral)
  return new range(idxType, boundedType, stridable,
                   _base.translate(i), _aligned);

pragma "inline"
proc range.translate(i)
{
  compilerError("offsets must be of integral type");
}

// Return an interior portion of this range.
pragma "inline"
proc range.interior(i: idxType)
  return new range(idxType, boundedType, stridable,
                    _base.interior(i), _aligned);

// Return an exterior portion of this range.
pragma "inline"
proc range.exterior(i: idxType)
  return new range(idxType, boundedType, stridable,
                   _base.exterior(i), _aligned);

// Returns an expanded range, or a contracted range if i < 0.
// The existing absolute alignment is preserved.
pragma "inline"
proc range.expand(i: idxType)
  return new range(idxType, boundedType, stridable,
                   _base.expand(i), _aligned);

//################################################################################
//# Syntax Functions
//# These are special functions known to the compiler parser.
//#

// Assignment
pragma "inline"
proc =(r1: range(stridable=?s1), r2: range(stridable=?s2))
{
  r1._base = r2._base;
  r1._aligned = r2._aligned;
  return r1;
}

//////////////////////////////////////////////////////////////////////////////////
// Range arithmetic.
//
// Shifts and entire range to the right or left.
// Absolute alignment is not preserved
// (That is, the alignment shifts along with the range.)
//
pragma "inline"
proc +(r: range(?e, ?b, ?s), i: integral)
{
  var temp = r._base + i;
  return new range(temp.idxType, b, s, temp, r._aligned);
}

pragma "inline"
proc +(i:integral, r: range(?e,?b,?s))
  return r + i;

pragma "inline"
proc -(r: range(?e,?b,?s), i: integral)
{
  var temp = r._base - i;
  return new range(temp.idxType, b, s, temp, r._aligned);
}

// This is the syntax processing routine for the "by" keyword.
// The by operator always clobbers an existing alignment.
proc by(r : range(?), str)
{
  var temp = chpl__by(r._base, str);
  var result = new range(temp.idxType, temp.boundedType, temp.stridable);
  result._base = temp;
  result._aligned = r._aligned || chpl__hasAlignment(result);
  return result;
}

// This is the syntax processing routine for the "align" keyword.
// It produces a new range with the specified alignment.
// By definition, alignment is relative to the low bound of the range.
pragma "inline"
proc align(r : range(?e, ?b, ?s), algn)
  return new range(e, b, s, chpl__align(r._base, algn), true);

// Apply a natural alignment to an existing range.
proc range.offset(offs : integral)
{
  _base.offset(offs);
  this._aligned = true;
  return this;
}

// Composition
// Return the intersection of this and other.
proc range.this(other: range(?))
{
  // Two cases to consider:
  //  1) Both ranges unambiguously aligned
  //  2) One or both ranges ambiguously aligned.
  // In the latter case, we can obtain a result modulo alignment
  // as long as the two strides are relatively prime.
  // Otherwise, we can't know whether the two ranges intersect or not.
  var ambig = false;
  if this.isAmbiguous() || other.isAmbiguous()
  {
    var st1 = abs(this.stride);
    var st2 = abs(other.stride);
    var (g,x) = chpl__extendedEuclid(st1, st2);
    if g > 1 then
      __primitive("chpl_error", "Cannot slice ranges with ambiguous alignments unless their strides are relatively prime.");

    // OK, we can combine these two ranges, but the result is marked as ambiguous.
    ambig = true;
  }

  var temp = _base.this(other._base);
  var result = new range(temp.idxType, temp.boundedType, temp.stridable);
  result._base = temp;
  result._aligned = !ambig && (this._aligned || other._aligned);
  return result;
}

//////////////////////////////////////////////////////////////////////////////////
// syntax functions for counted ranges
//

// Creates a new range from an existing range, but with the specified number of
// elements.
// The new range has the same stride and alignment as the existing range.
// If the argument n is positive, the new range contains
// the first n elements in the existing range.
// If the argument n is negative, the new range contains
// the last abs(n) elements in the existing range.

proc #(r:range(?), i:integral)
{
  if r.isAmbiguous() then
    __primitive("chpl_error", "count -- Cannot count off elements from a range which is ambiguously aligned.");

  var temp = chpl__count(r._base, i);
  var result = new range(temp.idxType, temp.boundedType, temp.stridable);
  result._base = temp;
  result._aligned = r._aligned;
  return result;
}

//################################################################################
//# Iterators
//#
//#

iter range.these()
{
  // TODO: hilde
  // Does this test nesting affect performance?
  // Inline and remove the test if so.
  if this.isAmbiguous() then
    __primitive("chpl_error", "these -- Attempt to iterate over a range with ambiguous alignment.");
  for i in _base.these() do yield i;
}

iter range.these(param tag: iterator) where tag == iterator.leader
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "these -- Attempt to iterate over a range with ambiguous alignment.");
  for i in _base.these(iterator.leader) do yield i;
}

iter range.these(param tag: iterator, follower) where tag == iterator.follower
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "these -- Attempt to iterate over a range with ambiguous alignment.");
  for i in _base.these(iterator.follower, follower) do yield i;
}

//################################################################################
//# Utilities
//#

// Write implementation for ranges
proc range.writeThis(f: Writer)
{
  _base.writeThis(f);
}

// Return a substring of a string with a range of indices.
proc string.substring(r: range(?))
{
  if r.isAmbiguous() then
    __primitive("chpl_error", "substring -- Cannot select from a string using a range with ambiguous alignment.");

  return this.substring(r._base);
}

//################################################################################
//# Internal helper functions.
//#

pragma "inline"
proc range.chpl__unTranslate(i: idxType)
  return this - i;

pragma "inline"
proc range.chpl__unTranslate(i)
{
  if _isSignedType(i.type) then
    return this - i;
  else
    return this + abs(i);
}

  // Determine if a strided range has a definite alignment.
proc chpl__hasAlignment(r : range(?))
{
  if r.hasLowBound() && r.stride >= 2 then return true;
  if r.hasHighBound() && r.stride <= -2 then return true;
  return false;
}

// ChapelRange.chpl
//

use ChapelRangeBase;

//
// range type
//
//   parameterized by:
//        1) an integral element type,
//        2) whether low and/or high bounds exist, and
//        3) whether the stride is one or not.
//
// A range can only be aligned if it is strided.  Since alignments are taken
// modulo the stride, if the stride is one, even a nonzero alignment has no effect.
// The alignment of a range is relative to the low bound if it exists, otherwise
// relative to the high bound if it exists, otherwise absolute.
//
// The type of the stride is a signed type with the same number of bits as the
// index type.  This means that for an unsigned index type, a maximal range can
// be reached in no less than two strides.
//
// Ranges are usually naturally aligned; the _unaligned flag indicates when the
// alignment has been set explicitly -- thus making it "unaligned" w.r.t. its
// natural alignment.
//
// Some ranges have ambiguous alignment -- by definition:
//  Those which lack an upper bound and have a stride less than -1; or
//  Those which lack a lower bound and have a stride greater than 1.
// Ambiguous alignment is propagated by some operations, such as striding and slicing.
// Ambiguous alignment is erased if the alignment is set explicitly.
//
// The _aligned flag is used to track whether a range has been explicitly aligned.
// Initially, all ranges are unaligned, but since they have a stride of 1
// their alignment is not ambiguous.
// When a stride is applied, we check to see if any of the above cases is created.
// If not, the _aligned flag is set indicating that the alignment for that range
// has been determined.  Further applications of the "by" operator preserve that bit.
// The _aligned bit can also be set through the application of an explicit alignment.
//

pragma "range"
record range
{
  type idxType = int;                            // element type
  param boundedType: BoundedRangeType = BoundedRangeType.bounded; // bounded or not
  param stridable: bool = false;                 // range can be strided

  var _base : rangeBase(idxType, boundedType, stridable);
  var _aligned : bool = false;

  // TODO: hilde 2011/03/31
  // This should be a pragma and not a var declaration.
  var _promotionType: idxType;                   // enables promotion

  pragma "inline" proc low return _base.low;       // public getter for low bound
  pragma "inline" proc high return _base.high;     // public getter for high bound
  pragma "inline" proc stride return _base.stride; // public getter for stride
  // public getter for alignment
  pragma "inline" proc alignment return _base.alignment;
  // public getter for the ambiguous alignment flag.
  pragma "inline" proc aligned return _aligned;

  // Returns the starting index in the sequence.
  pragma "inline" proc first return _base.first;
  // Returns the ending index.
  pragma "inline" proc last return _base.last;
  // Returns the low index, properly aligned.
  pragma "inline" proc alignedLow : idxType return _base.alignedLow;
  // Returns the high index, properly aligned.
  pragma "inline" proc alignedHigh : idxType return _base.alignedHigh;
  // Returns the number of elements in this range.
  pragma "inline" proc length return _base.length;
}

//################################################################################
//# Constructors
//#

// Declare this as constructor, so we can capture range creation.
// If it is not a constructor, then the user can still create a maximal range
// (for example) without being warned.
//
proc range.range(type idxType = int,
                 param boundedType : BoundedRangeType = BoundedRangeType.bounded,
                 param stridable : bool = false,
                 _low : idxType = 1,
                 _high : idxType = 0,
                 _stride : chpl__signedType(idxType) = 1,
                 _alignment : idxType = 0,
                 _aligned : bool = false)
{
  _base = new rangeBase(idxType, boundedType, stridable, _low, _high, _stride, _alignment);
  this._aligned = _aligned;
}

proc range.range(type idxType = int,
                 param boundedType = BoundedRangeType.bounded,
                 param stridable : bool = false,
                 _base : rangeBase(idxType, boundedType, stridable),
                 _aligned : bool = false)
{
  this._base = _base;
  this._aligned = _aligned;
}

//////////////////////////////////////////////////////////////////////////////////
// Range builders for bounded ranges
// Range builders are used by the parser to create literal ranges.
//
proc _build_range(low: int, high: int)
  return new range(idxType = int, _low = low, _high = high);
proc _build_range(low: uint, high: uint)
  return new range(uint, _low = low, _high = high);
proc _build_range(low: int(64), high: int(64))
  return new range(int(64), _low = low, _high = high);
proc _build_range(low: uint(64), high: uint(64))
  return new range(uint(64), _low = low, _high = high);

//////////////////////////////////////////////////////////////////////////////////
// Range builders for unbounded ranges
//
proc _build_range(param bt: BoundedRangeType, bound: int)
  return new range(int, bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType, bound: uint)
  return new range(uint, bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType, bound: int(64))
  return new range(int(64), bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType, bound: uint(64))
  return new range(uint(64), bt, false, bound, bound);
proc _build_range(param bt: BoundedRangeType)
  return new range(int, bt);

//################################################################################
//# Predicates
//#

// Returns true if this range has a low bound.
proc range.hasLowBound() param
  return boundedType == BoundedRangeType.bounded ||
         boundedType == BoundedRangeType.boundedLow;

// Returns true if this range has a high bound.
proc range.hasHighBound() param
  return boundedType == BoundedRangeType.bounded ||
         boundedType == BoundedRangeType.boundedHigh;

pragma "inline"
proc range.hasFirst()
  return if isAmbiguous() then false else _base.hasFirst();

pragma "inline"
proc range.hasLast()
  return if isAmbiguous() then false else _base.hasLast();

// Returns true if this range is naturally aligned, false otherwise.
// Note that this does not indicate if the range is ambiguously aligned.
pragma "inline"
proc range.isAligned()
  return _base.isAligned();

// Returns true if the alignment of this range is ambiguous.
// After a stride whose absolute value is 2 or greater is applied,
// the alignment must be positively established as evidenced by the _aligned
// flag being set to "true".
pragma "inline"
proc range.isAmbiguous()
{
  // If the range is not strided, then its alignment is unambiguously zero.
  if !stridable then return false;
  else return abs(stride) >= 2 && !aligned;
}

// Returns true if i is in this range.
pragma "inline" proc range.member(i: idxType)
{
  if this.isAmbiguous() then return false;
  return _base.member(i);
}

// Returns true if the other range is contained within this one.
pragma "inline" proc range.member(other: range(?))
{
  if this.isAmbiguous() || other.isAmbiguous() then return false;
  return _base.member(other);
}

// Returns true if this range is equivalent to the other.
// Equivalent ranges produce the same index set.
proc ==(r1: range(?), r2: range(?))
{
  // An ambiguous ranges cannot equal an unambiguous one
  //  even if all their parameters match.
  if r1.isAmbiguous() != r2.isAmbiguous() then return false;

  // As a special case, two ambiguous ranges compare equal
  // if their representations are identical.
  if r1.isAmbiguous() then return r1.ident(r2);

  return r1._base == r2._base;
}

proc !=(r1: range(?), r2: range(?))  return !(r1 == r2);

// This makes use of the fact that the default values for the
// stride and alignment fields are consistent, whether the two ranges
// being compared are stridable or not.
proc ident(r1: range(?), r2: range(?))
  where r1.idxType == r2.idxType &&
  r1.boundedType == r2.boundedType &&
  r1.stridable == r2.stridable
{
  if r1._aligned != r2._aligned then return false;
  return ident(r1._base, r2._base);
}

// If the parameters don't match, then the two ranges cannot be identical.
proc ident(r1: range(?), r2: range(?))
  return false;

//////////////////////////////////////////////////////////////////////////////////
// Bounds checking
//
// returns true if other is in bounds of this for all specified
// bounds; these functions are used to determine if an array slice is
// valid.  We break out the boundedNone case in order to permit
// unbounded ranges to slice ranges of various index types -- otherwise
// we get a compiler error in the boundsCheck function.
//

pragma "inline"
proc range.boundsCheck(other: range(?e,?b,?s))
  where b == BoundedRangeType.boundedNone
{
  if this.isAmbiguous() || other.isAmbiguous()
    then return false;

  return true;
}

pragma "inline"
proc range.boundsCheck(other: range(?e,?b,?s))
{
  if this.isAmbiguous() || other.isAmbiguous()
    then return false;

  return _base.boundsCheck(other._base);
}

pragma "inline"
proc range.boundsCheck(other: idxType)
  return member(other);

//################################################################################
//# Member functions
//#

// Moves the low bound of the range up to the next alignment point.
proc range.alignLow()
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "alignLow -- Canot be applied to a range with ambiguous alignment.");

  _base.alignLow();
  return this;
}

// Moves the high bound of the range down to the next alignment point.
proc range.alignHigh()
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "alignHigh -- Canot be applied to a range with ambiguous alignment.");

  _base.alignHigh();
  return this;
}

// Returns the ordinal of this index within the sequence described by this range.
proc range.indexOrder(i: idxType)
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "indexOrder -- Undefined on a range with ambiguous alignment.");

  return _base.indexOrder(i);
}

//////////////////////////////////////////////////////////////////////////////////
// translate the indices in this range by i
// A range can be translated even if its alignment is ambiguous.
//
pragma "inline"
proc range.translate(i: integral)
  return new range(idxType, boundedType, stridable,
                   _base.translate(i), _aligned);

pragma "inline"
proc range.translate(i)
{
  compilerError("offsets must be of integral type");
}

// Return an interior portion of this range.
pragma "inline"
proc range.interior(i: idxType)
  return new range(idxType, boundedType, stridable,
                    _base.interior(i), _aligned);

// Return an exterior portion of this range.
pragma "inline"
proc range.exterior(i: idxType)
  return new range(idxType, boundedType, stridable,
                   _base.exterior(i), _aligned);

// Returns an expanded range, or a contracted range if i < 0.
// The existing absolute alignment is preserved.
pragma "inline"
proc range.expand(i: idxType)
  return new range(idxType, boundedType, stridable,
                   _base.expand(i), _aligned);

//################################################################################
//# Syntax Functions
//# These are special functions known to the compiler parser.
//#

// Assignment
pragma "inline"
proc =(r1: range(stridable=?s1), r2: range(stridable=?s2))
{
  r1._base = r2._base;
  r1._aligned = r2._aligned;
  return r1;
}

//////////////////////////////////////////////////////////////////////////////////
// Range arithmetic.
//
// Shifts and entire range to the right or left.
// Absolute alignment is not preserved
// (That is, the alignment shifts along with the range.)
//
pragma "inline"
proc +(r: range(?e, ?b, ?s), i: integral)
{
  var temp = r._base + i;
  return new range(temp.idxType, b, s, temp, r._aligned);
}

pragma "inline"
proc +(i:integral, r: range(?e,?b,?s))
  return r + i;

pragma "inline"
proc -(r: range(?e,?b,?s), i: integral)
{
  var temp = r._base - i;
  return new range(temp.idxType, b, s, temp, r._aligned);
}

// This is the syntax processing routine for the "by" keyword.
// The by operator always clobbers an existing alignment.
proc by(r : range(?), str)
{
  var temp = chpl__by(r._base, str);
  var result = new range(temp.idxType, temp.boundedType, temp.stridable);
  result._base = temp;
  result._aligned = r._aligned || chpl__hasAlignment(result);
  return result;
}

// This is the syntax processing routine for the "align" keyword.
// It produces a new range with the specified alignment.
// By definition, alignment is relative to the low bound of the range.
pragma "inline"
proc align(r : range(?e, ?b, ?s), algn)
  return new range(e, b, s, chpl__align(r._base, algn), true);

// Apply a natural alignment to an existing range.
proc range.offset(offs : integral)
{
  _base.offset(offs);
  this._aligned = true;
  return this;
}

// Composition
// Return the intersection of this and other.
proc range.this(other: range(?))
{
  // Two cases to consider:
  //  1) Both ranges unambiguously aligned
  //  2) One or both ranges ambiguously aligned.
  // In the latter case, we can obtain a result modulo alignment
  // as long as the two strides are relatively prime.
  // Otherwise, we can't know whether the two ranges intersect or not.
  var ambig = false;
  if this.isAmbiguous() || other.isAmbiguous()
  {
    var st1 = abs(this.stride);
    var st2 = abs(other.stride);
    var (g,x) = chpl__extendedEuclid(st1, st2);
    if g > 1 then
      __primitive("chpl_error", "Cannot slice ranges with ambiguous alignments unless their strides are relatively prime.");

    // OK, we can combine these two ranges, but the result is marked as ambiguous.
    ambig = true;
  }

  var temp = _base.this(other._base);
  var result = new range(temp.idxType, temp.boundedType, temp.stridable);
  result._base = temp;
  result._aligned = !ambig && (this._aligned || other._aligned);
  return result;
}

//////////////////////////////////////////////////////////////////////////////////
// syntax functions for counted ranges
//

// Creates a new range from an existing range, but with the specified number of
// elements.
// The new range has the same stride and alignment as the existing range.
// If the argument n is positive, the new range contains
// the first n elements in the existing range.
// If the argument n is negative, the new range contains
// the last abs(n) elements in the existing range.

proc #(r:range(?), i:integral)
{
  if r.isAmbiguous() then
    __primitive("chpl_error", "count -- Cannot count off elements from a range which is ambiguously aligned.");

  var temp = chpl__count(r._base, i);
  var result = new range(temp.idxType, temp.boundedType, temp.stridable);
  result._base = temp;
  result._aligned = r._aligned;
  return result;
}

//################################################################################
//# Iterators
//#
//#

iter range.these()
{
  // TODO: hilde
  // Does this test nesting affect performance?
  // Inline and remove the test if so.
  if this.isAmbiguous() then
    __primitive("chpl_error", "these -- Attempt to iterate over a range with ambiguous alignment.");
  for i in _base.these() do yield i;
}

iter range.these(param tag: iterator) where tag == iterator.leader
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "these -- Attempt to iterate over a range with ambiguous alignment.");
  for i in _base.these(iterator.leader) do yield i;
}

iter range.these(param tag: iterator, follower) where tag == iterator.follower
{
  if this.isAmbiguous() then
    __primitive("chpl_error", "these -- Attempt to iterate over a range with ambiguous alignment.");
  for i in _base.these(iterator.follower, follower) do yield i;
}

//################################################################################
//# Utilities
//#

// Write implementation for ranges
proc range.writeThis(f: Writer)
{
  _base.writeThis(f);
}

// Return a substring of a string with a range of indices.
proc string.substring(r: range(?))
{
  if r.isAmbiguous() then
    __primitive("chpl_error", "substring -- Cannot select from a string using a range with ambiguous alignment.");

  return this.substring(r._base);
}

//################################################################################
//# Internal helper functions.
//#

pragma "inline"
proc range.chpl__unTranslate(i: idxType)
  return this - i;

pragma "inline"
proc range.chpl__unTranslate(i)
{
  if _isSignedType(i.type) then
    return this - i;
  else
    return this + abs(i);
}

  // Determine if a strided range has a definite alignment.
proc chpl__hasAlignment(r : range(?))
{
  if r.hasLowBound() && r.stride >= 2 then return true;
  if r.hasHighBound() && r.stride <= -2 then return true;
  return false;
}


Added some very simple error handling

Added some very simple error handling

/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use Sort;

//
// This module defines several iterators that are designed to help
// support reasoning about directory and file contents.  At present,
// all are serial and single-locale, though the ultimate intention
// is to also support parallel and multi-locale options.
//
// These interfaces should be considered experimental and subject to
// change for the 1.10 release.  For that reason, send in feedback if
// you would like to see changes or additional arguments/features.
// And, as always, send in bug reports if you think we got something
// wrong.
//

/* iter listdir(path: string, hidden=false, dirs=true, files=true,
                listlinks=true): string

    listdir() lists the contents of a directory, similar to 'ls'
      * path: the directory whose contents should be listed
      * hidden: should hidden files/directories be listed?
      * dirs: should dirs be listed?
      * files: should files be listed?
      * listlinks: should symbolic links be listed?

   By default this routine lists all files and directories in the
   current directory, including symbolic links, as long as they don't
   start with '.'
*/

iter listdir(path: string, hidden=false, dirs=true, files=true,
             listlinks=true): string {
  extern type DIRptr;
  extern type direntptr;
  extern proc opendir(name: c_string): DIRptr;
  extern proc readdir(dirp: DIRptr): direntptr;
  extern proc closedir(dirp: DIRptr): c_int;

  proc direntptr.d_name(): c_string {
    extern proc chpl_rt_direntptr_getname(d: direntptr): c_string;

    return chpl_rt_direntptr_getname(this);
  }

  var dir: DIRptr;
  var ent: direntptr;
  dir = opendir(path:c_string);
  if (!is_c_nil(dir)) {
    ent = readdir(dir);
    while (!is_c_nil(ent)) {
      const filename = ent.d_name();
      if (hidden || filename.substring(1) != '.') {
        if (filename != "." && filename != "..") {
          //
          // use FileSystem;  // Doesn't work, see comment below
          //
          const fullpath = path + "/" + filename;
          {
            //
            // The use of this compound statement to restrict the
            // impact of the 'use' of FileSystem is unfortunate
            // (compared to placing it in the more logical place
            // above), yet seemingly required at present; otherwise
            // the 'path' argument gets shadowed by a
            // (compiler-introduced?) method coming from one of the
            // standard or internal modules.  See
            // test/modules/bradc/useFileSystemShadowsPath.chpl for
            // a smaller standalone test exhibiting the issue (or
            // uncomment the 'use' above to see it here).
            //
            use FileSystem;

            if (listlinks || !isLink(fullpath)) {
              if (dirs && isDir(fullpath)) then
                yield filename;
              else if (files && isFile(fullpath)) then
                yield filename;
            }
          }
        }
      }
      ent = readdir(dir);
    }
    closedir(dir);
  } else {
    extern proc perror(s: c_string);
    perror("error in listdir(): ");
  }
}

/* iter walkdirs(path: string=".", topdown=true, depth=max(int),
                 hidden=false, followlinks=false, sort=false): string

   walkdirs() recursively walks a directory structure, yielding
   directory names.  The strings that are generated will be rooted
   from 'path'.

     * path: the directory to start from
     * topdown: indicates whether to yield the directories using a
       preorder (vs. postorder) traversal
     * depth: indicates the maximal depth of recursion to use
     * hidden: indicates whether to enter hidden directories
     * followlinks: indicates whether to follow symbolic links or not
     * sort: indicates whether to consider subdirectories in sorted
       order or not

   by default, walkdirs() will start in the current directory, process
   directories in preorder; recursively traverse subdirectories; and
   neither follow dotfile directories nor symbolic links.  It will not
   sort the directories by default.
*/

iter walkdirs(path: string=".", topdown=true, depth=max(int), hidden=false,
              followlinks=false, sort=false): string {

  if (topdown) then
    yield path;

  if (depth) {
    var subdirs = listdir(path, hidden=hidden, files=false, listlinks=followlinks);
    if (sort) then
      QuickSort(subdirs);
    for subdir in subdirs {
      const fullpath = path + "/" + subdir;
      for subdir in walkdirs(fullpath, topdown, depth-1, hidden,
                             followlinks, sort) do
        yield subdir;
    }
  }

  if (!topdown) then
    yield path;
}

//
// Here's a parallel version
//
iter walkdirs(path: string=".", topdown=true, depth=max(int), hidden=false,
              followlinks=false, sort=false, param tag: iterKind): string
       where tag == iterKind.standalone {

  if (sort) then
    warning("sorting has no effect for parallel invocations of walkdirs()");

  if (topdown) then
    yield path;

  if (depth) {
    var subdirs = listdir(path, hidden=hidden, files=false, listlinks=followlinks);
    forall subdir in subdirs {
      const fullpath = path + "/" + subdir;
      //
      // Call standalone walkdirs() iterator recursively; set sort=false since it is
      // not useful and we've already printed the warning
      //
      for subdir in walkdirs(fullpath, topdown, depth-1, hidden, followlinks, sort=false, iterKind.standalone) do
        yield subdir;
    }
  }

  if (!topdown) then
    yield path;
}

/* iter glob(pattern="*")

   glob() gives glob() capabilities and is implemented using C's glob()

     * pattern: the glob pattern to match against

   By default, it will list all files/directories in the current directory
*/

module Chpl_rt_glob {
  extern type glob_t;

  extern const GLOB_NOMATCH: c_int;

  extern proc chpl_glob(pattern:c_string, flags: c_int,
                        ref ret_glob:glob_t):c_int;
  extern proc chpl_glob_num(x:glob_t): size_t;
  extern proc chpl_glob_index(x:glob_t, idx:size_t): c_string;
  extern proc globfree(ref glb:glob_t);
}

iter glob(pattern="*") {
  var glb : Chpl_rt_glob.glob_t;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  // TODO: Handle error cases better
  if (err != 0 && err != Chpl_rt_glob.GLOB_NOMATCH) then
    __primitive("chpl_error", "unhandled error in glob()");
  const num = Chpl_rt_glob.chpl_glob_num(glb);
  if (num) then
    for i in 0..num-1 do
      yield Chpl_rt_glob.chpl_glob_index(glb, i): string;

  Chpl_rt_glob.globfree(glb);
}

iter glob(pattern:string="*", param tag: iterKind)
       where tag == iterKind.standalone {
  var glb : Chpl_rt_glob.glob_t;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  // TODO: Handle error cases better
  if (err != 0 && err != Chpl_rt_glob.GLOB_NOMATCH) then
    __primitive("chpl_error", "unhandled error in glob()");
  const num = Chpl_rt_glob.chpl_glob_num(glb);
  if (num) then
    forall i in 0..num-1 do
      yield Chpl_rt_glob.chpl_glob_index(glb, i): string;

  Chpl_rt_glob.globfree(glb);
}

//
// TODO: The following leader/follower iterator assumes that
// the file system state won't change between calls because
// it calls the glob routines twice and assumes the same
// result will come back.  In leader-follower 2.0, we would
// like to store such state between calls in which case this
// should be rewritten to do so (and would require freeing
// the state at the end of the call).
//
iter glob(pattern:string="*", param tag: iterKind)
       where tag == iterKind.leader {
  var glb : Chpl_rt_glob.glob_t;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  // TODO: Handle error cases better
  if (err != 0 && err != Chpl_rt_glob.GLOB_NOMATCH) then
    __primitive("chpl_error", "unhandled error in glob()");
  //
  // cast is used here to ensure we create an int-based leader
  //
  const num = Chpl_rt_glob.chpl_glob_num(glb).safeCast(int);
  if (num) {
    Chpl_rt_glob.globfree(glb);

    //
    // Forward to the range type's leader
    //
    for followThis in (0..num-1).these(tag) do
      yield followThis;
  }
}

iter glob(pattern:string="*", followThis, param tag: iterKind)
       where tag == iterKind.follower {
  var glb : Chpl_rt_glob.glob_t;
  if (followThis.size != 1) then
    compilerError("glob() iterator can only be zipped with 1D iterators");
  var (r,) = followThis;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  // TODO: Handle error cases better
  if (err != 0 && err != Chpl_rt_glob.GLOB_NOMATCH) then
    __primitive("chpl_error", "unhandled error in glob()");
  const num = Chpl_rt_glob.chpl_glob_num(glb);
  if (r.high > num.safeCast(int)) then
    halt("glob() iterator zipped with something too big");
  if (num) then
    for i in r do
      //
      // safe cast is used here to turn an int into a size_t
      //
      yield Chpl_rt_glob.chpl_glob_index(glb, i.safeCast(size_t)): string;

  Chpl_rt_glob.globfree(glb);
}

/* iter findfiles(startdir = ".", recursive=false, hidden=false)

   findfiles() is a simple find-like utility implemented using the
   above routines

     * startdir: where to start when looking for files
     * recursive: tells whether or not to descend recurisvely
     * hidden: tells whether or not to yield hidden
*/

iter findfiles(startdir = ".", recursive=false, hidden=false) {
  if (recursive) then
    for subdir in walkdirs(startdir, hidden=hidden) do
      for file in listdir(subdir, hidden=hidden, dirs=false, files=true, listlinks=true) do
        yield subdir+"/"+file;
  else
    for file in listdir(startdir, hidden=hidden, dirs=false, files=true, listlinks=false) do
      yield startdir+"/"+file;
}

iter findfiles(startdir = ".", recursive=false, hidden=false, param tag: iterKind) where tag == iterKind.standalone {
  if (recursive) then
    forall subdir in walkdirs(startdir, hidden=hidden) do
      for file in listdir(subdir, hidden=hidden, dirs=false, files=true, listlinks=true) do
        yield subdir+"/"+file;
  else
    for file in listdir(startdir, hidden=hidden, dirs=false, files=true, listlinks=false) do
      yield startdir+"/"+file;
}

/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use Sort;

//
// This module defines several iterators that are designed to help
// support reasoning about directory and file contents.  At present,
// all are serial and single-locale, though the ultimate intention
// is to also support parallel and multi-locale options.
//
// These interfaces should be considered experimental and subject to
// change for the 1.10 release.  For that reason, send in feedback if
// you would like to see changes or additional arguments/features.
// And, as always, send in bug reports if you think we got something
// wrong.
//

/* iter listdir(path: string, hidden=false, dirs=true, files=true,
                listlinks=true): string

    listdir() lists the contents of a directory, similar to 'ls'
      * path: the directory whose contents should be listed
      * hidden: should hidden files/directories be listed?
      * dirs: should dirs be listed?
      * files: should files be listed?
      * listlinks: should symbolic links be listed?

   By default this routine lists all files and directories in the
   current directory, including symbolic links, as long as they don't
   start with '.'
*/

iter listdir(path: string, hidden=false, dirs=true, files=true,
             listlinks=true): string {
  extern type DIRptr;
  extern type direntptr;
  extern proc opendir(name: c_string): DIRptr;
  extern proc readdir(dirp: DIRptr): direntptr;
  extern proc closedir(dirp: DIRptr): c_int;

  proc direntptr.d_name(): c_string {
    extern proc chpl_rt_direntptr_getname(d: direntptr): c_string;

    return chpl_rt_direntptr_getname(this);
  }

  var dir: DIRptr;
  var ent: direntptr;
  dir = opendir(path:c_string);
  if (!is_c_nil(dir)) {
    ent = readdir(dir);
    while (!is_c_nil(ent)) {
      const filename = ent.d_name();
      if (hidden || filename.substring(1) != '.') {
        if (filename != "." && filename != "..") {
          //
          // use FileSystem;  // Doesn't work, see comment below
          //
          const fullpath = path + "/" + filename;
          {
            //
            // The use of this compound statement to restrict the
            // impact of the 'use' of FileSystem is unfortunate
            // (compared to placing it in the more logical place
            // above), yet seemingly required at present; otherwise
            // the 'path' argument gets shadowed by a
            // (compiler-introduced?) method coming from one of the
            // standard or internal modules.  See
            // test/modules/bradc/useFileSystemShadowsPath.chpl for
            // a smaller standalone test exhibiting the issue (or
            // uncomment the 'use' above to see it here).
            //
            use FileSystem;

            if (listlinks || !isLink(fullpath)) {
              if (dirs && isDir(fullpath)) then
                yield filename;
              else if (files && isFile(fullpath)) then
                yield filename;
            }
          }
        }
      }
      ent = readdir(dir);
    }
    closedir(dir);
  } else {
    extern proc perror(s: c_string);
    perror("error in listdir(): ");
  }
}

/* iter walkdirs(path: string=".", topdown=true, depth=max(int),
                 hidden=false, followlinks=false, sort=false): string

   walkdirs() recursively walks a directory structure, yielding
   directory names.  The strings that are generated will be rooted
   from 'path'.

     * path: the directory to start from
     * topdown: indicates whether to yield the directories using a
       preorder (vs. postorder) traversal
     * depth: indicates the maximal depth of recursion to use
     * hidden: indicates whether to enter hidden directories
     * followlinks: indicates whether to follow symbolic links or not
     * sort: indicates whether to consider subdirectories in sorted
       order or not

   by default, walkdirs() will start in the current directory, process
   directories in preorder; recursively traverse subdirectories; and
   neither follow dotfile directories nor symbolic links.  It will not
   sort the directories by default.
*/

iter walkdirs(path: string=".", topdown=true, depth=max(int), hidden=false,
              followlinks=false, sort=false): string {

  if (topdown) then
    yield path;

  if (depth) {
    var subdirs = listdir(path, hidden=hidden, files=false, listlinks=followlinks);
    if (sort) then
      QuickSort(subdirs);
    for subdir in subdirs {
      const fullpath = path + "/" + subdir;
      for subdir in walkdirs(fullpath, topdown, depth-1, hidden,
                             followlinks, sort) do
        yield subdir;
    }
  }

  if (!topdown) then
    yield path;
}

//
// Here's a parallel version
//
iter walkdirs(path: string=".", topdown=true, depth=max(int), hidden=false,
              followlinks=false, sort=false, param tag: iterKind): string
       where tag == iterKind.standalone {

  if (sort) then
    warning("sorting has no effect for parallel invocations of walkdirs()");

  if (topdown) then
    yield path;

  if (depth) {
    var subdirs = listdir(path, hidden=hidden, files=false, listlinks=followlinks);
    forall subdir in subdirs {
      const fullpath = path + "/" + subdir;
      //
      // Call standalone walkdirs() iterator recursively; set sort=false since it is
      // not useful and we've already printed the warning
      //
      for subdir in walkdirs(fullpath, topdown, depth-1, hidden, followlinks, sort=false, iterKind.standalone) do
        yield subdir;
    }
  }

  if (!topdown) then
    yield path;
}

/* iter glob(pattern="*")

   glob() gives glob() capabilities and is implemented using C's glob()

     * pattern: the glob pattern to match against

   By default, it will list all files/directories in the current directory
*/

module Chpl_rt_glob {
  extern type glob_t;
  extern proc chpl_glob(pattern:c_string, flags: c_int,
                        ref ret_glob:glob_t):c_int;
  extern proc chpl_glob_num(x:glob_t): size_t;
  extern proc chpl_glob_index(x:glob_t, idx:size_t): c_string;
  extern proc globfree(ref glb:glob_t);
}

iter glob(pattern="*") {
  var glb : Chpl_rt_glob.glob_t;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  const num = Chpl_rt_glob.chpl_glob_num(glb);
  if (num) then
    for i in 0..num-1 do
      yield Chpl_rt_glob.chpl_glob_index(glb, i): string;

  Chpl_rt_glob.globfree(glb);
}

iter glob(pattern:string="*", param tag: iterKind)
       where tag == iterKind.standalone {
  var glb : Chpl_rt_glob.glob_t;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  const num = Chpl_rt_glob.chpl_glob_num(glb);
  if (num) then
    forall i in 0..num-1 do
      yield Chpl_rt_glob.chpl_glob_index(glb, i): string;

  Chpl_rt_glob.globfree(glb);
}

//
// TODO: The following leader/follower iterator assumes that
// the file system state won't change between calls because
// it calls the glob routines twice and assumes the same
// result will come back.  In leader-follower 2.0, we would
// like to store such state between calls in which case this
// should be rewritten to do so (and would require freeing
// the state at the end of the call).
//
iter glob(pattern:string="*", param tag: iterKind)
       where tag == iterKind.leader {
  var glb : Chpl_rt_glob.glob_t;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  //
  // cast is used here to ensure we create an int-based leader
  //
  const num = Chpl_rt_glob.chpl_glob_num(glb).safeCast(int);
  if (num) {
    Chpl_rt_glob.globfree(glb);

    //
    // Forward to the range type's leader
    //
    for followThis in (0..num-1).these(tag) do
      yield followThis;
  }
}

iter glob(pattern:string="*", followThis, param tag: iterKind)
       where tag == iterKind.follower {
  var glb : Chpl_rt_glob.glob_t;
  if (followThis.size != 1) then
    compilerError("glob() iterator can only be zipped with 1D iterators");
  var (r,) = followThis;

  const err = Chpl_rt_glob.chpl_glob(pattern:c_string, 0, glb);
  const num = Chpl_rt_glob.chpl_glob_num(glb);
  if (r.high > num.safeCast(int)) then
    halt("glob() iterator zipped with something too big");
  if (num) then
    for i in r do
      //
      // safe cast is used here to turn an int into a size_t
      //
      yield Chpl_rt_glob.chpl_glob_index(glb, i.safeCast(size_t)): string;

  Chpl_rt_glob.globfree(glb);
}

/* iter findfiles(startdir = ".", recursive=false, hidden=false)

   findfiles() is a simple find-like utility implemented using the
   above routines

     * startdir: where to start when looking for files
     * recursive: tells whether or not to descend recurisvely
     * hidden: tells whether or not to yield hidden
*/

iter findfiles(startdir = ".", recursive=false, hidden=false) {
  if (recursive) then
    for subdir in walkdirs(startdir, hidden=hidden) do
      for file in listdir(subdir, hidden=hidden, dirs=false, files=true, listlinks=true) do
        yield subdir+"/"+file;
  else
    for file in listdir(startdir, hidden=hidden, dirs=false, files=true, listlinks=false) do
      yield startdir+"/"+file;
}

iter findfiles(startdir = ".", recursive=false, hidden=false, param tag: iterKind) where tag == iterKind.standalone {
  if (recursive) then
    forall subdir in walkdirs(startdir, hidden=hidden) do
      for file in listdir(subdir, hidden=hidden, dirs=false, files=true, listlinks=true) do
        yield subdir+"/"+file;
  else
    for file in listdir(startdir, hidden=hidden, dirs=false, files=true, listlinks=false) do
      yield startdir+"/"+file;
}


Remove an extraneous space character.

Remove an extraneous space character.

/*
 * Copyright 2004-2014 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
For more information, see "User-Defined Parallel Zippered iterators
in Chapel". Bradford L. Chamberlain, Sung-Eun Choi, Steven J. Deitz,
Angeles Navarro. PGAS 2011: Fifth Conference on Partitioned Global
Address Space Programming Models, October 2011.
*/

record vlock {
  var l: atomic bool;
  proc lock() {
    on this do while l.testAndSet() != false do chpl_task_yield();
  }
  proc unlock() {
    l.write(false);
  }
}

config param debugAdvancedIters:bool=false;

//************************* Dynamic iterator

// Serial iterator

iter dynamic(c:range(?), chunkSize:int, numTasks:int=0) {

  if debugAdvancedIters then
    writeln("Serial dynamic Iterator. Working with range ", c);

  for i in c do yield i;
}

// Parallel iterator

// Leader iterator

iter dynamic(param tag:iterKind, c:range(?), chunkSize:int, numTasks:int=0)
where tag == iterKind.leader
{
  assert(chunkSize > 0); // caller's responsibility

  use UtilMath;
  // # of tasks the range can fill. (fast) ceil so all work is represented
  const chunkTasks = divceilpos(c.length, chunkSize): int;

  // Check if the number of tasks is 0, in that case it returns a default value
  const nTasks = min(chunkTasks, defaultNumTasks(numTasks));

  type rType=c.type;

  // We're going to have to densify at some point, might as well
  // do it early and make range slicing easier.
  const remain:rType=densify(c,c);

  // If the number of tasks is insufficient, yield in serial
  if c.length == 0 then halt("The range is empty");
  if nTasks == 1 then {
    if debugAdvancedIters then
      writeln("Dynamic Iterator: serial execution because there is not enough work");
    yield (remain,);
  } else {
    var moreWork : bool =true;
    var curIndex : atomic remain.low.type;
    curIndex.write(remain.low);

    coforall tid in 0..#nTasks ref(remain, moreWork,curIndex) do {
      while moreWork do {
        // There is local work in remain
        const low = curIndex.fetchAdd(chunkSize);
        var high = low + chunkSize-1;

        if low > remain.high {
          break;
        } else if high > remain.high {
          high = remain.high;
          moreWork = false;
        }

        const current:rType = remain(low .. high);

        if high >= low then {
          if debugAdvancedIters then
            writeln("Parallel dynamic Iterator. Working at tid ", tid, " with range ", unDensify(current,c), " yielded as ", current);
          yield (current,);
        }
      }
    }
  }
}

// Follower
iter dynamic(param tag:iterKind, c:range(?), chunkSize:int, numTasks:int, followThis)
where tag == iterKind.follower
{
  type rType=c.type;
  const current:rType=unDensify(followThis(1),c);
  if debugAdvancedIters then
    writeln("Follower received range ", followThis, " ; shifting to ", current);
  for i in current do {
    yield i;
  }
}

//************************* Guided iterator
//Serial iterator
iter guided(c:range(?), numTasks:int=0) {

  if debugAdvancedIters then
    writeln("Serial guided Iterator. Working with range ", c);

  for i in c do yield i;
}

// Parallel iterator

// Leader iterator
iter guided(param tag:iterKind, c:range(?), numTasks:int=0)
where tag == iterKind.leader
{
  // Check if the number of tasks is 0, in that case it returns a default value
  const nTasks=min(c.length, defaultNumTasks(numTasks));
  type rType=c.type;
  var remain:rType = densify(c,c);
  // If the number of tasks is insufficient, yield in serial
  if c.length == 0 then halt("The range is empty");
  if nTasks == 1 then {
    if debugAdvancedIters then
      writeln("Guided Iterator: serial execution because there is not enoguh work");
    yield (remain,);
  }

  else {
    var undone=true;
    const factor=nTasks;
    var lock : vlock;

    coforall tid in 0..#nTasks ref(remain,undone, lock) do {
      while undone do {
        // There is local work in remain(tid)
        const current:rType=adaptSplit(remain, factor, undone, lock);
        if current.length !=0 then {
          if debugAdvancedIters then
            writeln("Parallel guided Iterator. Working at tid ", tid, " with range ", unDensify(current,c), " yielded as ", current);
          yield (current,);
        }
      }
    }
  }
}

// Follower
iter guided(param tag:iterKind, c:range(?), numTasks:int, followThis)
where tag == iterKind.follower

{
  type rType=c.type;
  const current:rType=unDensify(followThis(1),c);
  if debugAdvancedIters then
    writeln("Follower received range ", followThis, " ; shifting to ", current);
  for i in current do {
    yield i;
  }
}

//************************* Adaptive work-stealing iterator
//Serial iterator
iter adaptive(c:range(?), numTasks:int=0) {

  if debugAdvancedIters then
    writeln("Serial adaptive work-stealing Iterator. Working with range ", c);

  for i in c do yield i;

}

// Parallel iterator

enum Method {
  Whole = 0,            // Steal until range is exhausted
  RoundRobin = 1,       // Steal from a different victim every time
  WholeTail = 2         // Steal from the tail until range is exhausted
};

config param methodStealing = Method.Whole;

// Leader iterator
iter adaptive(param tag:iterKind, c:range(?), numTasks:int=0)
where tag == iterKind.leader

{
  /*if (methodStealing != Method.Whole || methodStealing != Method.WholeTail) then
    compilerError("methodStealing value must be between 0 and 2");*/

  // Check if the number of tasks is 0, in that case it returns a default value
  const nTasks=min(c.length, defaultNumTasks(numTasks));
  type rType=c.type;

  // If the number of tasks is insufficient, yield in serial
  if c.length == 0 then halt("The range is empty");
  if nTasks == 1 then {
    if debugAdvancedIters then
      writeln("Adaptive work-stealing Iterator: serial execution because there is not enough work");
    yield (densify(c,c),);

  }
  else {
    const r:rType=densify(c,c);
    const SpaceThreads:domain(1)=0..#nTasks;
    var localWork:[SpaceThreads] rType; // The remaining range to split on each Thread
    var moreLocalWork:[SpaceThreads] bool=true; // bool var to signal there is still work on each local range
    var locks:[SpaceThreads] vlock; // sync var to control the splitting on each Thread
    const factor:int=2;

    const factorSteal:int=2;
    var moreWork:bool=true; // A global var to control the termination

    // Variables to put a barrier to ensure the initial range is computed on each Thread
    var barrier : atomic int;

    // Start the parallel work
    coforall tid in 0..#nTasks ref(localWork, moreLocalWork, moreWork, r) do {

      // Step 1: Initial range per Thread/Task

      // Initial Local range in localWork[tid]
      const chunkSize = c.length/nTasks;
      localWork[tid]=
      if tid==nTasks-1 then
        r#(chunkSize*(nTasks-1)-r.length)
      else
        (r+tid*chunkSize)#chunkSize;
      barrier.add(1);

      if debugAdvancedIters then
        writeln("Parallel adaptive work-stealing Iterator. Working at tid ", tid, " with initial range ", localWork[tid]);

      // A barrier waiting for each thread to finish the initial assignment
      barrier.waitFor(nTasks);

      // Step 2: While there is work at tid, do splitting

      while moreLocalWork[tid] do {
        // There is local work
        // The current range we get after splitting locally
        const zeroBasedIters:rType=adaptSplit(localWork[tid], factorSteal, moreLocalWork[tid], locks[tid]);
        if zeroBasedIters.length !=0 then {
          if debugAdvancedIters then
            writeln("Parallel adaptive Iterator. Working locally at tid ", tid, " with range yielded as ", zeroBasedIters);
          yield (zeroBasedIters,);
        }
      }

      // Step3: Task tid finished its work, so it will try to steal from a neighbor

      var nVisitedVictims:int=0;
      var victim=(tid+1) % nTasks;
      var stealFailed:bool=false;

      while moreWork do {
        if debugAdvancedIters then
          writeln("Entering at Stealing phase in tid ", tid," with victim ", victim, " using method of Stealing ", methodStealing);

        // Perform the spliting at the victim remaining range

        if methodStealing == Method.RoundRobin {
          if moreLocalWork[victim] then {
            // There is work in victim
            const zeroBasedIters2:rType=adaptSplit(localWork[victim], factorSteal, moreLocalWork[victim], locks[victim]);
            if zeroBasedIters2.length !=0 then {
              if debugAdvancedIters then
                writeln("Range stealed at victim ", victim," yielded as ", zeroBasedIters2," by tid ", tid);
              yield (zeroBasedIters2,);
            }
          } else {
            stealFailed=true;
          }
        } else {
          while moreLocalWork[victim] do {
            // There is work in victim
            const zeroBasedIters2:rType=adaptSplit(localWork[victim], factorSteal, moreLocalWork[victim], locks[victim], methodStealing==Method.WholeTail);
                                          //after splitting from a victim range
            if zeroBasedIters2.length !=0 then {
              if debugAdvancedIters then
                writeln("Range stealed at victim ", victim," yielded as ", zeroBasedIters2," by tid ", tid);
              yield (zeroBasedIters2,);
            }
          }
        }

        // If here, then it can have failed the stealing intent at the victim (method 1),
        // or we have exhausted the victim range (methods 0, 2)

        if (methodStealing==Method.Whole || methodStealing==Method.WholeTail || (methodStealing==Method.RoundRobin && stealFailed)) then {
          nVisitedVictims += 1; // Signal that there is no more work in victim
          stealFailed=false;
          if debugAdvancedIters then
            writeln("Failed Stealing intent at tid ", tid," with victim ", victim, " and total no. of visited victims ", nVisitedVictims);
        }
        // Check if there is no more work
        if nVisitedVictims >= nTasks-1 then
          moreWork=false; // Signal that there is no more work in any victim
        else {  // There can be still work in other victim
          victim=(victim+1) % nTasks; // New victim to steal
          if methodStealing==Method.RoundRobin && victim==tid then
            victim=(victim+1) % nTasks;
        }
      }
    }
  }
}

// Follower
iter adaptive(param tag:iterKind, c:range(?), numTasks:int, followThis)
where tag == iterKind.follower
{
  type rType=c.type;
  var current:rType=unDensify(followThis(1),c);
  if debugAdvancedIters then
    writeln("Follower received range ", followThis, " ; shifting to ", current);
  for i in current do {
    yield i;
  }
}

//************************* Helper functions
proc defaultNumTasks(nTasks:int)
{
  var dnTasks=nTasks;
  if nTasks==0 then {
    if dataParTasksPerLocale==0 then dnTasks=here.maxTaskPar;
      else dnTasks=dataParTasksPerLocale;
  } else if nTasks<0 then {
    halt("'numTasks' is negative");
  }
  return dnTasks;
}

proc adaptSplit(ref rangeToSplit:range(?), splitFactor:int, ref itLeft:bool, ref lock : vlock, splitTail:bool=false)
{
  type rType=rangeToSplit.type;
  type lenType=rangeToSplit.length.type;
  var totLen, size:lenType;
  const profThreshold=1;

  lock.lock();
  totLen=rangeToSplit.length;
  if totLen > profThreshold then
    size=max(totLen/splitFactor, profThreshold);
  else {
    size=totLen;
    itLeft=false;}
  const direction = if splitTail then -1 else 1;
  const firstRange:rType=rangeToSplit#(direction*size);
  rangeToSplit=rangeToSplit#(direction*(size-totLen));
  lock.unlock();
  return firstRange;
}


Removed calls to startVerboseComm and stopVerboseComm that I accidentally left
in with revision 15501.

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

//
// Use standard modules for Block distributions and Timing routines
//
use MultiBlockDist, Time;

//
// Use the user modules for computing HPCC problem sizes and for
// defining RA's random stream of values
//
use HPCCProblemSize, RARandomStream;

//
// The number of tables as well as the element and index types of
// that table
//
const numTables = 1;
type elemType = randType,
     indexType = randType;

//
// Configuration constants defining log2(problem size) -- n -- and
// the number of updates -- N_U
//
config const n = computeProblemSize(numTables, elemType,
                                    returnLog2=true, retType=indexType),
             N_U = 2**(n+2);

//
// Constants defining the problem size (m) and a bit mask for table
// indexing
//
const m = 2**n,
      indexMask = m-1;

//
// Configuration constant defining the number of errors to allow (as a
// fraction of the number of updates, N_U)
//
config const errorTolerance = 1e-2;

//
// The number of tasks to use per Chapel locale
//
config const tasksPerLocale = min reduce Locales.numCores;

//
// Configuration constants to control what's printed -- benchmark
// parameters, input and output arrays, and/or statistics
//
config const printParams = true,
             printArrays = false,
             printStats = true;

//
// TableDist is a 1D block distribution for domains storing indices
// of type "indexType", and it is computed by blocking the bounding
// box 0..m-1 across the set of locales.  UpdateDist is a similar
// distribution that is computed by blocking the indices 0..N_U-1
// across the locales.
//
const TableDist = new Block(1, indexType, bbox=[0..m-1],
                            tasksPerLocale=tasksPerLocale),
      UpdateDist = new Block(1, indexType, bbox=[0..N_U-1],
                             tasksPerLocale=tasksPerLocale);

//
// TableSpace describes the index set for the table.  It is a 1D
// domain storing indices of type indexType, it is distributed
// according to TableDist, and it contains the indices 0..m-1.
// Updates is an index set describing the set of updates to be made.
// It is distributed according to UpdateDist and contains the
// indices 0..N_U-1.
//
const TableSpace: domain(1, indexType) distributed TableDist = [0..m-1],
      Updates: domain(1, indexType) distributed UpdateDist = [0..N_U-1];

//
// T is the distributed table itself, storing a variable of type
// elemType for each index in TableSpace.
//
var T: [TableSpace] elemType;

//
// The program entry point
//
def main() {
  printConfiguration();   // print the problem size, number of trials, etc.

  //
  // In parallel, initialize the table such that each position
  // contains its index.  "[i in TableSpace]" is shorthand for "forall
  // i in TableSpace"
  //
  [i in TableSpace] T(i) = i;

  const startTime = getCurrentTime();              // capture the start time

  //
  // The main computation: Iterate over the set of updates and the
  // stream of random values in a parallel, zippered manner, dropping
  // the update index on the ground ("_") and storing the random value
  // in r.  Use an on-clause to force the table update to be executed on
  // the locale which owns the table element in question to minimize
  // communications.  Compute the update using r both to compute the
  // index and as the update value.
  //
  forall (_, r) in (Updates, RAStream()) do
    on T.domain.dist.ind2loc(r & indexMask) do
      T(r & indexMask) ^= r;

  const execTime = getCurrentTime() - startTime;   // capture the elapsed time

  const validAnswer = verifyResults();             // verify the updates
  printResults(validAnswer, execTime);             // print the results
}

//
// Print the problem size and number of updates
//
def printConfiguration() {
  if (printParams) {
    if (printStats) then printLocalesTasks(tasksPerLocale);
    printProblemSize(elemType, numTables, m);
    writeln("Number of updates = ", N_U, "\n");
  }
}

//
// Verify that the computation is correct
//
def verifyResults() {
  //
  // Print the table, if requested
  //
  if (printArrays) then writeln("After updates, T is: ", T, "\n");

  //
  // Reverse the updates by recomputing them, this time using an
  // atomic statement to ensure no conflicting updates
  //
  forall (_, r) in (Updates, RAStream()) do
    on T.domain.dist.ind2loc(r & indexMask) do
      atomic T(r & indexMask) ^= r;

  //
  // Print the table again after the updates have been reversed
  //
  if (printArrays) then writeln("After verification, T is: ", T, "\n");

  //
  // Compute the number of table positions that weren't reverted
  // correctly.  This is an indication of the number of conflicting
  // updates.
  //
  const numErrors = + reduce [i in TableSpace] (T(i) != i);
  if (printStats) then writeln("Number of errors is: ", numErrors, "\n");

  //
  // Return whether or not the number of errors was within the benchmark's
  // tolerance.
  //
  return numErrors <= (errorTolerance * N_U);
}

//
// Print out success/failure, the execution time, and the GUPS value
//
def printResults(successful, execTime) {
  writeln("Validation: ", if successful then "SUCCESS" else "FAILURE");
  if (printStats) {
    writeln("Execution time = ", execTime);
    writeln("Performance (GUPS) = ", (N_U / execTime) * 1e-9);
  }
}

//
// Use standard modules for Block distributions and Timing routines
//
use MultiBlockDist, Time;

//
// Use the user modules for computing HPCC problem sizes and for
// defining RA's random stream of values
//
use HPCCProblemSize, RARandomStream;

//
// The number of tables as well as the element and index types of
// that table
//
const numTables = 1;
type elemType = randType,
     indexType = randType;

//
// Configuration constants defining log2(problem size) -- n -- and
// the number of updates -- N_U
//
config const n = computeProblemSize(numTables, elemType,
                                    returnLog2=true, retType=indexType),
             N_U = 2**(n+2);

//
// Constants defining the problem size (m) and a bit mask for table
// indexing
//
const m = 2**n,
      indexMask = m-1;

//
// Configuration constant defining the number of errors to allow (as a
// fraction of the number of updates, N_U)
//
config const errorTolerance = 1e-2;

//
// The number of tasks to use per Chapel locale
//
config const tasksPerLocale = min reduce Locales.numCores;

//
// Configuration constants to control what's printed -- benchmark
// parameters, input and output arrays, and/or statistics
//
config const printParams = true,
             printArrays = false,
             printStats = true;

//
// TableDist is a 1D block distribution for domains storing indices
// of type "indexType", and it is computed by blocking the bounding
// box 0..m-1 across the set of locales.  UpdateDist is a similar
// distribution that is computed by blocking the indices 0..N_U-1
// across the locales.
//
const TableDist = new Block(1, indexType, bbox=[0..m-1],
                            tasksPerLocale=tasksPerLocale),
      UpdateDist = new Block(1, indexType, bbox=[0..N_U-1],
                             tasksPerLocale=tasksPerLocale);

//
// TableSpace describes the index set for the table.  It is a 1D
// domain storing indices of type indexType, it is distributed
// according to TableDist, and it contains the indices 0..m-1.
// Updates is an index set describing the set of updates to be made.
// It is distributed according to UpdateDist and contains the
// indices 0..N_U-1.
//
const TableSpace: domain(1, indexType) distributed TableDist = [0..m-1],
      Updates: domain(1, indexType) distributed UpdateDist = [0..N_U-1];

//
// T is the distributed table itself, storing a variable of type
// elemType for each index in TableSpace.
//
var T: [TableSpace] elemType;

//
// The program entry point
//
def main() {
  printConfiguration();   // print the problem size, number of trials, etc.

  //
  // In parallel, initialize the table such that each position
  // contains its index.  "[i in TableSpace]" is shorthand for "forall
  // i in TableSpace"
  //
  [i in TableSpace] T(i) = i;

  const startTime = getCurrentTime();              // capture the start time

  //
  // The main computation: Iterate over the set of updates and the
  // stream of random values in a parallel, zippered manner, dropping
  // the update index on the ground ("_") and storing the random value
  // in r.  Use an on-clause to force the table update to be executed on
  // the locale which owns the table element in question to minimize
  // communications.  Compute the update using r both to compute the
  // index and as the update value.
  //
  startVerboseComm();
  forall (_, r) in (Updates, RAStream()) do
    on T.domain.dist.ind2loc(r & indexMask) do
      T(r & indexMask) ^= r;
  stopVerboseComm();

  const execTime = getCurrentTime() - startTime;   // capture the elapsed time

  const validAnswer = verifyResults();             // verify the updates
  printResults(validAnswer, execTime);             // print the results
}

//
// Print the problem size and number of updates
//
def printConfiguration() {
  if (printParams) {
    if (printStats) then printLocalesTasks(tasksPerLocale);
    printProblemSize(elemType, numTables, m);
    writeln("Number of updates = ", N_U, "\n");
  }
}

//
// Verify that the computation is correct
//
def verifyResults() {
  //
  // Print the table, if requested
  //
  if (printArrays) then writeln("After updates, T is: ", T, "\n");

  //
  // Reverse the updates by recomputing them, this time using an
  // atomic statement to ensure no conflicting updates
  //
  forall (_, r) in (Updates, RAStream()) do
    on T.domain.dist.ind2loc(r & indexMask) do
      atomic T(r & indexMask) ^= r;

  //
  // Print the table again after the updates have been reversed
  //
  if (printArrays) then writeln("After verification, T is: ", T, "\n");

  //
  // Compute the number of table positions that weren't reverted
  // correctly.  This is an indication of the number of conflicting
  // updates.
  //
  const numErrors = + reduce [i in TableSpace] (T(i) != i);
  if (printStats) then writeln("Number of errors is: ", numErrors, "\n");

  //
  // Return whether or not the number of errors was within the benchmark's
  // tolerance.
  //
  return numErrors <= (errorTolerance * N_U);
}

//
// Print out success/failure, the execution time, and the GUPS value
//
def printResults(successful, execTime) {
  writeln("Validation: ", if successful then "SUCCESS" else "FAILURE");
  if (printStats) {
    writeln("Execution time = ", execTime);
    writeln("Performance (GUPS) = ", (N_U / execTime) * 1e-9);
  }
}


got past dimension mismatch thanks to BenA, my new best friend

module MLP {
  // https://gist.github.com/ben-albrecht/e2765ddd49007744a09dd016535038f9

  use LinearAlgebra;
  use Random;
  //config const epoch = 5000;
  config const epoch = 5,
               lr = 0.1;

  /*
   Attempts to implement the Multi-Layer Perceptron described here
   https://www.analyticsvidhya.com/blog/2017/05/neural-network-from-scratch-in-python-and-r/
   I'm going to do it very literally the first time
   */
  proc main() {
    writeln("Hola Mundo!");
    var X = Matrix(
       [1.0,0.0,1.0,0.0],
       [1.0,0.0,1.0,1.0],
       [0.0,1.0,0.0,1.0]);
    var y = Vector([1,1,0]);

    // Variable Initialization
    const inputLayerNeurons = X.shape[1],
          hiddenlayer_neurons = 3,
          output_neurons = 1;

    /* Create Ranges for the objects */
    const inputRange = 0..X.shape[1],
          hiddenRange = 0..3,
          outputRange = 0..#1;

    // Weight and bias matrices
    var wh: [{inputRange, hiddenRange}] real,
        bh: [{0..0, hiddenRange}] real,
        wout: [{hiddenRange, outputRange}] real,
        bout: [{0..0, outputRange}] real;

    fillRandom(wh);
    fillRandom(bh);
    fillRandom(wout);
    fillRandom(bout);

    for i in 1..#epoch {

      /* Forward propagation */
      var hidden_layer_input1 = dot(X,wh);
      writeln(hidden_layer_input1);
    }

  }

  proc sigmoid(x: real) {
    return (1/(1 + exp(-x)));
  }

  proc derivatives_sigmoid(x) {
    return x * (1-x);
  }
}

module MLP {
  use LinearAlgebra;
  use Random;
  //config const epoch = 5000;
  config const epoch = 5;
  config const lr = 0.1;

  /*
   Attempts to implement the Multi-Layer Perceptron described here
   https://www.analyticsvidhya.com/blog/2017/05/neural-network-from-scratch-in-python-and-r/
   I'm going to do it very literally the first time
   */
  proc main() {
    writeln("Hola Mundo!");
    var dom = {1..3,1..4};
    var X: [dom] real;
    X = Matrix([1,0,1,0],
       [1,0,1,1],
       [0,1,0,1]);
    var y = Vector([1,1,0]);

    // Variable Initialization
    var inputlayer_neurons = X.domain.dim(1).size;
    var hiddenlayer_neurons = 3;
    var output_neurons = 1;

    // Weight and bias matrices
    var wh: [{X.domain.dim(1),1..#hiddenlayer_neurons}] real;
    var bh: [{1..1,1..#hiddenlayer_neurons}] real;
    var wout: [{1..#hiddenlayer_neurons, 1..#output_neurons}] real;
    var bout: [{1..1, 1..#output_neurons}] real;
    fillRandom(wh);
    fillRandom(bh);
    fillRandom(wout);
    fillRandom(bout);

    for i in 1..#epoch {

      // Forward propagation
      var hidden_layer_input1 = dot(X,wh); // Dimension mis-match
      writeln(hidden_layer_input1);
    }

  }

  proc sigmoid(x: real) {
    return (1/(1 + exp(-x)));
  }

  proc derivatives_sigmoid(x) {
    return x * (1-x);
  }
}


It seems that if this module has no code in it,
it doesn't get used properly.  I added some bogus
code for now.

I have moved the BitOps from _chpl_math to here
in my private version of the compiler, but have
not had a chance to test yet, so will test over
the weekend and check in on Monday if it works.
In doing this move, I've also cleaned some of
them up a bit/generalized them.

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