MF 602

Assignment 1

Objective and Overview

Objective: The objective of this assignment is to develop competence with basic Python syntax, definining and testing functions that work with numeric data. Further, you will develop a client program that takes inputs from the user, calls functions, and prints outputs to the console.

Preliminaries

For each problem in this problem set, we will be writing or evaluating some Python code. You are encouraged to use the Spyder IDE which will be discuss/presented in class, but you are welcome to use another IDE if you choose.

If you have questions while working on this assignment, please post them on Piazza! This is the best way to get a quick response from your classmates and the course staff.


General Guidelines

  • Refer to the class Coding Standards for important style guidelines. The grader will be awarding/deducting points for writing code that comforms to these standards.

  • Include comments at the top of the file that are similar to the ones that we gave you at the top of a1task1.py.

  • Your functions must have the exact names that we have specified, or we won’t be able to test them. Note in particular that the case of the letters matters (all of them should be lowercase), and that you should use an underscore character (_) wherever we have specified one (e.g., in convert_from_inches).

  • Each of your functions should include a docstring that describes what your function does and what its inputs are.

  • If a function takes more than one input, you must keep the inputs in the order that we have specified.

  • You should not use any Python features that we have not discussed in class or read about in the textbook.

  • Unless expressly stated, your functions do not need to handle bad inputs – inputs with a type or value that doesn’t correspond to the description of the inputs provided in the problem.

  • Make sure that your functions return the specified value, rather than printing it. Unless it is expressly stated in the problem, none of these functions should use a print statement.

Important note regarding test cases and Gradescope:

  • You must test each function after you write it. Here are two ways to do so:

    • Run your file after you finish a given function. Doing so will bring you to the Shell, where you can call the function using different inputs and check to see that you obtain the correct outputs.
    • Add test calls to the bottom of your file, inside the if __name__ == '__main__' control struture. For example:

      if __name__ == '__main__':
      
          print("mystery(6,7) returned", mystery(6,7))
      

      These tests will be called every time that you run the file, which will save you from having to enter the tests yourself. We have given you an example of one such test in the starter file.

  • You must not leave any print statements in the global scope. This will cause an error with the Gradescope autograder. Make sure all of your print statements are inside a function scope or insude the if __name__ == '__main__' control struture.



Task 1: Indexing and slicing puzzles

20 points; individual-only

This problem will give you practice with indexing and slicing. Begin by downloading this file: a1task1.py. Open it in Spyder, as demonstrated in class.

List puzzles
The first half of the problem focuses on lists. In particular, you will be constructing new lists from the following:

pi = [3, 1, 4, 1, 5, 9]
e = [2, 7, 1]

We’ve given you these lines in a1task1.py. In addition, we’ve provided the answer to the first puzzle (puzzle 0). You should add in the answers for the remaining puzzles, following the format that we’ve given you for puzzle 0.

The expressions that you construct must only use pi and e and the following list operations:

We encourage you to try using as few operations as possible, to keep your answers elegant and efficient. However, you will get full credit for any expression that follows the rules above and produces the correct result.

Before getting started, you should run a1task1.py in Spyder. This will make the lists pi and e available to you in the Python Shell.

Here are the puzzles:

  1. Use pi and/or e to create the list [2, 5, 9], and assign it to the variable answer0. We’ve given you the code for this puzzle.

  2. Use pi and/or e to create the list [2, 7] and assign it to the variable answer1. Your answer should follow the format that we’ve given you for problem 0. In other words, it should look like this:

    # Puzzle 1:
    # Creating the list [2, 7] from pi and e
    answer1 =
    

    where you put the appropriate expression to the right of the assignment operator (=). Please leave a blank line between puzzles to make things more readable.

  3. Use pi and/or e to create the list [5, 4, 3], and assign it to the variable answer2. Here again, make sure to follow the correct format, and to leave a blank line between puzzles.

  4. Use pi and/or e to create the list [3, 5, 7], and assign it to the variable answer3. (Optional challenge: See if you can do this with just three list operations!)

  5. Use pi and/or e to create the list [1, 2, 3, 4, 5], and assign it to the variable answer4. (Optional challenge: See if you can do this with just three list operations!)

String puzzles
The second half of the problem focuses on strings. In particular, you will be working with the following strings:

b = 'boston'
u = 'university'
t = 'terriers'

We’ve given you these lines in a1task1.py, along with the answer to the first string puzzle (puzzle 5). Run the file as needed so that the strings will be available for you to experiment with in Spyder.

The expressions that you construct for the remaining puzzles must only use the above strings and the following string operations:

Here again, you will get full credit for any expression that follows the rules above and produces the correct result, but we encourage you to try using as few operations as possible.

Here are the puzzles:

  1. Use b, u, and/or t to create the string 'bossy', and assign it to the variable answer5. We’ve given you the following code for this puzzle:

    # Puzzle 5:
    # Creating the string 'bossy'
    answer5 = b[:3] + t[-1] + u[-1]
    

    Note that our answer involves 5 operations: 2 uses of indexing, 1 slice, and 2 concatenations with +. (It’s actually possible to solve this puzzle using only 3 operations. Give it a try if you have time!)

  2. Use b, u, and/or t to create the string 'universe', and assign it to the variable answer6. (Our best answer uses 3 ops.) Here again, make sure to follow the correct format, and to leave a blank line between puzzles.

  3. Use b, u, and/or t to create the string 'roster', and assign it to the variable answer7. (Our best: 5 ops.)

  4. Use b, u, and/or t to create the string 'boisterous', and assign it to the variable answer8. (Our best: 8 ops.)

  5. Use b, u, and/or t to create the string 'yesyesyes', and assign it to the variable answer9. (Our best: 4 ops.)

  6. Use b, u, and/or t to create the string 'trist', and assign it to the variable answer10. (Our best: 4 ops.)

After finishing all of the puzzles, make sure to run your a1task1.py file to check that the correct outputs are printed.

Task 2: Functions with numeric inputs

20 points; individual-only

In this problem you will write a collection of simple functions that operate on numeric inputs.

Begin by downloading this file: a1task2.py. Open it in your IDE, following the procedure outlined in class.

Here are the descriptions of the functions:

  1. (example) Write a function opposite(x) that takes a number x as its input and returns the opposite of its input. We have given you this example function in the starter file.

  2. Write a function cube(x) that takes a number x as its input and returns the cube of its input (i.e., x raised to the power of 3). For example:

    >>> cube(2)
    8
    >>> print(cube(-5))
    -125
    

    Warning

    Make sure that your function returns the correct value rather than printing it. If your function is printing the return value, you will see the word None as part of the output for the second test above. If you are seeing None in your output, you must fix your function so that it uses a return statement rather than a print statement. This same warning applies to all of the functions that you will write for this assignment.

    Note: You should leave one or two blank lines between functions to make things more readable, and make sure to include a docstring like the one in our example function.

    Warning

    Make sure that you use the correct amount of indentation. In particular, your docstrings should be indented by 4 spaces as shown in our code for opposite, so that they line up with the code inside the function.

  3. Write a function slope(x1, y1, x2, y2) that takes four numeric inputs that specify the coordinates of two points (x1, y1) and (x2, y2) in the Cartesian plane, and that returns the slope of the line formed by those two points. Recall that slope is given by the following formula:

             y2 - y1
    slope = ---------
             x2 - x1
    

    Examples:

    >>> slope(2, 3, 4, 7)     # line between (2,3) and (4,7)
    2.0
    >>> slope(7, 2, 3, 4)     # line between (7,2) and (3,4)
    -0.5
    >>> print(slope(2, 3, 5, 3))
    0.0
    

    Note

    In Python, if you divide 0 by a negative number using the / operator, the result is -0.0. You don’t need to worry if your slope function returns -0.0 for cases in which the slope is 0.

    Also, if you divide by 0, the program will crash. You do not need to handle this case for this week’s assignment.

  4. Write a function cylinder_volume(diameter, height) that calculates and returns the volume of a cylinder of a given diameter and height.

    The volume of a cylinder is given by: v = π r^2 h.

    You can access the constant math.pi by importing the math module at the top of your file:

    import math
    

    Test cases:

    >>> cylinder_volume(10, 10) 
    785.3981633974483
    >>> cylinder_volume(20, 10)
    3141.5926535897934
    

    Do not round your answer, simply return the floating point value.


Task 3: Functions for time value of money calculations

40 points; individual-only

Create a new Python code file and save it with the name a1task3.py. Remember to create a header comment at the top of your file with your name, email address, assignment number, and a brief description. Write all of the functions for this task in the file a1task3.py.

  1. Write a function fv_lump_sum(r, n, pv) to calculate and return the future value of a lump sump pv invested at the periodic rate r for n periods. Recall the equation for the future value of a lump sum: FVFORUMULA

Examples:

    >>> # $100 at 5% rate for 2 years
    >>> fv_lump_sum(0.05, 2, 100)
    110.25
    >>> # $400 at 8% APR for 20 years (with monthly compounding)
    >>> fv_lump_sum(0.08/12, 20*12, 400)
    1970.7211083238797
  1. Write a function pv_lump_sum(r, n, fv) to calculate and return the present value of a lump sum fv to be received in the future, discounted at the periodic rate r for n periods. Recall the equation for the present value of a lump sum:

    PVFORUMULA

Examples:

    >>> # $1000 to be received in 5 years at 6% per year
    >>> pv_lump_sum(0.06, 5, 1000)
    747.2581728660571
    >>> # $500 received in 5 years, 6% APR, semi-ann. compounding
    >>> pv_lump_sum(0.06/2, 5*2, 500)
    372.0469574483625
  1. Write a function fv_annuity(r, n, pmt) to calculate and return the future value of an annuity of pmt to be received each period for n periods, invested at the periodic rate r. Recall the equation for the future value of an annuity is: FVANNUITY

    Examples:

    >>> # invest $100 per year for 5 years at 4% interest
    >>> fv_annuity(0.04, 5, 100)
    541.6322560000003
    >>> # invest $100 per month for 10 years at 9% APR
    >>> fv_annuity(0.09/12, 10*12, 100)
    19351.42770833082
    
  2. Write a function pv_annuity(r, n, pmt) to calculate and return the present value of an annuity of pmt to be received each period for n periods, discounted at the rate r. Recall the equation for the present value of an annuity is: PVANNUITY

    Examples:

    >>> # pv of 30 payments of $250 per year, 5% interest
    >>> pv_annuity(0.05, 30, 250)
    3843.1127567207104
    >>> # pv of 60 payments of $471.75 per month, 0.9% APR
    >>> pv_annuity(0.009/12,60, 471.75)
    27667.441596482677
    
  3. Write a function annuity_payment(r, n, pv) that calculates the annuity payment for a present value of pv to be repaid at a periodic interest rate of r for n periods. Recall the equation for the annuity payment is:

PMT

Examples:

    >>> # annuity payment for pv of $1,000 for 10 year at 5%
    >>> annuity_payment(0.05, 10, 1000)
    129.5045749654566
    >>> # annuity payment for pv of $27,667 for 60 months at 0.9% APR
    >>> annuity_payment(0.009/12, 60, 27667.44)
    471.7499727788093


Task 4: The Life-Cycle Model of Saving and Consumption

20 points; individual-only

Background/Overview

The Life-Cycle Model was first developed by Nobel Prize winning economist Franco Modigliani in the 1950s to help explain household’s decisions about spending and saving over time. Modigliani observed that households accumulate wealth during their working years and spend down that wealth during their retirement years, with the goal of maintaining a relatively smooth standard of living for all years, i.e., to keep spending the same amount year in and year out, even when they stop working.

To find this smooth level of consumption, we will need to find a household’s total economic resources, which are a combination of human capital (the value of future income) and financial assets. Given a household’s total economic, we can calculate the sustainable (smooth) amount of spending for each year of life until some maximum age.

Assumptions: We assume to work in real (inflation-adjusted dollars) and to use an inflation-adjusted risk free interest rate. As a simplification, we also assume no taxes.

Here are two examples to give you an idea of how this program should work:

Example 1: 35 year-old, mid-career, with $150,000 of assets:

    Enter the current inflation-indexed risk-free rate of return: 0.03
    Enter your age now: 35
    Enter your expected retirement age: 67
    Enter your current annual income: 83000

    You have 32 remaining working years with an income of $83000 per year.
    The present value of your human capital is about $1692267
    Enter the value of your financial assets: 150000
    Your economic net worth is: $1842267

    Your sustainable standard of living is about $64747 per year.
    To achieve this standard of living to age 100, you must save $18252 per year.

Example 2: 22-year old, first job, $100,000 of student loan debt (i.e., negative assets):

    Welcome to the Life-Cycle Sustainable Spending Calculator.

    Enter the current inflation-indexed risk-free rate of return: 0.03
    Enter your age now: 22
    Enter your expected retirement age: 65
    Enter your current annual income: 45600

    You have 43 remaining working years with an income of $45600 per year.
    The present value of your human capital is about $1093574
    Enter the value of your financial assets: -100000
    Your economic net worth is: $993574

    Your sustainable standard of living is about $33108 per year.
    To achieve this standard of living to age 100, you must save $12491 per year.

Implementation Details

Do your work in a file called a1task4.py. Save your file in the same directory as your file from task 3 (above). At the top of your file (after the header comment), write the following statement to be able to access the functions you wrote in task 3:

    from a1task3 import *

Collecting User Input:

To collect an input from the user at the keyboard, we will use the built-in Python input function. This function displays a prompt to the user (text with instructions) and then waits for the user to type a value and hit the enter key. The input will always be received as a string, so we must convert it to numeric data type using the int or float function so that we can do arithmetic.

An example is given here:

    number = int(input("What is your favorite number? "))

Do the following tasks in a function called life_cycle_model. This function will interact with the user to collect inputs and display outputs, and will not have a return value.

  1. Collecting inputs for the rate of return, the user’s age now, retirement age, and current income. Print out the number of working years remaining and the income per year, formatted as whole dollars without cents.

  2. Calculate the human capital, which is the present value of the user’s lifetime income (i.e., an annuity). Use your pv_annuity function. Print out the present value of human capital.

  3. Prompt the user for the amount of current assets. If there are no assets, the user can enter 0, and if there are debts the user can enter a negative number. Calculate the economic net worth as human capital plus assets. Print out the economic net worth.

  4. Calculate the sustainable standard of living (i.e., consumption). Determine the number of years of consumption, as 100 - age. Use your annuity_payment function to calculate the amount of annual consumption that can be sustained from the economic net worth. Print out the annual standard of living.

  5. Calculate the amount of annual savings required. Savings is income minus consumption. Print out the savings.

Your program should be a self-contained execuatble file, i.e., when we run the file it should automatically call the life_cycle_model function. The best way to do this is using the form:

    if __name__ == '__main__':

        life_cycle_model()

At the bottom of your file. Test that this works by running your program!


Submitting Your Work

Submitting Your Work

Log in to GradeScope to submit your work.

Be sure to name your files correctly!

Under the heading for Assignment 1, attach each of the 4 required files to your submission.

When you upload the files, the autograder will test your program.

Notes:

Warnings about Submissions

  • Make sure to use these exact file names, or Gradescope will not accept your files. If Gradescope reports that a file does not have the correct name, you should rename the file using the name listed in the assignment page.

  • If you make any last-minute changes to one of your Python files (e.g., adding additional comments), you should run the file in Spyder after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.

  • If you submit an unrunnable file, Gradescope will accept your file, but it will not be able to auto-grade it. If time permits, you are strongly encouraged to fix your file and resubmit. Otherwise, your code will fail most if not all of our tests.

Important note regarding test cases and Gradescope:

  • You must test each function after you write it. Here are two ways to do so:

    • Run your file after you finish a given function. Doing so will bring you to the Shell, where you can call the function using different inputs and check to see that you obtain the correct outputs.
    • Add test calls to the bottom of your file, inside the if __name__ == '__main__' control structure. For example:

      if __name__ == '__main__':
      
          print("mystery(6,7) returned", mystery(6,7))
      

      These tests will be called every time that you run the file, which will save you from having to enter the tests yourself. We have given you an example of one such test in the starter file.

  • You must not leave any print statements in the global scope. This will cause an error with the Gradescope autograder. Make sure all of your print statements are inside a function scope or insude the if __name__ == '__main__' control structure.