2015-07-13 02:17:23 +03:00
|
|
|
|
---
|
|
|
|
|
language: chapel
|
|
|
|
|
filename: learnchapel.chpl
|
|
|
|
|
contributors:
|
2015-07-13 02:40:32 +03:00
|
|
|
|
- ["Ian J. Bertolacci", "http://www.cs.colostate.edu/~ibertola/"]
|
2015-07-13 02:17:23 +03:00
|
|
|
|
lang: en
|
|
|
|
|
---
|
|
|
|
|
What is Chapel?
|
|
|
|
|
===============
|
|
|
|
|
You can read all about chapel at [Cray's official Chapel website](chapel.cray.com).
|
|
|
|
|
In short, Chapel is an open-source, high-productivity, parallel-programming language in development
|
|
|
|
|
at Cray Inc., and is designed to run on multi-core PCs as well as multi-kilocore supercomputers.
|
|
|
|
|
|
|
|
|
|
Your input, questions, and discoveries are important to us!
|
|
|
|
|
-----------------------------------------------------------
|
2015-07-13 02:43:42 +03:00
|
|
|
|
Chapel is currently in-development so there are occasional hiccups with
|
|
|
|
|
performance and language features.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
The more information you give the Chapel development team about issues you encounter with the language,
|
|
|
|
|
the better the language gets.
|
|
|
|
|
Feel free to email the team and other developers through the sourceforge email lists at [sourceforge](https://sourceforge.net/p/chapel/mailman)
|
|
|
|
|
There is also a #chapel-developers hosted at chat.freenode.net.
|
|
|
|
|
|
|
|
|
|
If you're really interested in the cutting edge compiler or contributing to the project,
|
|
|
|
|
the git repository for Chapel is open-source at [github](https://github.com/chapel-lang/chapel)
|
|
|
|
|
under the Apache v2.0 license
|
|
|
|
|
|
|
|
|
|
Installing the Compiler
|
|
|
|
|
-----------------------
|
|
|
|
|
Chapel can be built and installed on your average 'nix machine (and cygwin).
|
|
|
|
|
Download the latest release version from https://github.com/chapel-lang/chapel/releases/
|
|
|
|
|
and its as easy as
|
2015-07-13 02:45:18 +03:00
|
|
|
|
1. ```tar -xvf chapel-1.11.0.tar.gz```
|
|
|
|
|
2. ```cd chapel-1.11.0```
|
|
|
|
|
3. ```make```
|
|
|
|
|
4. ```source util/setchplenv.bash # or .sh or .csh or .fish```
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
You will need to ```source util/setchplenv.*``` from the chapel directory every
|
|
|
|
|
time your terminal starts so its suggested that you drop that command in a script
|
|
|
|
|
that will get executed on startup (like .bashrc).
|
|
|
|
|
|
|
|
|
|
Chapel is easily installed with Brew for OS X
|
2015-07-13 02:45:18 +03:00
|
|
|
|
1. ```brew update```
|
|
|
|
|
2. ```brew install chapel```
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
Who is this tutorial for?
|
|
|
|
|
-------------------------
|
|
|
|
|
This tutorial is for people who want to learn the ropes of chapel without having to
|
|
|
|
|
hear about what fiber mixture the ropes are, or how they were braided, or how the braid configurations
|
|
|
|
|
differ between one another.
|
|
|
|
|
It won't teach you how to develop amazingly performant code, and it's not exhaustive.
|
|
|
|
|
Refer to the [language specification](http://chapel.cray.com/language.html)
|
|
|
|
|
and the [library-documentation](http://chapel.cray.com/docs/latest/) for more details.
|
|
|
|
|
|
|
|
|
|
Occasionally check here back to see if more topics have been added.
|
|
|
|
|
|
|
|
|
|
```chapel
|
|
|
|
|
// Comments are C-family style
|
|
|
|
|
// one line comment
|
|
|
|
|
/*
|
|
|
|
|
multi-line comment
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Basic printing
|
|
|
|
|
write( "Hello, " );
|
|
|
|
|
writeln( "World!" );
|
|
|
|
|
// write and writeln can take a list of things to print.
|
|
|
|
|
// each thing is printed right next to each other, so include your spacing!
|
|
|
|
|
writeln( "There are ", 3, " commas (\",\") in this line of code" );
|
|
|
|
|
// Different output channels
|
|
|
|
|
stdout.writeln( "This goes to standard output (just like plain writeln() does)");
|
|
|
|
|
stderr.writeln( "This goes to standard error" );
|
|
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
|
// Variables dont have to be explicitly as long as the compiler can figure
|
|
|
|
|
// out the type that it will hold.
|
|
|
|
|
var myVar = 10; // 10 is an int, so myVar is implicitly an int
|
|
|
|
|
myVar = -10;
|
|
|
|
|
// var anError; // compile time error, dont know what type anError should be.
|
|
|
|
|
|
|
|
|
|
// We can (and should) explicitly type things
|
|
|
|
|
var mySecondVar: real; // define mySecondVar as a real
|
|
|
|
|
var myThirdVar: real = -1.234;
|
|
|
|
|
mySecondVar = myThirdVar;
|
|
|
|
|
|
|
|
|
|
// There are a number of basic types.
|
|
|
|
|
var myInt: int = -1000; // signed ints
|
|
|
|
|
var myUint: uint = 1234; // unsigned ints
|
|
|
|
|
var myReal: real = 9.876; // floating point numbers
|
|
|
|
|
var myImag: imag = 5.0i; // imaginary numbers
|
|
|
|
|
var myCplx: complex = 10 + 9i; // complex numbers
|
|
|
|
|
myCplx = myInt + myImag ; // another way to form complex numbers
|
|
|
|
|
var myBool: bool = false; // booleans
|
|
|
|
|
var myStr: string = "Some string..."; // strings
|
|
|
|
|
|
|
|
|
|
// Some types can have sizes
|
|
|
|
|
var my8Int: int(8) = 10; // 8 bit (one byte) sized int;
|
|
|
|
|
var my64Real: real(64) = 1.516; // 64 bit (8 bytes) sized real
|
|
|
|
|
|
|
|
|
|
// Typecasting
|
|
|
|
|
var intFromReal = myReal : int;
|
|
|
|
|
// could also explicitly type intFromReal
|
|
|
|
|
// var intFromReal: int = myReal : int;
|
|
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
// Math operators
|
|
|
|
|
var a: int, thisInt = 1234, thatInt = 5678;
|
|
|
|
|
a = thisInt + thatInt; // Addition
|
|
|
|
|
a = thisInt * thatInt; // Multiplication
|
|
|
|
|
a = thisInt - thatInt; // Subtraction
|
|
|
|
|
a = thisInt / thatInt; // division
|
|
|
|
|
a = thisInt ** thatInt; // exponentiation
|
|
|
|
|
a = thisInt % thatInt; // remainder (modulo)
|
|
|
|
|
|
|
|
|
|
// Logical Operators
|
|
|
|
|
var b: bool, thisBool = false, thatBool = true;
|
|
|
|
|
b = thisBool && thatBool; // logical and
|
|
|
|
|
b = thisBool || thatBool; // logical or
|
|
|
|
|
b = !thisBool; // logical negation
|
|
|
|
|
|
|
|
|
|
// Relational Operators
|
|
|
|
|
b = thisInt > thatInt; // greater-than
|
|
|
|
|
b = thisInt >= thatInt; // greater-than-or-equal-to
|
|
|
|
|
b = thisInt < a && a <= thatInt; // less-than, and, less-than-or-equal-to
|
|
|
|
|
b = thisInt != thatInt; // not-equal-to
|
|
|
|
|
b = thisInt == thatInt; // equal-to
|
|
|
|
|
|
|
|
|
|
// Bitwise operations
|
|
|
|
|
a = thisInt << 10; // left-bit-shift by 10 bits;
|
|
|
|
|
a = thatInt >> 5; // right-bit-shift by 5 bits;
|
|
|
|
|
a = ~thisInt; // bitwise-negation
|
|
|
|
|
a = thisInt ^ thatInt; // bitwise exclusive-or
|
|
|
|
|
|
|
|
|
|
// Compound assignment operations
|
|
|
|
|
a += thisInt; // addition-equals ( a = a + thisInt;)
|
|
|
|
|
a *= thatInt; // times-equals ( a = a * thatInt; )
|
|
|
|
|
b &&= thatBool; // logical-and-equals ( b = b && thatBool; )
|
|
|
|
|
a <<= 3; // left-bit-shift-equals ( a = a << 10; )
|
|
|
|
|
// and so on...
|
|
|
|
|
// Unlike other C family languages there are no
|
|
|
|
|
// pre/post-increment/decrement operators like
|
|
|
|
|
// ++j, --j, j++, j--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Swap operator
|
|
|
|
|
var temp_this = thisInt;
|
|
|
|
|
var temp_that = thatInt;
|
|
|
|
|
thisInt <=> thatInt; // Swap the values of thisInt and thatInt
|
|
|
|
|
writeln( (temp_this == thatInt) && (temp_that == thisInt) );
|
|
|
|
|
|
|
|
|
|
// We can also define operator overloads,
|
|
|
|
|
// which we'll cover with procedures.
|
|
|
|
|
|
|
|
|
|
// Tuples
|
|
|
|
|
// tuples can be of the same type
|
|
|
|
|
var sameTup: 2*int = (10,-1);
|
|
|
|
|
// or different types
|
|
|
|
|
var diffTup: (int,real,complex) = (5, 1.928, myCplx);
|
|
|
|
|
// Accessed using array bracket notation
|
|
|
|
|
// However, tuples are all 1-indexed
|
|
|
|
|
writeln( "(", sameTup[1], ",", sameTup[2], ")" );
|
|
|
|
|
writeln( diffTup );
|
|
|
|
|
// Tuples can also be written into.
|
|
|
|
|
diffTup[1] = -1;
|
|
|
|
|
// Can also be used to easily write a collection of variables
|
|
|
|
|
// as is common in debugging
|
|
|
|
|
writeln( (a,b,thisInt,thatInt,thisBool,thatBool) );
|
|
|
|
|
|
|
|
|
|
// Type aliasing
|
|
|
|
|
type chroma = int; // type of a single hue
|
|
|
|
|
type RGBColor = 3*chroma; // type representing a full color
|
|
|
|
|
var black: RGBColor = ( 0,0,0 );
|
|
|
|
|
var white: RGBColor = ( 255, 255, 255 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If-Then statements
|
|
|
|
|
// if-thens dont require parentheses around the condition
|
|
|
|
|
// as they do in C (however, we will use them)
|
|
|
|
|
// and a single line body can use the 'then' keyword instead of braces
|
|
|
|
|
// and else statements can be written similarly
|
|
|
|
|
// (but we're only going to show it once).
|
|
|
|
|
if 10 < 100 then
|
|
|
|
|
writeln( "All is well" );
|
|
|
|
|
|
|
|
|
|
if -1 < 1 then
|
|
|
|
|
writeln( "Continuing to believe reality" );
|
|
|
|
|
else
|
|
|
|
|
writeln( "Send mathematician, something's wrong" );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( 10 > 100 ) {
|
|
|
|
|
writeln( "Universe broken. Please reboot universe." );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( a % 2 == 0 ) {
|
|
|
|
|
writeln( a, " is even." );
|
|
|
|
|
} else {
|
|
|
|
|
writeln( a, " is odd." );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( a % 3 == 0 ) {
|
|
|
|
|
writeln( a, " is even divisible by 3." );
|
|
|
|
|
} else if ( a % 3 == 1 ){
|
|
|
|
|
writeln( a, " is divided by 3 with a remainder of 1." );
|
|
|
|
|
} else {
|
|
|
|
|
writeln( b, " is divided by 3 with a remainder of 2." );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ternary: if-then-else in a statement
|
|
|
|
|
var maximum = if ( thisInt < thatInt ) then thatInt else thisInt;
|
|
|
|
|
|
|
|
|
|
// Select statements
|
|
|
|
|
// Select statements are much like switch statements in other languages
|
|
|
|
|
// However, Select statements dont cascade like in C or Java
|
|
|
|
|
var inputOption = "anOption";
|
|
|
|
|
select( inputOption ){
|
|
|
|
|
when "anOption" do writeln( "Chose 'anOption'" );
|
|
|
|
|
when "otherOption" {
|
|
|
|
|
writeln( "Chose 'otherOption'" );
|
|
|
|
|
writeln( "Which has a body" );
|
|
|
|
|
}
|
|
|
|
|
otherwise {
|
|
|
|
|
writeln( "Any other Input" );
|
|
|
|
|
writeln( "the otherwise case doesn't need a do if the body is one line" );
|
|
|
|
|
writeln( "Oh, and when statements dont cascade like the case statements" );
|
|
|
|
|
writeln( "of other languages" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loops
|
|
|
|
|
// While Loops
|
|
|
|
|
// While loops and Do-While loops are basically the same in every language.
|
|
|
|
|
|
|
|
|
|
var j: int = 1;
|
|
|
|
|
var jSum: int = 0;
|
|
|
|
|
while( j <= 1000 ){
|
|
|
|
|
jSum += j;
|
|
|
|
|
j += 1; // there are no ++j, --j, j++, j--, operators
|
|
|
|
|
}
|
|
|
|
|
writeln( jSum );
|
|
|
|
|
|
|
|
|
|
// basic Do-While loop
|
|
|
|
|
do{
|
|
|
|
|
jSum += j;
|
|
|
|
|
j += 1;
|
|
|
|
|
}while( j <= 10000 );
|
|
|
|
|
writeln( jSum );
|
|
|
|
|
|
|
|
|
|
// For loops
|
|
|
|
|
// For loops are much like those in python in that they iterate over a range.
|
|
|
|
|
// ranges themselves are types, and can be stuffed into variables
|
|
|
|
|
// (more about that later)
|
|
|
|
|
|
|
|
|
|
for i in 1..10 do write( i , ", ") ;
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
var iSum: int = 0;
|
|
|
|
|
for i in 1..1000 {
|
|
|
|
|
iSum += i;
|
|
|
|
|
}
|
|
|
|
|
writeln( iSum );
|
|
|
|
|
|
|
|
|
|
for x in 1..10 {
|
|
|
|
|
for y in 1..10 {
|
|
|
|
|
write( (x,y), "\t" );
|
|
|
|
|
}
|
|
|
|
|
writeln();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ranges and Domains
|
|
|
|
|
// For-loops and arrays both use ranges and domains to
|
|
|
|
|
// define an index set that can be iterated over.
|
|
|
|
|
// Ranges are single dimensional
|
|
|
|
|
// Domains can be multi-dimensional and represent indicies
|
|
|
|
|
// of different types as well.
|
|
|
|
|
// They are types, and can be assigned into variables;
|
|
|
|
|
var range1to10: range = 1..10; // // 1, 2, 3, ... , 10
|
|
|
|
|
|
|
|
|
|
// Ranges can be strided using the 'by' operator.
|
|
|
|
|
// Note: the stridable=true is only necessary if we type the variable
|
|
|
|
|
var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10
|
|
|
|
|
|
|
|
|
|
// The end point of a range can be determined using the count (#) operator
|
|
|
|
|
var rangeCount: range = -5..#12; // range from -5 to 6
|
|
|
|
|
|
|
|
|
|
// Can mix operators
|
|
|
|
|
var rangeCountBy: range(stridable=true) = -5..#12 by 2; // -5, -3, -1, 1, 3, 5
|
|
|
|
|
writeln( rangeCountBy );
|
|
|
|
|
|
|
|
|
|
// Can query properties of the range
|
|
|
|
|
// Print the first index, last index, number of indices,
|
|
|
|
|
// stride, and ask if 2 is include in the range
|
|
|
|
|
writeln( ( rangeCountBy.first, rangeCountBy.last, rangeCountBy.length,
|
|
|
|
|
rangeCountBy.stride, rangeCountBy.member( 2 ) ) );
|
|
|
|
|
|
|
|
|
|
for i in rangeCountBy{
|
|
|
|
|
write( i, if i == rangeCountBy.last then "\n" else ", " );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// domains are similarly defined using range notation
|
|
|
|
|
var domain1to10: domain(1) = {1..10}; // domain from 1..10;
|
|
|
|
|
var twoDimensions: domain(2) = {-2..2,0..2}; // domain over two dimensions
|
|
|
|
|
|
|
|
|
|
// Can iterate over the indices as tuples
|
|
|
|
|
for idx in twoDimensions do
|
|
|
|
|
write( idx , ", ");
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
// Or can deconstruct the tuple
|
|
|
|
|
for (x,y) in twoDimensions {
|
|
|
|
|
write( (x,y), ", " );
|
|
|
|
|
}
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
// Associative domains act like sets
|
|
|
|
|
var intSet: domain(int); // empty set of ints
|
|
|
|
|
intSet += 1;
|
|
|
|
|
intSet += 2;
|
|
|
|
|
intSet += 3;
|
|
|
|
|
intSet += 1; // redundant add 1
|
|
|
|
|
intSet -= 3; // remove 3
|
|
|
|
|
writeln( intSet );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Arrays
|
|
|
|
|
// Array are similar to those of other languages.
|
|
|
|
|
// Their sizes are defined using ranges and domains.
|
|
|
|
|
// that represent their indices, but we'll touch more on those later
|
|
|
|
|
var intArray: [1..10] int; // array of integers defined using range literal
|
|
|
|
|
|
|
|
|
|
// Accessed using bracket notation
|
|
|
|
|
for i in 1..10 do
|
|
|
|
|
intArray[i] = -i;
|
|
|
|
|
writeln( intArray );
|
|
|
|
|
// we cannot access intArray[0] because it exists outside
|
|
|
|
|
// of the index set we defined (1..10)
|
|
|
|
|
// intArray[11] is illegal for the same reason.
|
|
|
|
|
|
|
|
|
|
var realDomain: domain(2) = {1..5,1..7};
|
|
|
|
|
var realArray: [realDomain] real;
|
|
|
|
|
// similarly we could have done:
|
|
|
|
|
// var realArray: [1..5,1..7] real;
|
|
|
|
|
|
|
|
|
|
for i in 1..5 {
|
|
|
|
|
// use the range from 2nd dimension of the domain
|
|
|
|
|
for j in realDomain.dim(2) {
|
|
|
|
|
realArray[i,j] = -1.61803 * i + 0.5 * j; // access using index list
|
|
|
|
|
var idx: 2*int = (i,j); // note: 'index' is a keyword
|
|
|
|
|
realArray[idx] = - realArray[(i,j)]; // index using tuples
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// arrays have domains as members that we can iterate over
|
|
|
|
|
for idx in realArray.domain { // idx is, again, a 2*int tuple
|
|
|
|
|
realArray[idx] = 1 / realArray[idx[1],idx[2]]; // access by tuple and list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writeln( realArray );
|
|
|
|
|
|
|
|
|
|
// can also iterate over the values of an array
|
|
|
|
|
var rSum: real = 0;
|
|
|
|
|
for value in realArray {
|
|
|
|
|
rSum += value; // read a value
|
|
|
|
|
value = rSum; // write a value
|
|
|
|
|
}
|
|
|
|
|
writeln( rSum, "\n", realArray );
|
|
|
|
|
|
|
|
|
|
// Using associative domains we can create associative arrays (dictionaries)
|
|
|
|
|
var dictDomain: domain(string) = { "one", "two" };
|
|
|
|
|
var dict: [dictDomain] int = [ "one" => 1, "two" => 2 ];
|
|
|
|
|
dict["three"] = 3;
|
|
|
|
|
writeln( dict );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Procedures
|
|
|
|
|
// Chapel procedures have similar syntax to other languages functions.
|
|
|
|
|
|
|
|
|
|
proc fibonacci( n : int ) : int {
|
|
|
|
|
if ( n == 0 || n == 1 ) then return n;
|
|
|
|
|
return fibonacci( n-1 ) + fibonacci( n-2 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// input parameters can be untyped
|
|
|
|
|
proc doublePrint( thing ): void {
|
|
|
|
|
write( thing, " ", thing, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return type can be inferred (as long as the compiler can figure it out)
|
|
|
|
|
proc addThree( n ) {
|
|
|
|
|
return n + 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doublePrint( addThree( fibonacci( 20 ) ) );
|
|
|
|
|
|
|
|
|
|
// Can also take unlimited number of parameters
|
|
|
|
|
proc maxOf( x ...?k ) {
|
|
|
|
|
// x refers to a tuple of one type, with k elements
|
|
|
|
|
var maximum = x[1];
|
|
|
|
|
for i in 2..k do maximum = if (maximum < x[i]) then x[i] else maximum;
|
|
|
|
|
return maximum;
|
|
|
|
|
}
|
|
|
|
|
writeln( maxOf( 1, -10, 189, -9071982, 5, 17, 20001, 42 ) );
|
|
|
|
|
|
|
|
|
|
// the ? operator is called the query operator, and is used to take
|
|
|
|
|
// undetermined values (like tuple and array sizes, and generic types).
|
|
|
|
|
|
|
|
|
|
// Taking arrays as parameters.
|
|
|
|
|
// The query operator is used to determine the domain of A.
|
|
|
|
|
// this is important to define the return type (if you wanted to)
|
|
|
|
|
proc invertArray( A: [?D] int ): [D] int{
|
|
|
|
|
for a in A do a = -a;
|
|
|
|
|
return A;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writeln( invertArray( intArray ) );
|
|
|
|
|
|
|
|
|
|
// Procedures can have default parameter values, and
|
|
|
|
|
// the parameters can be named in the call, even out of order
|
|
|
|
|
proc defaultsProc( x: int, y: real = 1.2634 ): (int,real){
|
|
|
|
|
return (x,y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writeln( defaultsProc( 10 ) );
|
|
|
|
|
writeln( defaultsProc( x=11 ) );
|
|
|
|
|
writeln( defaultsProc( x=12, y=5.432 ) );
|
|
|
|
|
writeln( defaultsProc( y=9.876, x=13 ) );
|
|
|
|
|
|
|
|
|
|
// Generic procedures can still retain type
|
|
|
|
|
// Here we define a procedure that takes two arguments
|
|
|
|
|
// of the same type, yet we dont define what that type is.
|
|
|
|
|
proc genericProc( arg1 : ?valueType, arg2 : valueType ): void {
|
|
|
|
|
select( valueType ){
|
|
|
|
|
when int do writeln( arg1, " and ", arg2, " are ints" );
|
|
|
|
|
when real do writeln( arg1, " and ", arg2, " are reals" );
|
|
|
|
|
otherwise writeln( arg1, " and ", arg2, " are somethings!" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
genericProc( 1, 2 );
|
|
|
|
|
genericProc( 1.2, 2.3 );
|
|
|
|
|
genericProc( 1.0+2.0i, 3.0+4.0i );
|
|
|
|
|
|
|
|
|
|
// We can also enforce a form of polymorphism with the 'where' clause
|
|
|
|
|
// This allows the compiler to decide which function to use.
|
|
|
|
|
// Note: that means that all information needs to be known at compile
|
|
|
|
|
// time. Hence, we use params here to assert that the arguments must
|
|
|
|
|
// be known at compile time.
|
|
|
|
|
proc whereProc( param N : int ): void
|
|
|
|
|
where ( N > 0 ) {
|
|
|
|
|
writeln( "N is greater than 0" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc whereProc( param N : int ): void
|
|
|
|
|
where ( N < 0 ) {
|
|
|
|
|
writeln( "N is less than 0" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
whereProc( 10 );
|
|
|
|
|
whereProc( -1 );
|
|
|
|
|
// whereProc( 0 ) would result in a compiler error because there
|
|
|
|
|
// are no functions that satisfy the where clause's condition.
|
|
|
|
|
// We could have defined a whereProc without a where clause that would
|
|
|
|
|
// then have been called.
|
|
|
|
|
|
|
|
|
|
// Operator definitions are through procedures as well
|
|
|
|
|
// we can define the unary operators:
|
|
|
|
|
// + - ! ~
|
|
|
|
|
// and the binary operators:
|
|
|
|
|
// + - * / % ** == <= >= < > << >> & | ˆ by
|
|
|
|
|
// += -= *= /= %= **= &= |= ˆ= <<= >>= <=>
|
|
|
|
|
|
|
|
|
|
// boolean exclusive or operator
|
|
|
|
|
proc ^( left : bool, right : bool ): bool {
|
|
|
|
|
return (left || right) && !( left && right );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writeln( true ^ true );
|
|
|
|
|
writeln( false ^ true );
|
|
|
|
|
writeln( true ^ false );
|
|
|
|
|
writeln( false ^ false );
|
|
|
|
|
|
|
|
|
|
// Define a * operator on any two types.
|
|
|
|
|
proc *( left : ?ltype, right : ?rtype): ( ltype, rtype ){
|
|
|
|
|
return (left, right );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writeln( 1 * "a" ); // uses our * operator
|
|
|
|
|
writeln( 1 * 2 ); // uses the original * operator
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Note: You could break everything if you
|
|
|
|
|
get careless with your overloads.
|
|
|
|
|
This here will break everything. Dont do it.
|
|
|
|
|
proc +( left: int, right: int ): int{
|
|
|
|
|
return left - right;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Classes
|
|
|
|
|
class MyClass {
|
|
|
|
|
// Member variables
|
|
|
|
|
var memberInt : int;
|
|
|
|
|
var memberBool : bool = true;
|
|
|
|
|
|
|
|
|
|
// Classes have default constructors that dont need to be coded (see below)
|
|
|
|
|
// Our explicitly defined constructor
|
|
|
|
|
proc MyClass( val : real ){
|
|
|
|
|
this.memberInt = ceil( val ): int;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Our explicitly defined destructor
|
|
|
|
|
proc ~MyClass( ){
|
|
|
|
|
writeln( "MyClass Destructor called ", (this.memberInt, this.memberBool) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Class methods
|
|
|
|
|
proc setMemberInt( val: int ){
|
|
|
|
|
this.memberInt = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc setMemberBool( val: bool ){
|
|
|
|
|
this.memberBool = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc getMemberInt( ): int{
|
|
|
|
|
return this.memberInt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc getMemberBool(): bool {
|
|
|
|
|
return this.memberBool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct using default constructor, using default values
|
|
|
|
|
var myObject = new MyClass( 10 );
|
|
|
|
|
myObject = new MyClass( memberInt = 10 ); // equivalent
|
|
|
|
|
writeln( myObject.getMemberInt() );
|
|
|
|
|
// ... using our values
|
|
|
|
|
var myDiffObject = new MyClass( -1, true );
|
|
|
|
|
myDiffObject = new MyClass( memberInt = -1,
|
|
|
|
|
memberBool = false ); // equivalent
|
|
|
|
|
writeln( (myDiffObject.getMemberInt(), myDiffObject.getMemberBool() ));
|
|
|
|
|
|
|
|
|
|
// Construct using written constructor
|
|
|
|
|
var myOtherObject = new MyClass( 1.95 );
|
|
|
|
|
myOtherObject = new MyClass( val = 1.95 ); // equivalent
|
|
|
|
|
writeln( myOtherObject.getMemberInt() );
|
|
|
|
|
|
|
|
|
|
// We can define an operator on our class as well but
|
|
|
|
|
// the definition has to be outside the class definition
|
|
|
|
|
proc +( A : MyClass, B : MyClass) : MyClass {
|
|
|
|
|
return new MyClass( memberInt = A.getMemberInt() + B.getMemberInt(),
|
|
|
|
|
memberBool = A.getMemberBool() || B.getMemberBool() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var plusObject = myObject + myDiffObject;
|
|
|
|
|
writeln( (plusObject.getMemberInt(), plusObject.getMemberBool() ) );
|
|
|
|
|
|
|
|
|
|
// destruction
|
|
|
|
|
delete myObject;
|
|
|
|
|
delete myDiffObject;
|
|
|
|
|
delete myOtherObject;
|
|
|
|
|
delete plusObject;
|
|
|
|
|
|
|
|
|
|
// Classes can inherit from one or more parent classes
|
|
|
|
|
class MyChildClass : MyClass {
|
|
|
|
|
var memberComplex: complex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generic Classes
|
|
|
|
|
class GenericClass {
|
|
|
|
|
type classType;
|
|
|
|
|
var classDomain: domain(1);
|
|
|
|
|
var classArray: [classDomain] classType;
|
|
|
|
|
|
|
|
|
|
// Explicit constructor
|
|
|
|
|
proc GenericClass( type classType, elements : int ){
|
|
|
|
|
this.classDomain = {1..#elements};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy constructor
|
|
|
|
|
// Note: We still have to put the the type as an argument, but we can
|
|
|
|
|
// default to the type of the other object using the query (?) operator
|
|
|
|
|
// Further, we can take advantage of this to allow our copy constructor
|
|
|
|
|
// to copy classes of different types
|
|
|
|
|
proc GenericClass( other : GenericClass(?otherType),
|
|
|
|
|
type classType = otherType ) {
|
|
|
|
|
this.classDomain = other.classDomain;
|
|
|
|
|
// Copy and cast
|
|
|
|
|
[ idx in this.classDomain ] this[ idx ] = other[ idx ] : classType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Define bracket notation on a GenericClass object
|
|
|
|
|
// i.e. objVar[ i ] or objVar( i )
|
|
|
|
|
proc this( i : int ) ref : classType {
|
|
|
|
|
return this.classArray[ i ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Define an iterator for the class.
|
|
|
|
|
// i.e. for i in objVar do ....
|
|
|
|
|
iter these() ref : classType {
|
|
|
|
|
for i in this.classDomain do
|
|
|
|
|
yield this[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var realList = new GenericClass( real, 10 );
|
|
|
|
|
// We can assign to the array in the object using the bracket notation
|
|
|
|
|
for i in realList.classDomain do realList[i] = i + 1.0;
|
|
|
|
|
// We can iterate over a
|
|
|
|
|
for value in realList do write( value, ", " );
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
// Make a copy of realList using the copy constructor
|
|
|
|
|
var copyList = new GenericClass( realList );
|
|
|
|
|
for value in copyList do write( value, ", " );
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
// make a copy of realList and change the type, also using the copy constructor
|
|
|
|
|
var copyNewTypeList = new GenericClass( realList, int );
|
|
|
|
|
for value in copyNewTypeList do write( value, ", " );
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Tasks
|
|
|
|
|
// A task is some work that will be done separately from
|
|
|
|
|
// the current task, and (if there are any available) in its own thread.
|
|
|
|
|
|
|
|
|
|
// a synch statement will ensure that the progress of the
|
|
|
|
|
// main task will not progress until the children have synced back up.
|
|
|
|
|
sync {
|
|
|
|
|
// a begin statement will spin the body off into one new task
|
|
|
|
|
begin {
|
|
|
|
|
var a = 0;
|
|
|
|
|
for i in 1..1000 do a += 1;
|
|
|
|
|
writeln( "Done: ", a);
|
|
|
|
|
}
|
|
|
|
|
writeln( "spun off a task!");
|
|
|
|
|
}
|
|
|
|
|
writeln( "Back together" );
|
|
|
|
|
|
|
|
|
|
proc printFibb( n: int ){
|
|
|
|
|
writeln( "fibonacci(",n,") = ", fibonacci( n ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// a cobegin statement will spin each
|
|
|
|
|
// statement of the body into one new task
|
|
|
|
|
cobegin {
|
|
|
|
|
printFibb( 20 );
|
|
|
|
|
printFibb( 10 );
|
|
|
|
|
printFibb( 5 );
|
|
|
|
|
{
|
|
|
|
|
// this is a nested statement body and thus is a single statement
|
|
|
|
|
// to the parent statement and is executed by a single task
|
|
|
|
|
writeln( "this gets" );
|
|
|
|
|
writeln( "executed as" );
|
|
|
|
|
writeln( "a whole" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Notice here that the prints may happen in any order.
|
|
|
|
|
|
|
|
|
|
// Coforall loop will create a new task for EACH iteration
|
|
|
|
|
// NOTE! coforall should be used only for creating tasks!
|
|
|
|
|
// Using it to iterating over an array or something like that is very a bad idea!
|
|
|
|
|
|
|
|
|
|
var num_tasks = 10; // Number of tasks we want
|
|
|
|
|
coforall taskID in 1..#num_tasks {
|
|
|
|
|
writeln( "Hello from task# ", taskID );
|
|
|
|
|
}
|
|
|
|
|
// Again we see that prints happen in any order.
|
|
|
|
|
|
|
|
|
|
// forall loops are another parallel loop, but only create a smaller number
|
|
|
|
|
// of tasks, specifically dataParTasksPerLocale number of task (more later)
|
|
|
|
|
forall i in 1..100 {
|
|
|
|
|
write( i, ", ");
|
|
|
|
|
}
|
|
|
|
|
writeln();
|
|
|
|
|
// Here we see that there are sections that are in order, followed by
|
|
|
|
|
// a section that would not follow ( e.g. 1, 2, 3, 7, 8, 9, 4, 5, 6, )
|
|
|
|
|
// this is because each task is taking on a chunk of the range 1..10
|
|
|
|
|
// (1..3, 4..6, or 7..9) doing that chunk serially, but each task happens
|
|
|
|
|
// in parallel.
|
|
|
|
|
// Your results may depend on your machine and configuration
|
|
|
|
|
|
|
|
|
|
// For both the forall and coforall loops, the execution of the parent task
|
|
|
|
|
// will not continue until all the children sync up.
|
|
|
|
|
|
|
|
|
|
// forall loops are particularly useful for parallel iteration over arrays
|
|
|
|
|
// Lets run an experiment to see how much faster a parallel loop is
|
|
|
|
|
use Time; // Import the Time module to use Timer objects
|
|
|
|
|
var timer: Timer;
|
|
|
|
|
var myBigArray: [{1..4000,1..4000}] real; // large array we will write into
|
|
|
|
|
// Serial Experiment
|
|
|
|
|
timer.start(); // start timer
|
|
|
|
|
for (x,y) in myBigArray.domain { // serial iteration
|
|
|
|
|
myBigArray[x,y] = (x:real) / (y:real);
|
|
|
|
|
}
|
|
|
|
|
timer.stop(); // stop timer
|
|
|
|
|
writeln( "Serial: ", timer.elapsed() ); // print elapsed time
|
|
|
|
|
timer.clear(); // clear timer for parallel loop
|
|
|
|
|
|
|
|
|
|
// Parallel Experiment
|
|
|
|
|
timer.start(); // start timer
|
|
|
|
|
forall (x,y) in myBigArray.domain { // parallel iteration
|
|
|
|
|
myBigArray[x,y] = (x:real) / (y:real);
|
|
|
|
|
}
|
|
|
|
|
timer.stop(); // stop timer
|
|
|
|
|
writeln( "Parallel: ", timer.elapsed() ); // print elapsed time
|
|
|
|
|
timer.clear();
|
|
|
|
|
// you may have noticed that (depending on how many cores you have) that
|
|
|
|
|
// the parallel loop went faster than the serial loop
|
|
|
|
|
|
|
|
|
|
// A succinct way of writing a forall loop over an array:
|
|
|
|
|
[ val in myBigArray ] val = 1 / val; // iterate over values
|
|
|
|
|
// or
|
|
|
|
|
[ idx in myBigArray.domain ] myBigArray[idx] = -myBigArray[idx]; // iterate over indicies
|
|
|
|
|
|
2015-07-13 02:40:32 +03:00
|
|
|
|
```
|