Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

CS 135 Fall 2020

Becker, Clarke, Hackman, Holtby, Lank, Morland, Nijjar, Watson

Assignment: 04
Due: Tuesday, October 20 at noon (Waterloo time)
Language level: Beginning Student with List Abbreviations
Files to submit: vector.rkt, recognize.rkt
Practice exercises: HtDP 12.2.1, 12.2.2, 12.3.1, 12.3.2, 12.4.1

• This assignment covers concepts up to the end of Module 08. You should change your Racket
language to Beginning Student with List Abbreviations. You may use the (list val val
...) construct to create lists.
• Read the OFFICIAL A04 post on Piazza for answers to frequently asked questions, especially
before you post to Piazza.
• Recall the policy on plagiarism and check all coding you do against the style guide.
• Submit early and often. Once the submission system closes we do not accept further
submissions for marks, so submitting early is always a good idea.
• It is very important that your function names, strings, and symbols match ours. Basic
tests results will catch many, but not necessarily all of these types of errors.
• Unless otherwise stated, all policies from Assignment 03 carry forward.

CS 135 — Fall 2020 Assignment 04 1


1. [8% correctness] In this question you will perform step-by-step evaluations of Racket
programs, as you did in assignment one and two. Please review the instructions on stepping
in A01.
Complete the required Module 07 and 08 stepper questions at
https://www.student.cs.uwaterloo.ca/~cs135/assign/stepping/.

2. For this question, recall that a vector is an object with a magnitude and a direction. We are
going to be representing a vector as a list of numbers. Note that this means the list for a vector
of degree n would be of length n.

(a) [4% Correctness] The Euclidean Norm of a vector is the square root of the sum
of squares of the vector’s components. So for a vector v composed composed of
x0 , x1 , ..., xn , the Euclidean Norm formula is
. r
ENorm (v) = ∑ xi2
i=0...n

Define a function euclidean-norm which, given a vector v (i.e. a list of numbers) of


arbitrary length, produces the Euclidean Norm of v. For example:
(check-within (euclidean-norm (list 3 4)) 5 0.01)

(b) [4% Correctness] A unit vector aligned to a vector v, is a vector of magnitude 1


obtained by dividing each component of v by v’s Euclidean Norm. Define a function
unit-vector which, given a vector (i.e. a list of numbers) of positive length, produces
its aligned unit vector. You may assume that v will not be a zero vector. For example:
(check-within (unit-vector (list 3 4)) (list 0.6 0.8) 0.01)

(c) [4% Correctness] ] Let A and B be vectors of the same degree n with a1 , a2 , ..., an and
b1 , b2 , ..., bn being their respective components. The dot product of a and b is:
n
A · B = ∑ (ai )(bi )
i=1

The cosine of the angle between a and b is the dot product of the unit vectors aligned
with vector a and vector b. Define a function cos-between which, given two non zero
vectors a and b of positive length, produces the cosine of the angle between a and b. For
example:
(check-within (cos-between (list 3 4) (list 0 6)) 0.8 0.01)

In order to test cases with inexact numbers, you should use check-within with a tolerance
of 0.01 for your test cases.
Place your code in a file vector.rkt.

CS 135 — Fall 2020 Assignment 04 2


3. For this question, you should download the files templates.rkt and recognize.rkt and
save them on your computer in the same folder. You will complete and submit recognize.rkt
(including any necessary design recipe not already provided).
Problem Description and Context
In this question, you will build a gesture recognizer in Racket that recognizes a type of
gestures called unistroke gestures. That means that they are gestures comprised of one single
gesture or stroke. The gestures that your recognizer will recognize are a Graffiti alphabet that
was originally used on the Palm Pilot, the first widely successful handheld computer, and
the pre-cursor of the modern smartphone. The Graffiti alphabet that the Palm Pilot used is
pictured here. Each gesture is a single stroke and represents an alphabetic character.

We’ve created a simple JavaScript app1 at:


https://cs.uwaterloo.ca/~lank/canvas.html
This app will let you create your own gesture as a list of points by dragging your mouse. Once
you create a gesture, the “copy” button will copy it to your clipboard. You can then paste it
directly into DrRacket. If you create a new set of points and want to look at the new gesture
you have created, you can use the paste button to paste points into the canvas.
Note that, if you paste into the app, the app will ask for permission to access your clipboard.
Note also that, while copying always works, sometimes pasting does not. I have heard reports
that it does not work with Firefox on Linux. This may be a permissions issue, and you may
have more luck if you download a copy of the page locally to your computer.
By convention, the top left corner of any on-screen display object, for example the drawing
area, is its origin (i.e. position (0, 0)), which means that the y-axis increases going down
the display (opposite to Cartesian planes where y increases going up). The x-axis increases
going from left-to-right. When you move your mouse on the above canvas, the movement
is captured as a list of (x, y) points. A point on the screen is a set of two numbers, an
1 You can download and inspect the code and/or run the app on your own computer by going to the page, right

clicking in the middle of the page, selecting view source, and then copying the source to a text editor. The code is
very loosely based upon an online example, heavily modified from https://stackoverflow.com/questions/
2368784/draw-on-html5-canvas-using-a-mouse

CS 135 — Fall 2020 Assignment 04 3


x-coordinate and a y-coordinate, i.e. a list. A gesture is therefore a list of these points, or a
list of lists.
To clarify,

• A point at the origin would be represented by:


(list 0 0)

In your starter code, we include the following data definition for Point:
;; A Point is a (list Num Num) that represents an (x, y) coordinate.

• A single gesture (i.e. a uni-stroke) that creates a diamond shape in a box positioned
from (list 0 0) to (list 200 200) would be represented by the gesture:
(list (list 100 0) (list 200 100) (list 100 200) (list 0 100) (list
100 0))

Pasting this list into https://cs.uwaterloo.ca/~lank/canvas.html will give


you the following image (note, again, the y-axis increases downward):

In your starter code, we include the following data definition for Gesture:
;; A Gesture is a (listof Point).

• The Bounding Box of the above figure would be (list (list 0 0) (list 200 200)),
i.e. a box defined by two points, the top left point located at point (list min-x min-y)
and the bottom right point located at (list max-x max-y).
;; A BoundingBox is a (list Point Point).
;; requires: the coordinate values in the first point are less
;; than the respective values in the second point

CS 135 — Fall 2020 Assignment 04 4


• We also define a template library in your starter code:
;; A TemplateLibrary (TL) is a (listof (list Sym Gesture))
;; requires: the list is non-empty
;; each Sym key is unqiue
;; each Gesture value is not both vertical and horizontal

Tasks
As noted above, download your starter files. Also, whenever your calculations involve inexact
numbers, always use check-within with tolerance 0.01.

(a) In part a, you will write a series of helper functions. Because these are helper functions,
you should have a purpose, one or two examples, and a contract. You do not need to
fully test the helper functions; just provide one or two examples for each.
i. [2% Correctness] Write two helper functions get-x and get-y which consume a
Point and produce, respectively, the x-coordinate and the y-coordinate of the point.
ii. [2% Correctness] To translate a gesture, you add or subtract a number from each
Point’s x-value and a second number from each Point’s y-value. Write a function,
translate-gesture, that consumes a Gesture and two numbers, an x-offset and
a y-offset, and produces a new gesture such that each Point ((list x y)) in the
original gesture now has value (list (+ x x-offset) (+ y y-offset)) in the
new gesture.
iii. [3% Correctness] To scale a gesture, you multiply each component by a scale value.
The x and y scale values need not be identical. Define a function scale-gesture
that consumes a Gesture and two numbers, x-scale and y-scale, and produces
a new stroke such that each Point ((list x y)) in the original gesture now has
value (list (* x x-scale) (* y y-scale)) in the new gesture. x-scale and
y-scale should be positive, non-zero values.
iv. [3% Correctness] Write a function get-b-box which consumes a non-empty
Gesture and produces the gesture’s BoundingBox, as defined above.
(b) Write the following two functions. Include the full design recipe.
i. [5% Correctness] Write a function gesture-length which consumes a Gesture
and calculates its length. To calculate the length of a list of points, you may find
the Euclidean formula helpful:
q
d(p1 , p2 ) = (x2 − x1 )2 + (y2 − y1 )2
where d is the distance between two points, p1 and p2 , defined by points (x1 , y1 )
and (x2 , y2 ). Gesture length is the sum of the distances between adjacent points in
the gesture. A Gesture of one point has gesture-length → 0. A Gesture of 0
Points can also be defined to have length 0.

CS 135 — Fall 2020 Assignment 04 5


ii. [5% Correctness] Write a function get-points which consumes a Gesture, g,
and a non-decreasing list of Nat in the range [0...(n − 1)], where n is the number of
Points in g. get-points produces a Gesture where each Point in the produced
Gesture is indexed by one element of the list of Nat consumed.
For example, (get-points g (list 0)) produces a Gesture containing only the
first point of g. Another example is that (get-points g (list 0 1 6)) pro-
duces a Gesture produces a gesture with the first, second, and seventh Points of g
preserving that order.
(define mygest (list (list 100 0) (list 200 100) (list 100 200)
(list 0 100) (list 100 50)))

;; example
(check-expect (get-points mygest (list 0 0 2 4 4))
(list (list 100 0) (list 100 0) (list 100 200) (list 100 50)
(list 100 50)))

(c) Now, it’s time to write your recognizer. There are three functions which form the core
of your recognizer. The first function is five-sample which, consumes a Gesture of
arbitrary number of points and produces a new Gesture that has exactly 5 points. The
second is normalize-gesture which consumes a Gesture and produces a translated and
scaled Gesture such that the produced Gesture is normalized in position and size. Finally,
the third is five-point-rec which consumes a Gesture and a TemplateLibrary and
produces the symbol whose sample Gesture in the template library is closest to the
Gesture.
i. [5% Correctness] Write a function, five-sample. five-sample consumes a non-
empty Gesture containing any number of points and produces a new Gesture with
exactly five points such that:
• The first point in the new Gesture is equal to the first point in the original
gesture.
• If the original gesture has n points, then the second point in the new gesture is
equal to the (floor (* 0.25 n))-th point in the original gesture.
• Likewise, the third point in the new gesture is (floor (* 0.5 n))-th point in
the original gesture and the fourth point is the (floor (* 0.75 n))-th point.
• The last point in the new Gesture is equal to the last point in the original gesture.
ii. [5% Correctness] Define a function move-and-scale which consumes a Gesture
and two positive numbers, an x-scale, and a y-scale and produces a new gesture
positioned at (0, 0) and scaled in size by factors x-scale and y-scale. Note that
you should first translate the gesture to (0, 0) and then scale!!.
iii. [5% Correctness] Consider the Grafitti alphabet depicted above. For most gestures,
normalizing in width and height causes no particular problem. However, for the ’i
symbol, there is a problem. It is a vertical line.
Given the drawing pad at https://cs.uwaterloo.ca/~lank/canvas.html

CS 135 — Fall 2020 Assignment 04 6


is of size 400X400, let’s assume that any gesture that is less “wide” than min-width
in pixels and/or less “high” than min-height in pixels is, respectively, a vertical or
horizontal line. Vertical and horizontal lines should not be scaled in, respectively,
width or height during normalization. min-width and min-height are already
defined in your starter file (they are set to 30). In your starter file, there is also a re-
quirement defined that one of width or height must be greater than its corresponding
minimum value (written as “a gesture is not both vertical and horizontal”).
Write a function normalize-gesture which, given a non-empty gesture, if the
gesture is vertical, it translates it but scales it only in height; if the gesture is
horizontal, it translates it but scales it only in width, and if it is neither vertical nor
horizontal (i.e. it’s just a regular, two-dimensional gesture) it translates it and scales
it in both width and height. Your normalize-gesture function should invoke
move-and-scale and it should make use of constant norm-size already defined in
your starter code to be equal to 200.
The net effect of normalize-gesture is to position and scale produced gestures
such that their bounding boxes’ top left corner is (0, 0). Provided they are not
vertical or horizontal lines, the bottom right corner of their bounding boxes should
be located at (200, 200). One way to test your normalize-gesture function is via
the bounding box function, i.e.
(check-within (get-b-box (normalize-gesture
(list (list Num Num) (list Num Num) ...)))
(list (list 0 0) (list 200 200)) 0.01)

iv. [5% Correctness] Define a function geometric-5match which takes two gestures
and produces a number that represents the average distance between points on the
two gestures. Note, again, that for each gesture, one of width or height must be
greater than its corresponding minimum value. It does this as follows:
A. It five-samples the two gestures.
B. It normalizes the two sub-sampled gestures.
C. It calculates the average distance between the points on the two gestures. If the
two gestures, g and g0 are composed of k points, such that the points of g are
pi = (xi , yi ) and the points of g0 are p0i = (xi0 , y0i ) where i = 0 . . . (k − 1), then it
computes:
1
average-distance(g, g0 ) = ∑ d(pi, p0i)
k i=0...k−1
For this part of the question, k equals five.

;; templates is a TemplateLibrary defined in templates.rkt


;; it is a variable that should be accessible to your code

(check-within (geometric-5match (second (fourth templates))


(second (fourth templates))) 0 0.1)

CS 135 — Fall 2020 Assignment 04 7


v. [5% Correctness] Define a function five-point-rec which consumes a Gesture
and a TemplateLibrary templates, and produces the symbol from templates
that is the closest geometric-5match to the candidate gesture.
To recognize a gesture, the function should call geometric-5match on each gesture
in the template library and identify the minimum geometric-match distance. So, for
example, ideally:
(check-expect (five-point-rec (second (third templates))
templates) ’c)

As long as you saved templates.rkt in the same directory as recognize.rkt you


should be able to use the templates as the input to your function. You can also
open templates.rkt to inspect the TemplateLibrary. If you do, you will see the
following:
(define templates (list
(list ’a
(list (list 112 309) (list 113 307) (list 113 305) ... ))
(list ’b
(list (list 135 22) (list 135 23) (list 137 28) ... ))
(list ’c
(list (list 285 82.5) (list 284 81.5) (list 284 80.5) ... ))
(list ’d
(list (list 107 25.5) (list 107 31.5) (list 107 42.5) ... ))
(list ’e
(list (list 261 47.5) (list 260 45.5) ... ))
...
))

(d) [5% Correctness] You can test your recognizer at this point by copying points that you
draw in the web app and pasting them into the interactions window in Dr Racket as
follows:
(five-point-rec <paste your stroke here> templates)

However, you may find that your recognizer works very poorly. It may work well on ’a,
’c, ’i, and other simple symbols, but longer symbols cause problems – because it doesn’t
use enough points! five-sample, geometric-5match, and five-point-rec assume 5
points, when more would be (definitely) better.
Define three new function sub-sample, geometric-match, and k-point-rec. These
are identical to the previous variants except that they should also consume a Nat, k,
which defines the number of points you want to sub-sample over during recognition. k
must be greater than 2.
You must include a purpose, examples (preferably two or three per function) and
contracts. You should fully test sub-sample. geometric-match and k-point-rec do
not require a full test suite as these functions are straightforward.
Submit the file recognize.rkt with all functions clearly documented as per the Style

CS 135 — Fall 2020 Assignment 04 8


Guide.

4. Bonus: [10% Correctness]


This bonus is challenging. Do not become frustrated if it seems really tough to handle all of
the corner cases.
In real-world recognizers, sometimes we create perfect templates. For example, the following
definition produces a perfect square with exactly four points:
(define perfect-square(list (list 50 100) (list 250 100)
(list 250 300) (list 50 300) (list 50 100)))

In our above code, if we draw a square and try to recognize on 8 points, the square we draw
will have one point at about the middle of each edge and one point at each corner (ideally).
And, in fact, depending on how fast we draw, it may have more or fewer points at different
locations along the gesture. In contrast, when we sub-sample perfect-square we will get
two points at each corner. This will mean that the Gesture that we draw, even if we use a
ruler or trace a perfect square, may not have a good match to the perfect-square we defined
above because of the way we are sub-sampling points.
There is a way to correct this. Rather than sub-sampling points from our gestures, we can
sub-sample in distance along the gesture. To understand this idea of spatial sampling, if
k = 5 the following three gestures:

(list (list 0 0) (list 200 200))

(list (list 0 0) (list 40 40) (list 80 80) (list 120 120)


(list 160 160) (list 200 200))

(list (list 0 0) (list 10 10) (list 20 20) (list 30 30)


(list 40 40) (list 200 200))

should all produce the following when sub-sampled:


(list (list 0 0) (list 50 50) (list 100 100) (list 150 150)
(list 200 200))

Define a function spatial-sub-sample which consumes a gesture and a value k and produces
a new gesture that has k points that are equally spaced along the path of the original gesture.
You should set the parameter k to 5 for initial testing, but then change it to at least 10 for
recognition.
Hint The first point in your newly sub-sampled gesture should be (x0 , y0 ), i.e. the first point
in your original gesture. You should be able to figure out the distance between any two points
in your new sub-sampled stroke using gesture-length and k − 1, call it dss .
Now, think about the distance between the first point and the second point in the original
stroke (call it d0−1 ). If d0−1 > dss , you need to move a fraction of the distance between

CS 135 — Fall 2020 Assignment 04 9


(x0 , y0 ) and (x1 , y1 ). If that’s the case, then the following may be helpful:

dss
x1ss = x0 + (x1 − x0 )
d0−1
dss
y1ss = y0 + (y1 − y0 )
d0−1
where (x1ss , y1ss ) is the second point on your new subsampled gesture. But what happens if
d0−1 > dss ?
Here’s a test to check your work. Let’s say someone draws a perfect square as defined above.
You can run the following example to verify you have created the correct triangle:
(check-within (spatial-sub-sample perfect-square 4)
(list (list 50 100) (list 250 166.66) (list 116.66 300)
(list 50 100)) 0.01)

Create a function spatial-rec which uses your above spatial-sub-sample to perform


recognition. Your geometric-match function from part 3 above should not need to change.
Add this bonus to recognize.rkt if you do it.

5. Enhancements

(a) Add another function to your code, n-best which consumes a gesture, a template-library,
and a number, n, and produces an n-best list, i.e. a list of n gestures ordered from closest
to nth-closest match.
(b) Try creating your own set of templates. For example, you can create the digits from
0...9 as unistroke gestures as follows:

Just enter these one-by-one at https://cs.uwaterloo.ca/~lank/canvas.html


and copy them into a new template library, digit-library, i.e.
(define digit-library (list
(list ’0 <paste the 0-gesture here>)
...
))

This becomes your new TemplateLibrary to recognize digits.


(c) In the above example, we just recognize a single gesture. A word would be a sequence of
gestures corresponding to letters. You could also add a space gesture (e.g. a horizontal

CS 135 — Fall 2020 Assignment 04 10


line), and even a period (if gesture-length is “short enough”, then it’s a period). So you
could modify your recognizer so that it took in a word or sentence and provided the
recognition back to you.
Of course, to do this elegantly, you might want to modify the JavaScript app to create
a larger canvas and to accept multiple strokes in a larger list. You can download the
JavaScript app, check it out, and modify it if you want. By the end of CS 136 (next term),
you would know all you need to know to modify the canvas, to port your recognizer
from Racket to JavaScript (JavaScript and C aren’t that different), and to have a neat
little app that you can show at co-op interviews.

The program that you created in question 3 implements a geometric template matcher, or,
in more formal artificial intelligence terms, “an instance-based nearest-neighbor classifier
with a 2-D Euclidean distance function”. The algorithm that you created above is very similar
to an algorithm called the 1$ recognizer created by Jacob Wobbrock of the University of
Washington, Andy Wilson of Microsoft Research, and Yang Li of Google Research. You can
read more about the algorithm that you recreated here:
http://depts.washington.edu/acelab/proj/dollar/index.html
The big difference between your algorithm and the 1$ recognizer is that the 1$ recognizer also
seeks to “pose-align” the bounding box, i.e to rotate the template to find the best alignment
with the gesture. The neat thing about the 1$ recognizer is that it implements a geometric
template recognizer in about 100 lines of code.
More generally, up to this point in CS 135, you’ve learned quite a bit of programming. In fact,
check out this video on support vector machines, a concept from machine learning (fourth
year course).
https://youtu.be/efR1C6CvhmE
You already know most of the basic programming concepts necessary to implement support
vector machine algorithms. A list can be an n-dimensional data set representing a sample that
you want to classify (based on the above video). For example, if you are trying to classify
people, it could be their age (1D), or it could be their age and height (2D), or it could be
their age, height and shoe size (3D), etc. If you have n-features, it’s just a list of n values
(listof Num). You can move this data into higher dimensions by manipulating the data
according to a function that you are given (see, for example, the polynomial kernel in the
video). If you can compute the Euclidean distance between two points in (x, y), then you can
do it in any number of dimensions – it’s the same formula.
Once you understand what concepts like cross-validation, the kernel trick, hyperplanes, etc.
are (and that’s what you’ll study in a fourth year machine learning course), then the actual
process of implementing something like support vector machines relies, in large part, on the
programming concepts you have learned to date in CS 135.
Before you get too excited, this is not to say that we won’t teach you a lot over the next four
years. We will! (At least we hope so). In particular, we will teach you how to take what

CS 135 — Fall 2020 Assignment 04 11


you’ve learned in this course (and the next two or three terms) and apply it to solve real
problems of increasing complexity. But we would like to say that, if you are doing well to this
point in this course, then take a moment to pat yourself on the back, because you’ve learned a
lot already.
Happy programming!

CS 135 — Fall 2020 Assignment 04 12

You might also like