Assignment 5
Discussion on Tuesday 2/17/26
Workshop in class on Wednesday 2/18/26
Submission due by 9:00 p.m. on Friday 2/20/26.
Preliminaries
In your work on this assignment, make sure to abide by the collaboration policies of the course.
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 discussed/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.
Programming 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.
-
Every program file must begin with a descriptive header comment that includes your name, username/BU email, and a brief description of the work contained in the file.
-
Every function must include a descriptive docstring that explains what the function does and identifies/defines each of the parameters to the function.
-
Your functions must have the exact names specified below, 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 some of the names include an underscore character (
_). -
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.
-
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.
-
You must test each function after you write it.
Warnings: Individual Work, Generative AI, and Academic Conduct!!
-
This is an individual assignment. You may discuss the problem statement/requirements, Python syntax, test cases, and error messages with your classmates. However, each student must write their own code without copying or referring to other student’s work.
-
It is strictly forbidden to use any code that you find from online websites including but not limited to as CourseHero, Chegg, or any other sites that publish homework solutions.
-
It is strictly forbidden to use any generative AI (e.g., ChatGPT, Claude, Gemini, CoPilot or any similar tools**) to write solutions for any assignment.
Students who submit work that is not authentically their own individual work will earn a grade of 0 on this assignment and a reprimand from the office of the Dean.
Objective and Overview
Objective: Develop additional practice with creating a user defined class, operator overloading and working with 2-dimensional lists.
Overview: In this assignment, you will re-package much of the work that you did in assignment 4, i.e., writing functions to work with matrices as 2-dimensional lists.
Task 1: A Matrix class
90 points; individual-only
Do all of your work for this assignment in the file a5task1.py.
Consider a class Matrix, which encapsulates the idea of a 2-dimensional matrix object.
The matrix will support a wide-variety of operations, including printing itself out,
row-based operations, and some linear-algebra operations.
Important Note: About re-using your own code
-
In this assignment, we are not specifying each method that you need to write. Rather, we are providing examples/use cases of how the
Matrixobject should work. -
You have previously written all of the relevant 2-dimensional list operations previously in a4[Assignment 4], and you should re-use your work from Assignment 4 as needed by implementing those algorithms as part of this class’s methods.
-
You must NOT import any functions from Assignment 4. Rather, you must implement the algorithms as methods on your
Matrixclass, and be sure to create methods that satisfy the requirements (i.e., parameter lists) as shown in the example that follow.
- Object creation, string representation, and testing for equality.
Here is some client code that creates and uses some Matrix objects, so you can see
how it might work:
>>> A = Matrix([[1,2,3],[4,5,6], [7,8,9]]) >>> A # evaluate A to obtain it's string repesentation! What method does this? [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]] >>> # create a second matrix object, identified by Z >>> B = Matrix([[1,2,3],[4,5,6], [7,8,9]]) >>> A == B # test for equality. What method does this? True
- Basic row operations.
Here is some client code that creates a Matrix and demonstrates the basic row operations
that it must support. Note in particular wheter an operation modifies the Matrix or
returns a new Matrix.
>>> A = Matrix([[1,2,3],[4,5,6], [7,8,9]]) >>> A.add_row_into(2,0) # adds row 2 into row 0 >>> A # evaluate A to obtain it's string repesentation [[8.00, 10.00, 12.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]] >>> A.add_mult_row_into(-1,2,0) # add -1 times row 2 into row 0 >>> A [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]] >>> A.swap_rows(1,2) # swap rows 1 and 2 Swap row 1 with row 2. >>> A [[1.00, 2.00, 3.00] [7.00, 8.00, 9.00] [4.00, 5.00, 6.00]]
- Arithmetic operations:
Here is some client code that creates a Matrix and demonstrates the basic arithmetic operations
that it must support. Note in particular wheter an operation modifies the Matrix or
returns a new Matrix.
>>> A = Matrix([[1,2,3],[4,5,6], [7,8,9]]) >>> A # evaluate A to obtain it's string repesentation [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]] >>> A.add_scalar(1) # this operation returns a new Matrix [[2.00, 3.00, 4.00] [5.00, 6.00, 7.00] [8.00, 9.00, 10.00]] >>> A.mult_scalar(5) # this operation returns a new Matrix [[5.00, 10.00, 15.00] [20.00, 25.00, 30.00] [35.00, 40.00, 45.00]] >>> A # evaluate A to obtain it's string repesentation -- notice that it is unchanged! [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]]
- Operator overloading:
Implement the following operators on your Matrix class, by providing the appropriate
operator overload methods.
>>> A = Matrix([[1,2,3],[4,5,6], [7,8,9]]) >>> A # evaluate A to obtain it's string repesentation [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]] >>> A + 1 # overload the + operator; this operation returns a new Matrix [[2.00, 3.00, 4.00] [5.00, 6.00, 7.00] [8.00, 9.00, 10.00]] >>> A - 1 # overload the - operator; this operation returns a new Matrix [[0.00, 1.00, 2.00] [3.00, 4.00, 5.00] [6.00, 7.00, 8.00]] >>> A * 5 # overloaded the * operator to do element-wise multiplication by scalar; this operation returns a new Matrix [[5.00, 10.00, 15.00] [20.00, 25.00, 30.00] [35.00, 40.00, 45.00]] >>> A / 2 # overload the / operator, element-wise division by scalar; this operation returns a new Matrix [[0.50, 1.00, 1.50] [2.00, 2.50, 3.00] [3.50, 4.00, 4.50]] >>> A # evaluate A to obtain it's string repesentation -- notice that it is unchanged! [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]]
- Matrix algebra operations:
Implement the following matrix-algebra operations on your Matrix class.
>>> A = Matrix([[1,2,3],[4,5,6], [7,8,9]]) >>> A # evaluate A to obtain it's string repesentation [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]] >>> A.transpose() # note: this is returning a new Matrix, but not changing A [[1.00, 4.00, 7.00] [2.00, 5.00, 8.00] [3.00, 6.00, 9.00]] >>> A # evaluate A to obtain it's string repesentation; notice it has not changed! [[1.00, 2.00, 3.00] [4.00, 5.00, 6.00] [7.00, 8.00, 9.00]]
Implement the dot-product operation, which requires 2 matrices:
>>> B = Matrix([[4,5,6],[1,2,3]]) >>> C = Matrix([[7,8],[9,10],[11,12]]) >>> B # evaluate B to obtain it's string repesentation! [[4.00, 5.00, 6.00] [1.00, 2.00, 3.00]] >>> C # evaluate C to obtain it's string repesentation! >>> [[7.00, 8.00] [9.00, 10.00] [11.00, 12.00]] >>> B.dot_product(C) [[139.00, 154.00] [58.00, 64.00]] >>> B * C # this operator does dot-product, when appropriate! [[139.00, 154.00] [58.00, 64.00]]
- Class-level methods:
The following methods are class-level methods (as opposed to instance methods),
i.e., they do not exist on an instance of a Matrix object but rather on the class itself.
These methjods will not have the implicit parameter self. The methods must create
and return a new Matrix object as their result/return value.
>>> Matrix.zeros(4) [[0.00, 0.00, 0.00, 0.00] [0.00, 0.00, 0.00, 0.00] [0.00, 0.00, 0.00, 0.00] [0.00, 0.00, 0.00, 0.00]] >>> Matrix.ones(3) [[1.00, 1.00, 1.00] [1.00, 1.00, 1.00] [1.00, 1.00, 1.00]] >>> Matrix.identity(5) [[1.00, 0.00, 0.00, 0.00, 0.00] [0.00, 1.00, 0.00, 0.00, 0.00] [0.00, 0.00, 1.00, 0.00, 0.00] [0.00, 0.00, 0.00, 1.00, 0.00] [0.00, 0.00, 0.00, 0.00, 1.00]]
- Drawing random numbers:
Write methods to draw a Matrix of random integers or random floating point numbers.
Your methods should be class-level methods that return a new Matrix as their result.
Also, these methods must accept default parameters as per these examples:
>>> # draw a 3x5 matrix of random integers in the range of 1 to 6 (inclusive) >>> Matrix.random_int_matrix(3,5,1,6) >>> [[1.00, 3.00, 5.00, 1.00, 3.00] [1.00, 5.00, 1.00, 4.00, 2.00] [6.00, 3.00, 2.00, 4.00, 1.00]] >>> >>> # draw a 2x3 matrix of random integers in the range of 1 to 10 (inclusive) >>> Matrix.random_int_matrix(2, 3) # using default parameters for low and high values [[7.00, 5.00, 4.00] [2.00, 9.00, 4.00]] >>> >>> Matrix.random_int_matrix(4) # using default parameters for columns, low, and high values [[8.00, 2.00, 1.00, 9.00] [2.00, 5.00, 6.00, 6.00] [9.00, 7.00, 7.00, 1.00] [6.00, 6.00, 4.00, 8.00]] >>> >>> Matrix.random_float_matrix(2, 2) # draw uniformly distributed random numbers between 0 and 1 [[0.33, 0.79] [0.87, 0.70]] >>> >>> Matrix.random_float_matrix(5) # use default value for columns [[0.09, 0.74, 0.76, 0.28, 0.48] [0.93, 0.30, 0.62, 0.61, 0.53] [0.06, 0.14, 0.23, 0.61, 0.25] [0.56, 0.54, 0.58, 0.23, 0.66] [0.20, 0.05, 0.99, 0.84, 0.43]]
Use the underlying functions random.randint(a, b) or random.random() as appropriate.
- Describing
Matrixdata:
Implemented a method called describe, which returns a string containing some useful
descriptive information about the values in a Matrix. Here are some examples:
>>> C = Matrix([[7,8],[9,10],[11,12]]) >>> print(C.describe()) [[7.00, 8.00] [9.00, 10.00] [11.00, 12.00]] dimensions: 3 X 2 sum of elements: 57 mean of elements: 9.5 column sums: [27, 30] column means: [9.0, 10.0] >>> >>> rand = Matrix.random_float_matrix(5) >>> print(rand.describe()) [[0.76, 0.93, 0.46, 0.97, 0.17] [0.42, 0.16, 0.45, 0.54, 0.67] [0.12, 0.58, 0.81, 0.60, 0.40] [0.55, 0.87, 0.81, 0.03, 0.93] [0.00, 0.90, 0.81, 0.62, 0.66]] dimensions: 5 X 5 sum of elements: 14.212557816892073 mean of elements: 0.5685023126756829 column sums: [1.8515784971027802, 3.4403493105068894, 3.337016260450002, 2.7601580159609638, 2.8234557328714374] column means: [0.37031569942055603, 0.6880698621013779, 0.6674032520900004, 0.5520316031921928, 0.5646911465742874]
Feel free to add additional elements to the output produced by describe!
OPTIONAL These operations require the “optional” functions that were part of assignment 4. They are not required in this assignment, but if you did the optional tasks in assignment 4, these would be very satisfying to implement.
>>> A.determinant() 10.0 >>> A.inverse() [[0.20, 0.20, -0.00] [-0.20, 0.30, 1.00] [0.20, -0.30, 0.00]] >>> I = Matrix.identity(3) >>> I == A * A.inverse() True
Submitting Your Work
10 points; will be assignmed by code review.
Use the link to GradeScope (left) to submit your work.
Be sure to name your files correctly!
Under the heading for Assignment 6, attach these: required files:
-
Your
a5task1.pyPython code file -
All
.csvdata files used by your program.
When you upload the files, the autograder will test your functions/programs.
Warning: Beware of Global print statements
- The autograder script cannot handle
printstatements in the global scope, and their inclusion causes this error:

* Why does this happen? When the autograder imports your file, the `print` statement(s) execute (at import time), which causes this error. * You can prevent this error by not having any `print` statements in the global scope. Instead, create an `if __name__ == '__main__':` section at the bottom of the file, and put any test cases/print statements in that controlled block. For example: if __name__ == '__main__': ## put test cases here: print('fv_lump_sum(0.05, 2, 100)', fv_lump_sum(0.05, 2, 100)) * `print` statements inside of functions do not cause this problem.
Notes:
- You may resubmit multiple times, but only the last submission will be graded.