Extra Homework 2
Due by 11:59pm on Tuesday, November 2
Instructions
Download extra02.zip. Inside the archive, you will find a file called , along with a copy of the Ok autograder.
Submission: When you are done, submit with
python3 ok --submit
. You may submit more than once before
the deadline; only the final submission will be scored.
Using Ok
The ok
program helps you test your code and track your progress.
The first time you run the autograder, you will be asked to log in with your
@berkeley.edu account using your web browser. Please do so. Each time you run
ok, it will back up your work and progress on our servers.
You can run all the doctests with the following command:
python3 ok
To test a specific question, use the -q
option with the
name of the function:
python3 ok -q <function>
By default, only tests that fail will appear. If you
want to see how you did on all tests, you can use the -v
option:
python3 ok -v
If you do not want to send your progress to our server or you have any
problems logging in, add the --local
flag to block all
communication:
python3 ok --local
When you are ready to submit, run ok
with the
--submit
option:
python3 ok --submit
Readings: You might find the following references useful:
Multiprocessing in Python using Ray
If you face timeout errors, you might want to use the timeout
flag while running the tests. Try --timeout 60
for a 60 seconds timeout.
Installing Ray
Before running the assignment you would need to installray
. You can simply run pip install -U ray
in your console. For further details, you can visit Ray Installation Guide.
Q1: Parallel Map
Implement parallel_map
, which takes a list arr
and a mapping function f
. It should return a new list computed by applying f
to each element of arr
. A serial version of the map function, serial_map
is given for your convenience in understanding the problem and also for evaluating your solution (along with the function func
). You must not change serial_map
or func
. Notice that ray
has been initialized for you with 4 processes and you do not need to call ray.init()
.
extra02.py
runs in one of the 4 processes allocated for Ray. Hence, you can assume you have 3 more unused processes for your use.
def serial_map(arr, f):
"""A serial implementation of map. DO NOT CHANGE.
>>> serial_map(list(range(10)), lambda x: x*2)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> serial_map(list(range(10)), lambda x: x**2)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
"""
return [f(x) for x in arr]
def func(x):
time.sleep(0.1)
return x
def parallel_map(arr, f):
"""A parallel implementation of map
>>> import time
>>> parallel_map(list(range(10)), lambda x: x*2)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> parallel_map(list(range(10)), lambda x: x**2)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> arr = list(range(50))
>>> start = time.time()
>>> res_s = serial_map(arr, func)
>>> end = time.time()
>>> time_s = end - start
>>> start = time.time()
>>> res_p = parallel_map(arr, func)
>>> end = time.time()
>>> time_p = end - start
>>> (res_s == res_p) == True
True
>>> (time_s/time_p > 1.5) == True
True
"""
"*** YOUR CODE HERE ***"
Q2: Parallel Merge Sort
Implement parallel_merge_sort
, which takes a list arr
and returns a new list with the elements sorted in ascending order. A serial version of the map function, sequential_merge_sort
is given for your convenience in understanding the problem and also for evaluating your solution. You must not change sequential_merge_sort
. Notice that ray
has been initialized for you with 4 processes and you do not need to call ray.init()
.
extra02.py
runs in one of the 4 processes allocated for Ray. Hence, you can assume you have 3 more unused processes for your use.
Hint: As we have a limited number of processes available, you might want to stop calling remote functions(which require new processes) after a certain depth of recursion.
def sequential_merge_sort(arr):
"""A parallel implementation of merge sort.
>>> arr = [1,5,3,2,4,9,8,7,6]
>>> sequential_merge_sort(arr)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
arr2 = arr.copy()
if len(arr) > 1:
# Finding the mid of the array
mid = len(arr)//2
# Dividing the array elements
L = arr[:mid]
# into 2 halves
R = arr[mid:]
# Sorting the first half
L = sequential_merge_sort(L)
# Sorting the second half
R = sequential_merge_sort(R)
i = j = k = 0
# Copy data to temp arrays L[] and R[]
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr2[k] = L[i]
i += 1
else:
arr2[k] = R[j]
j += 1
k += 1
# Checking if any element was left
while i < len(L):
arr2[k] = L[i]
i += 1
k += 1
while j < len(R):
arr2[k] = R[j]
j += 1
k += 1
return arr2
def parallel_merge_sort(arr):
"""A parallel implementation of merge sort.
>>> import random
>>> import time
>>> nums = list(random.sample(range(0, 1000000), 1000000))
>>> start = time.time()
>>> s1 = sequential_merge_sort(nums)
>>> time_s = time.time() - start
>>> start = time.time()
>>> s2 = parallel_merge_sort(nums)
>>> time_p = time.time() - start
>>> (s1==s2) == True
True
>>> (time_s/time_p > 1.5) == True
True
"""
"*** YOUR CODE HERE ***"
Optional Questions
Section 2.4.9 describes a system for solving equations with multiple free parameters using constraint programming, a declarative style of programming that asserts constraints and then applies a general method of constraint satisfaction. The following questions ask you to extend that system. The code for the system appears at the end of this homework.
Q3: Triangle Area
Implement the function triangle_area
, which defines a relation among
three connectors, the base b
, height h
, and area a
of a triangle,
so that a = 0.5 * b * h
:
def triangle_area(a, b, h):
"""Connect a, b, and h so that a is the area of a triangle with base b and
height h.
>>> a, b, h = [connector(n) for n in ('area', 'base', 'height')]
>>> triangle_area(a, b, h)
>>> a['set_val']('user', 75.0)
area = 75.0
>>> b['set_val']('user', 15.0)
base = 15.0
height = 10.0
"""
"*** YOUR CODE HERE ***"
Q4: Squarer
The multiplier
constraint from the readings is insufficient to model
equations that include squared quantities because constraint networks
must not include loops. Implement a new constraint squarer
that
represents the squaring relation:
def squarer(a, b):
"""The constraint that a*a=b.
>>> x, y = connector('X'), connector('Y')
>>> s = squarer(x, y)
>>> x['set_val']('user', 10)
X = 10
Y = 100
>>> x['forget']('user')
X is forgotten
Y is forgotten
>>> y['set_val']('user', 16)
Y = 16
X = 4.0
"""
"*** YOUR CODE HERE ***"
Use Ok to test your code:
python3 ok -q squarer
Q5: Pythagorean Theorem
Use your squarer
constraint to build a constraint network for the
Pythagorean theorem: a
squared plus b
squared equals c
squared:
def pythagorean(a, b, c):
"""Connect a, b, and c into a network for the Pythagorean theorem:
a*a + b*b = c*c
>>> a, b, c = [connector(name) for name in ('A', 'B', 'C')]
>>> pythagorean(a, b, c)
>>> a['set_val']('user', 5)
A = 5
>>> c['set_val']('user', 13)
C = 13
B = 12.0
"""
"*** YOUR CODE HERE ***"
Use Ok to test your code:
python3 ok -q pythagorean