Assignment 5
New!

Due: Friday, April 3

This assignment contains one programming exercise (the ubbi dubbi exercise from the original Assignment 5) and an alternative programming problem for the virus simulation problem that was included on the original assignment. You can turn in your solutions any time on 4/3/20, and only need to submit an electronic copy of your code files. Your electronic submission is described in the section Uploading your completed work (there is no Google form to submit for this assignment). If you need an extension on this assignment, please contact Ellen or Stella. You do not need to work with a partner on any of this assignment work.

Reading

The following material from the fifth or sixth edition of the text is useful to review for this assignment: pages 187-188, 192-196, and 200-202. You should also review notes and examples from Lectures #10, 12, and 13, and Labs #5 and 6.

Getting Started: Download assign5_new

For the exercise on this assignment, create your own folder named assign5_exercise. You will create a code file named ubbi.m from scratch and place it in your assign5_exercise folder. When you are ready to start the problem, use Cyberduck to connect to the CS server and download a copy of the assign5_new folder onto your Desktop. This folder contains four files for the programming problem in this assignment: two code files named cityDistance.m and convertCoords.m, a data file named cities.mat, and an image file named mapUS.png.

Uploading your completed work

When you have completed the work for this assignment, your assign5_exercise folder should contain one code file named ubbi.m and your assign5_new folder should contain its original contents (the four files noted above) plus six new code files that you will write, named printCityInfo.m, printCities.m, largestCity.m, nearbyCities.m, displayCities.m, and testCities.m. Use Cyberduck to connect to the CS file server and navigate to your cs112/drop/assign05 folder. Drag your assign5_exercise and assign5_new folders to this drop folder. More details about this process can be found on the webpage on Managing Assignment Work.

Exercise: ubbi dubbi

The old PBS show Zoom taught kids how to speak ubbidubbi, enabling them to speak to each other without their parents understanding what they were saying. You're going to write an ubbidubbi converter in MATLAB! (Never too late to learn a new language!) If you're interested, here's a YouTube video on how to learn ubbidubbi. (Ubbidubbi was also used by Penny and Amy in season 10 episode 7 of The Big Bang Theory to have a secret conversation to counter Sheldon and Leonard's use of Klingon.)

Write a function called ubbi that takes a string as input and returns the ubbidubbified string as output. The rule for conversion is to insert 'ub' in front of every vowel. This clip of MATLAB's command window shows what the function ubbi should do:

>> newcs112 = ubbi('cs112')
newcs112 =
cs112
>> 
>> test = ubbi('I am flying to America!')
test =
ubI ubam flubyubing tubo ubAmuberubicuba!
>> 

Note in the examples above that both lower case and upper case vowels work. You can put all the vowels into a single string, which MATLAB will store in a vector of characters (see examples from Lecture #10, of the 'Stella' string and our modification of makeBullseye to use a string of colors). Also recall that using square brackets allows for string concatenation, as in:

>> disp(['a' 'whole' 'bunch'])
awholebunch

The == operator can be used to compare a string with a single character. In this case, it returns a logical vector that contains 1's at the locations where the character appears in the string, for example:

>> 'banana' == 'a'
ans =
    0     1     0     1     0     1

Your function ubbi should still work (i.e. no MATLAB error messages are generated) if the user does not supply an input string, as shown in the example below:

>> ubbi
Please supply a string to ubbidubbify 
>> 
>> ubbi('cs112 makes me so happy!')
ans =
cs112 mubakubes mube subo hubappuby!
>> 
Hint: a for statement can be used to loop through the characters of a string, and a new string can be created by starting with an empty string and adding characters each time the body of the loop is executed. This is illustrated in the following code example that prints the string 'allets' (the reverse of 'stella').
newstring = '';
for letter = 'stella'
    newstring = [letter newstring];
end
disp(newstring)

Problem: Analyzing US Cities

In this problem, you will work with a vector of structures that contains information about the 978 cities in the US whose population is at least 50,000. The cities.mat file in the assign5_new folder contains one variable named cityData that is this vector of structures. Each structure has fields for the name of the city, state (two-letter abbreviation), location (vector of latitude and longitude), population (pop), and density (people per square mile). The following screen shot illustrates the loading of the data file and the MATLAB printout for the first and last structures in the cityData vector:



To begin, set your Current Folder to the assign5_new folder and start a new script named testCities.m to add code to test the four functions and script described below. (These functions can be written independently, as they do not depend on one another.) Every function needs to access the cityData variable that stores the information about all the cities. Rather than pass this variable as an input to each function, we will declare this variable as global, enabling it to be accessed inside function files. To do this, first add these statements to the top of your testCities.m script:

global cityData
load cityData.mat

Then, as you define each function, place the same variable declaration at the start of the body of the function, as shown in this example:

function [output1, output2] = myFunction (input1, input2)
% comments about myFunction
global cityData
...

You will then be able to refer to cityData within the rest of your function code.

(1) Print information about a single city

Define a new function named printCityInfo that has two inputs and no outputs. The two inputs are (1) a string that is the name of a city and (2) the two-letter abbreviation of the state name. This function should print all the information about the input city using disp statements. Your function should print a message like "city not found" if the city or state name are not valid. The loop that searches for the input city (and state) should terminate immediately when the requested city is found (this can be done with a for loop that contains a break statement, or a while loop). Use strcmp to compare two strings. The following printout illustrates this function in action (add your own tests to the testCities.m script):

>> printCityInfo('Boston', 'MA')
name: Boston
state: MA
location: 42.3188     -71.0846
population: 4637537
density: 5472
>> printCityInfo('Ellen', 'WA')
city not found
>> 

(2) Print all the cities in a state

Define a new function named printCities that has one input and no outputs. The one input is the two-letter abbreviation of a state name. This function should print the name (with disp) of each city in the requested state. It should print a message like "state not found" if the input state is not valid. The following printout illustrates this function in action (add your own tests to the testCities.m script):

>> printCities('UT')
Provo
West Jordan
Logan
Salt Lake City
Sandy
Lehi
Layton
St. George
South Jordan
West Valley City
Millcreek
Orem
Taylorsville
Ogden
>> printCities('XY')
state not found
>> 

(3) Largest city in a state

Define a new function named largestCity that has one input and two outputs. The input is the two-letter abbreviation of a state name. The outputs are (1) city name and (2) population. This function should return the name and population of the largest city in the requested state. It should print a message like "state not found" and return an empty string for the city name and population of zero if the input state is not valid. The following printout illustrates this function in action:

>> [city, pop] = largestCity('MT')
city =
    'Billings'
pop =
      120800
>> [city, pop] = largestCity('XY')
state not found
city =
  0×0 empty char array
pop =
     0
>> 

(4) Print nearby cities

Define a new function named nearbyCities that has three inputs and no outputs. The inputs are (1) the name of a city, (2) the two-letter abbreviation of a state name, and (3) a distance in miles. This function should print the name of each city that is within the requested distance of the input city. This function should print a message like "city not found" if the city and state names are not a valid combination. To assist with this function, the cityDistance function (given in the assign5_new folder) calculates the distance between two cities from their latitude and longitude values using the Haversine formula. The following printout illustrates both the cityDistance and nearbyCities functions in action (the printCityInfo function is first used to get latitude and longitude vectors for Boston and Chicago, to then illustrate the calculation of distance between these two cities, in miles). Below the printout is a hint for how to implement this function. Add your own tests to the testCities.m script:

>> printCityInfo('Boston', 'MA')
name: Boston
state: MA
location: 42.3188     -71.0846
population: 4637537
density: 5472
>> printCityInfo('Chicago', 'IL')
name: Chicago
state: IL
location: 41.8373     -87.6862
population: 8675982
density: 4612
>> dist = cityDistance([42.3188 -71.0846], [41.8373 -87.6862])
dist =
  850.7367
>> nearbyCities('Burlington', 'VT', 100)
Glens Falls, NY
>> nearbyCities('Denver', 'CO', 200)
Cheyenne, WY
Aurora, CO
Thornton, CO
Commerce City, CO
Castle Rock, CO
Colorado Springs, CO
Lakewood, CO
Pueblo, CO
Highlands Ranch, CO
Greeley, CO
Boulder, CO
Longmont, CO
Centennial, CO
Broomfield, CO
Lafayette, CO
Loveland, CO
Parker, CO
Arvada, CO
Fort Collins, CO
Westminster, CO
>> nearbyCities(cityData, 'Stella', 'CO', 200)
city not found
>>

The following outline provides a hint for a strategy that you can use to implement this function:

for each city in the vector of structures (let's refer to it as cityA)
   if cityA has the requested city name and state 
      for each city in the vector of structures (let's refer to it as cityB)
          if cityB is different from cityA and the distance between cityA and cityB 
                    is within the input distance
             print the name and state for cityB

(5) Display cities on a US map

Create a script file named displayCities.m to display the following image of a US map with a scatter plot superimposed that shows a dot at the location of each city stored in cityData (dots are not shown here):



Graphics (like a scatter plot) can be drawn superimposed on an image by first displaying the image, then specifying hold on, and then calling graphics commands (like plot or scatter) with x,y coordinates that are specified in the coordinate frame of the image. When loaded, the above image will be stored in a matrix with 884 rows and 1344 columns, so any superimposed graphics that we want to appear on this image will need to have x coordinates in the range of 1 to 1344, and y coordinates in the range of 1 to 844. The latitude and longitude values for US cities are not within this range, but you are given a function named convertCoords in the assign5_new folder that does this conversion for you. In your displayCities.m script, follow these steps to complete the task of showing the city locations on the US map:

  1. collect the latitude and longitude values from all 978 cities into two separate vectors, i.e., one vector that contains the 978 latitude values and a second vector that contains the 978 longitude values (it is ok to include cities in Alaska and Hawaii, even though they will not appear on the above map)
  2. use the convertCoords function to convert the latitude and longitude values to x,y coordinates. Suppose the latitude values are stored in a vector named lats and longitude values are stored in a vector named longs, and you want to create vectors named xc and yc to store the x,y coordinates. This can be done with the following function call: [xc, yc] = convertCoords(lats, longs);
  3. read in the mapUS.png image file (stored in the assign5_new folder) using imread, display it with imshow, and set hold on
  4. call the scatter function to create a scatter plot using the computed x,y coordinates. Try a dot size in the 10-30 range and draw the dots as 'filled'

To keep all your testing code in one place, you can add a statement to your testCities.m script to execute the displayCities.m script.