First, we need to define the CnC graph:
object FindPrimesCncDefinition { def main(args: Array[String]): Unit = { ApplicationName("FindPrimes") TargetPackage("findprimes") // default package TargetDirectory("findprimes") Comment("Item Collections") // The prime numbers as identified by the compute step ItemCollection[Point, Int]("primes") Comment("Tag Collections") // The tag values are the odd numbers in the range [3..n] TagCollection[Point]("oddNums") Comment("Step Dependences") // The compute step may produce a prime number (in the form of a tag instance) StepDependence("compute", List[String](), List("primes")) Comment("Step Prescriptions") // For each oddNums instance, there is Presription("oddNums", List("compute")) Comment("Environment Collections") // Input from the environment: initialize all tags // Output to the environment is the collection of the prime numbers EnvironmentDependence( List("oddNums"), List("primes") ) } }
The CnC graph states that oddNums
is a Tag Collection with strings as the tags.
Next, we define the Item Collection primes
which has strings as tags and integer as its values. These types are defined in the format tagType->itemType
before the name of the Item Collection.
env
is a keyword representing the environment and in this example we define the environment will put tags (of type Point) into the oddNums
Tag Collection and read the results from the primes
Item Collection.
After defining the CnC graph, we need to run this file using the CnC-Scala translator using the following command:
cnc_scala_translate FindPrimesCncDefinition
Running the command will generate some Scala files. In short, these are what the files represent:
File Name |
Function |
---|---|
|
A textual form of the CnC graph understood by other CnC implementations. |
|
A Scala class representation the CnC graph. Users will need to instantiate instances of this graph and invoke the |
|
This file includes Scala traits for the different Step instances. Users will need to implement these interfaces in their custom Steps. The file also includes default implementations of the Tag Collections. Users should not need to edit the contents of this file. |
Here is how a trait for the Step looks like:
import edu.rice.cnc.api._ import edu.rice.cnc.runtime._ import util.continuations.cps trait ComputeStep extends Step { def compute( tag: Point , outPrimes: OutputCollection[Point, Int] ): Unit@cps[Any] }
Below is a simple Step implementation:
import edu.rice.cnc.api._ import util.continuations.cps class UserComputeStep() extends ComputeStep { def compute( tag: Point, outPrimes: OutputCollection[Point, Int] ): Unit@cps[Any] = { val number: Int = tag(0) var factor: Int = 3 while (number % factor != 0) { factor += 2 } if (factor == number) { outPrimes.put(tag, number) } } }
This step does not rely on input from an Item Collection, instead it uses the tag as the input. Please refer to the Partition String example for a step instance that retrieves inputs from Item Collections.
Running this program with an input of 100
should produce the following output:
Determining primes from 1-100 Number of primes: 24 Contents of Collection'primes' [3]=3 [5]=5 ... [83]=83 [89]=89 [97]=97 HabaneroRuntime: num workers=4 executor service=jsr166y.ForkJoinPool@39385660[Terminated, parallelism = 4, size = 0, active = 0, running = 0, steals = 49, tasks = 0, submissions = 0] async instances=50 activity instances=50