diff options
| author | = <=> | 2015-07-12 16:17:23 -0700 | 
|---|---|---|
| committer | = <=> | 2015-07-12 16:17:23 -0700 | 
| commit | 56171326c725f70cfdec99d8086d9c5dc8d1a211 (patch) | |
| tree | e82c397c144d4daba8eb7659f604e06e1559832a | |
| parent | 6e34ebf88f7e675820d58dff0ed1421118d4b3ee (diff) | |
added chapel.html.markdown, performed a first pass at the tutorial, and the beginning readme of the tutorial. Currently missing topics [ reduction, scal, non-loop tuple expansion, whole array/partial array assignment]
| -rw-r--r-- | chapel.html.markdown | 722 | 
1 files changed, 722 insertions, 0 deletions
| diff --git a/chapel.html.markdown b/chapel.html.markdown new file mode 100644 index 00000000..a17222b9 --- /dev/null +++ b/chapel.html.markdown @@ -0,0 +1,722 @@ +--- +language: chapel +filename: learnchapel.chpl +contributors: +    - ["Ian J. Bertolacci", "http://www.cs.colostate.edu/~ibertola.com/"] +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. + +Chapel is currently in-development so there are occasional hiccups with  +performance and language features, which is why you should write as much Chapel   + +Your input, questions, and discoveries are important to us! +----------------------------------------------------------- +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  +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``` + +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 +1. ```brew update``` +2. ```brew install chapel``` + +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 + +```
\ No newline at end of file | 
