This is an old revision of the document!
This lab is designed to transition our interpreter to a more powerful image processing engine by binding in new data types, high performance primitives, and automatic parallelization of interpretation.
This lab builds on the previous interpreters. In addition, to support the image processing primitives and text rendering primitives, you will need to install the Cairo
and Images
packages into Julia. This is done using the Julia package management system:
Pkg.add(“Cairo”)
and
Pkg.add(“Images”)
Note: Julia uses Git as the foundation of their package management system. This can create problems if your system can't access Git using a
git://
protocol – this is manifest by Julia hanging when trying to install packages. To alleviate this, please check out the following links:
https://github.com/JuliaLang/julia/issues/7005
https://github.com/JuliaLang/julia/blob/master/README.md#source-download-and-compilation
When I installed my Julia packages, it took a long time, but it worked. Be patient. :)
For this lab, you will expand the interpreter that we have already built in three ways: with new data types, new high performance primitives, and automatic parallelization.
The primary deliverable for this lab is a new Julia module. Your module should export parse
, calc
analyze
functions, and three return types, NumVal
, ClosureVal
, and MatrixVal
.
Your module should be able to do everything that the three previous interpreters. You are welcome to examine the code we developed in class. The CI8.jl
module is available on LearningSuite, under “Content → Julia → Program analysis”.
Please name your module HPInt
.
For this lab, you will implement several new features:
MatrixVal
data type.Each is discussed in more detail in the following sections.
The grammar for our new language is the following:
<OWL> ::= number | (+ <OWL> <OWL> <OWL>*) # all owls could be a MatrixVal or a NumVal | (- <OWL> <OWL>) | (* <OWL> <OWL>) | (/ <OWL> <OWL>) | (mod <OWL> <OWL>) | (collatz <OWL>) | (- <OWL>) | id | (if0 <OWL> <OWL> <OWL>) | (with ( (id <OWL>)* ) <OWL>) | (lambda (id*) <OWL>) | (and <OWL> <OWL> <OWL>*) | (<OWL> <OWL>*) # # new primitives here # | (simple_load <string>) | (simple_save <OWL> <string>) # this owl should evaluate to a MatrixVal | (render_text <string> <OWL> <OWL>) # these owls should evaluate to NumVals | (emboss <OWL>) # this owl should evaluate to a MatrixVal | (drop_shadow <OWL>) # this owl should evaluate to a MatrixVal | (inner_shadow <OWL>) # this owl should evaluate to a MatrixVal | (min <OWL> <OWL>) # boths owls could be a MatrixVal or a NumVal | (max <OWL> <OWL>)
The new productions in our language map directly to the primitive functions of the same name. For each, you will need to do the following:
<OWL>
subexpressionsWe've been through this process several times in class, so we won't belabor it here.
You must also ensure that the +
, -
, *
and /
operators work any combination of NumVal
or MatrixVal
. I showed you my solution to this problem in class, but the reference code does not contain that, because your implementation (using BinOp
) is likely quite different.
A few notes:
min,max,+,-,/,*
functions all must work with any combination of NumVal
and MatrixVal
s..*
operation (element-wise matrix multiply) instead of *
(matrix-matrix multiply). The new primitives create new opportunities for error handling. You should bullet-proof them!
In particular, you should carefully check the number and type of all subexpressions and strings. For example, operations such as min
or max
should operate on NumVal
or MatrixVal
objects, but should throw an error if handed something like a ClosureVal
.
We discussed several opportunities for parallelization in class. You must use the proper combination of @spawn
and fetch
to parallelize as many of the calc
functions as possible by spawning for each sub-call to calc
. You do not need to parallelize the analyze functions.
Once all is said and done, the following program:
(with base_img (render_text "Hello" 25 100) (with swirl (simple_load "/Users/wingated/Desktop/swirl_256.png") (with ds (drop_shadow base_img) (with tmp4 (+ (* (+ (min ds base_img) (- 1 base_img)) base_img) (* (- 1 base_img) swirl) ) (with tmp5 (- 1 (emboss tmp4)) (with base_img2 (render_text "world!" 5 200) (with is (inner_shadow base_img2) (with tmp6 (max base_img2 (* (- 1 base_img2) is) ) (with output (min tmp5 tmp6 ) (simple_save output "output.png") ) ) ) ) ) ) ) ) )
should generate the image shown below: