2 Introduction
The purpose of this software design exercise is to write a Python program that follows the given formal specification. The given specification is for simulating the physics of a scene where a shape moves through 2D space. Simulations of this sort are used for animations and video game physics.
1
The simulation is based on the familiar equation for Newtonβs second law: F =md2r =mdv =ma
dt2 dt
where F is the unbalanced force, m is the mass, r is the position of the body, v is the velocity of the body and a is the acceleration of the body. The motion of the body is calculated about the centre of mass (cm). Figure 1 provides an example of the possible
output generated by the modules in this assignment.
Figure 1: Motion simulation for an object shown as plots of x vs t, y vs t and y vs x
For those that are interested, additional information can be found in the following papers: Physics, The Next Frontier and Physics, Part 2: Angular Effects.
As for the previous assignment, you will use doxygen, make, LaTeX and Python (version 3). In addition, this assignment will use pytest for unit testing and flake8 to verify that its pep8-inspired standard is enforced. This assignment also takes advantage of functional programming in Python.
All of your code, except for the testing files, should be documented using doxygen. Using doxygen on the testing files is optional. Your report should be written using LATEX. Your code should follow the given specification exactly. In particular, you should not
2
add public methods or procedures that are not specified and you should not change the number or order of parameters for methods or procedures. If you need private methods or procedures, please use the Python convention of naming the files with the double underscore ( methodName ) (dunders). Please follow specified naming EXACTLY. You do not want to lose marks for a simple mistake.
For the purpose of understandability, the specification provided at the end of the as- signment uses notation that is slightly different from the Hoffman and Strooper notation. Specifically the types for real and natural numbers are represented by R and N, respec- tively. (In this specification, the natural numbers are assumed to include 0.) Booleans are represented by B. Also, subscripts are used for indexing a sequence. For instance, xi means the same thing as x[i]. An overview of our mathematical notation and MIS templates can be found in the MIS Format document.
2.1 Installing scipy and matplotlib
This assignment uses two external modules that we have not previously installed: scipy and matplotlib. To install them on your virtual machine, do the following:
pip3 install scipy pip3 install matplotlib
2.2 Installing flake8
We will use flake8 to ensure your Python code meets the style conventions of the course. You have likely already installed flake8 on your VM or local machine. If not, you will need to install two βpipβ packages. This is the standard way to install packages for Python.
First run the following command in your terminal:
pip --version
If the output includes βPython 3,β then run the following instructions:
pip install flake8 pip install pep8-naming
If it does not, then use pip3 for the following alternate instructions.
pip3 install flake8 pip3 install pep8-naming
3
2.3 Running flake8
Run the following command in your A2 directory. This will inform you of the location and types of style violations. You can find more information on what each error means here: https://lintlyci.github.io/Flake8Rules/
flake8
Part 1 Step 1
Write the modules Shape.py, CircleT.py, TriangleT.py, BodyT.py, Scene.py, Plot.py following the specification given at the end of the assignment.
Step 2
Write a module (named test driver.py), using pytest, that tests the following mod- ules: CircleT.py, TriangleT.py, BodyT.py and Scene.py. (Plot.py should be tested manually.) For Scene.py you do not have to test the getters or setters for the functions Fx and Fy. The given makefile Makefile has a rule test for running your tests. Each procedure/method should have at least one test case. Record your rationale for test case selection and the results of using this module to test the procedures in your modules. (You will submit your rationale with your report in Step 6.) Please make an effort to test normal cases, boundary cases, and exception cases. Your test program should compare the calculated output to the expected output and provide a summary of the number of test case that have passed or failed.
Testing the output of the sim method from Scene.py is made challenging because the output is sequences of real numbers. Use the following relative error formula when comparing a calculated sequence xcalc to the true solution xtrue:
||xcalc β xtrue|| < Ξ΅ (1) ||xtrue ||
Subtracting two sequences is done by subtracting corresponding elements to create a new sequence. The double vertical bars around a sequence mean taking the norm of the sequence, where the norm is a measure of the magnitude of the sequence. There are many different possible norms. The simplest is to find the maximum absolute value in the sequence. The two sequences are considered close to being equal if the left hand side
4
of the equation is less than some small number Ξ΅. You are free to select a value for Ξ΅ that you feel is reasonable.
In testing you may want to consider some common cases, as follows:
β’ The shape falling under the force of gravity in the negative y direction: Fx(t) = 0,
Fy(t)=βgm,vx =0,vy =0.
β’ Projectile or ballistics motion: Fx(t) = 0, Fy(t) = βgm, vx = v cos(ΞΈ), vy = v sin(ΞΈ)
where v is the magnitude of the initial velocity and ΞΈ is the angle from the horizontal.
To get more interesting plots, you may want to experiment with conditional expres- sions, like that shown in test expt.py. You can run this file via the make rule (make expt).
Step 3
Test the supplied Makefile rule for doc. This rule should compile your documentation into an html and LATEX version. Along with the supplied Makefile, a doxygen configu- ration file is also given in your initial repo. You should not have to change these files.
Step 4
Submit (add, commit and push) all Python files using git. (Of course, you will be doing this throughout the development process. This step is to explicitly remind you that the version that will be graded is the one we see in the repo.) Please do not change the names and locations for the files already given in your git project repo. For Part 1, the only files that you should modify are the Python files.
Changing other files could result in a serious grading penalty, since the TAs might not be able to run your code and documentation generation. You should NOT submit your generated documentation (html and latex folders). In general, files that can be regenerated are not put under version control.
Optionally, you can tag your final submission of Part 1 of the assignment with the label A2Part1.
Part 2
Your CircleT.py, TriangleT.py, BodyT.py and Scene.py files will automatically be pushed to your partnerβs repo. Including your name in your partner code files is optional.
5
Step 5
After you have received your partnerβs files, temporarily replace your corresponding files with your partnerβs. (You are just moving the files for the purpose of testing; you will not replace your version of the code in the git repo.) Do not initially make any modifications to any of the code. Run your test module and record the results. Your evaluation for this step does not depend on the quality of your partnerβs code, but only on your discussion of the testing results. If the tests fail, for the purposes of understanding what happened, you are allowed to modify your partnerβs code.
Step 6
Write a report using LATEX (report.tex) following the template given in your repo. The report should include the following:
- Your name and macid.
- Your updated Python files.
- Your partnerβs files.
- The results of testing your files (along with the rational for test case selection). The summary of the results should consist of the following: the number of passed and failed test cases, and brief details on any failed test cases.
- The results of testing your files combined with your partnerβs files. Please include a discussion of the test results and what you learned doing the exercise. List any problems you found with your program and/or your partnerβs module. Compare the results of this exercise for A1 and A2.
- The specification of this assignment imposed design decisions on you. Please provide a critiques of the specified design. What did you like? What areas need improve- ment? How would you propose changing the design? Your answer should incor- porate the quality criteria we discussed in class, including consistency, essentiality, generality, minimality, high cohesion, low coupling and opacity. Does the interface provide the programmer with checks that will allow them to avoid generating an exception?
- Answers to the following questions:
a) Should getters and setters be unit tested? Please justify your answer.
6
- b) Β The assignment says that you do not have to test the setters or getters that are functions (Fx and Fy) in Scene.py. If you were required to test the getters and setters for these state variables, how might you do that?
- c) Β The assignment does not require automated tests for Plot.py. If automated tests were required, how might you do them? Hint: matplotlib can generate a file for any plots that you build.
- d) Β Write a mathematical specification for a function called close enough that takes two arguments xcalc and xtrue and returns true if the sequences represented by the arguments are close to being equal, as expressed by Equation 1.
- e) Β The given specification has exceptions for non-positive values of shape dimensions and mass, but not for the x and y coordinates of the centre of mass. Should there be exceptions for negative coordinates? Why or why not?
- f) Β TriangleT has a state invariant that s > 0 β§ m > 0. Informally prove that this invariant is always satisfied by the given specification.
- g) Β Write a Python list comprehension statement that generates a list of the square roots of all odd integers between 5 and 19 (inclusive).
- h) Β Define a Python function that takes a string and returns the string, but with all upper case letters removed.
- i) Β How are the principles of abstraction and generality related?
- j) Β If we have high coupling between modules we can have a cases where a module uses many other modules or a module is is used by many other modules. Which of these two scenarios would in general be better? Why?
The writing style for the report should be professional, but writing in the first person is fine. Some of your ideas can be summarized in lists, but most of the report should be written in full sentences. Spelling and grammar is important.
Commit and push report.tex and report.pdf. Although the pdf file is a generated file, for the purpose of helping the TAs, weβll make an exception to the general rule of avoiding version control for generated files. If you have made any changes to your Python files, you should also push those changes.
Optionally, the final submission can have the tag A2Part2. Notes
1. Your git repo will be organized with the following directories at the top level: A1, A2, A3, and A4.
7
- Inside the A2 folder you will start with initial stubs of the files and folders that you need to use. Please do not change the names or locations of any of these files or folders.
- Please put your name and macid at the top of each of your source files, except for those that you share with a partner. Including your name and macid is optional for those files.
- Your program must work on mills when compiled with its versions of Python (version 3), LaTeX, doxygen, make, pytest, pytest-cov, and flake8. (Since mills does not provide a gui, Plot.py does not have to be tested on mills.)
- Python specifics:
- The exceptions in the specification are intentionally selected to use the names of existing Python exceptions. There is no need to define new exceptions.
- Although efficient use of computing resources is always a good goal, your im- plementation will be judged on correctness and not on performance.
- Since the specification is silent on this point, for methods that return an object, or use objects in their state, you can decide to either use references or construct new objects. The implementation will be easier if you just work in terms of references to objects.
- For the interface modules, use Pythonβs Abstract Base Class (ABC). An illus- trative example of ABC is given at https://ca.godaddy.com/engineering/ 2018/12/20/python-metaclasses/.
- You should use the scipy library for odeint.
- A sample program (test expt.py) that uses the modules in this specification is available in the repo. You can use this to do an initial test that your interface matches the specification.
- Exceptions are documented with @throws.
- The marking scheme is available in the course repo. The marking scheme
includes grades based on git usage, unit testing, and flake8.
- If a flake8 check contradicts the use of a symbol used in the MIS specification, ignore this flake8 warning and continue to use the symbol as given in the MIS. A .flake8 configuration file will be pushed to your repo that should ignore any pep8 errors that are allowed, such as using doxygen comments.
8
- Your grade will be based to a significant extent on the ability of your code to compile and its correctness. If your code does not compile, then your grade will be significantly reduced.
- Any changes to the assignment specification will be announced in class. It is your responsibility to be aware of these changes. Please monitor all pushes to the course git repo.
9
Shape Interface Module Interface Module
Shape
Uses
None
Syntax
Exported Constants None
Exported Types
None
Exported Access Programs
Routine name
cmx cmy mass
m inert
In
Out Exceptions
R R R R
10
CircleT Module
Template Module inherits Shape
CircleT
Uses
Shape
Syntax
Exported Constants None
Exported Types
CircleT = ?
Exported Access Programs
Routine name
newCircleT cmx
cmy
mass
m inert
Semantics
State Variables
x:R y:R r:R m:R
State Invariant
r>0β§m>0
In
xs :R,ys :R,rs :R,ms :R
Out Exceptions
CircleT ValueError
R R R R
11
Assumptions
The arguments provided to the access programs will be of the correct type.
Access Routine Semantics
new CircleT(xs, ys, rs, ms):
β’ transition: x,y,r,m:=xs,ys,rs,ms
β’ output: out := self
β’ exception: (Β¬(rs > 0 β§ ms > 0) β ValueError)
cm x():
β’ output: out := x β’ exception: none
cm y():
β’ output: out := y β’ exception: none
mass():
β’ output: out := m β’ exception: none
m inert():
β’ output: out := mr2
2
β’ exception: none
12
TriangleT Module
Template Module inherits Shape
TriangleT
Uses
Shape
Syntax
Exported Constants None
Exported Types
TriangleT = ?
Exported Access Programs
Routine name
newTriangleT cmx
cmy
mass
m inert
Semantics
State Variables
x:R
y:R
s : R #side length (equilateral triangle) m:R
State Invariant
s>0β§m>0
In Out
Exceptions
xs :R,ys :R,ss :R,ms :R
TriangleT ValueError
R R R R
13
Assumptions
The arguments provided to the access programs will be of the correct type.
Access Routine Semantics
new TriangleT(xs, ys, ss, ms):
β’ transition: x,y,s,m:=xs,ys,ss,ms
β’ output: out := self
β’ exception: (Β¬(ss > 0 β§ ms > 0) β ValueError)
cm x():
β’ output: out := x β’ exception: none
cm y():
β’ output: out := y β’ exception: none
mass():
β’ output: out := m β’ exception: none
m inert():
β’ output: out := ms2
12
β’ exception: none
14
BodyT Module
Template Module inherits Shape
BodyT
Uses
Shape
Syntax
Exported Constants None
Exported Types
BodyT = ?
Exported Access Programs Routine name In
Out Exceptions
newBodyT cmx
cmy
mass
m inert
Semantics
State Variables
cmx : R cmy : R m:R moment : R
State Invariant
moment β₯0β§m>0
xs :seqofR,ys :seqofR,ms :seqofR BodyT ValueError R
R R R
15
Assumptions
The arguments provided to the access programs will be of the correct type.
Access Routine Semantics
new BodyT(xs, ys, ms):
- transition:
cmx,cmy,m,moment := cm(xs,ms),cm(ys,ms),sum(ms),
mmom(xs, ys, ms) β sum(ms)(cm(xs, ms)2 + cm(ys, ms)2) - output: out := self
- exception: (Β¬(|xs| = |ys| = |ms|) β ValueError |Β¬(β§ΞΌ : R|ΞΌ β ms : ΞΌ > 0) β
ValueError) cm x():
β’ output: out := cmx
β’ exception: none cm y():
β’ output: out := cmy
β’ exception: none mass():
β’ output: out := m
β’ exception: none m inert():
β’ output: out := moment β’ exception: none
16
Local Functions
sum : seq of R β R sum(ms)β‘(+ΞΌ:R|ΞΌβms :ΞΌ)
cm : seq of R Γ seq of R β R
cm(z, m) β‘ (+i : N|i β [0..|ms| β 1] : zimi)/sum(m)
mmom : seq of R Γ seq of R Γ seq of R β R mmom(x,y,m)β‘(+i:N|iβ[0..|m|β1]:mi(x2i +yi2))
17
Scene Module Template Module
Scene
Uses
Shape, SciPy
Syntax
Exported Constants None
Exported Types
Scene = ?
Exported Access Programs
name
new Scene
get shape
get unbal forces get init velo
set shape setunbalforces set init velo sim
Semantics State Variables
In
Shape, R β R, R β R, R, R
Shape RβR,RβR R, R
R, N
Out Exceptions
Scene
Shape
R β R, R β R R, R
seq of R, seq of (seq [4] of R)
s : Shape
Fx : R β R # unbalanced force function in x dir Fy : R β R # unbalanced force function in y dir vx : R # initial velocity in x dir
vy : R # initial velocity in y dir
18
State Invariant
None
Assumptions
None
Access Routine Semantics
new Scene(sβ²,Fxβ²,Fyβ²,vxβ² ,vyβ² ):
β’ transition: s,Fx,Fy,vx,vy = sβ²,Fxβ²,Fyβ²,vxβ² ,vyβ² β’ output: out := self
β’ exception: None
get shape():
β’ output: out := s β’ exception: none
get unbal forces():
β’ output: out := Fx, Fy β’ exception: none
get init velo():
β’ output: out := vx, vy β’ exception: none
set shape(sβ):
β’ transition: s := sβ² β’ exception: none
set unbal forces(Fxβ²,Fyβ²):
β’ transition: Fx,Fy :=Fxβ²,Fyβ² β’ exception: none
19
set init velo(vxβ² , vyβ² ):
β’ transition: vx, vy := vxβ² , vyβ² β’ exception: none
sim(tfinal, nsteps):
- output: out := t, odeint(ode, [s.cm x(), s.cm y(), vx, vy], t)
where t = [i : N|i β [0..nsteps β 1] : iΒ·tfinal ] nsteps β1
# for the sequence of t values the values should be in the natural ascending order for the i values
- exception: none Local Functions
ode : (seq [4] of R) Γ R β seq [4] of R
ode(w, t) β‘ [w[2], w[3], Fx(t)/s.mass(), Fy(t)/s.mass()]
20
Plot Module Module
Plot
Uses
None
Syntax
Exported Constants None
Exported Access Programs
Routine name In Out
plot seq of (seq [4] of R), seq of R
Semantics
Environment Variables
win: two dimensional sequence of coloured pixels
State Variables
None
State Invariant
None
Assumptions
None
Exceptions
ValueError
21
Access Routine Semantics
plot(w, t)
- transition: modify win so that it displays three appropriately labelled x-y graphs of
the data points in w showing the following plots
1. x versus t 2. y versus t 3. y versus x
where t is the supplied argument and β x=β¨i:N|iβ[0..|w|β1]:w[i][0]β©
β y=β¨i:N|iβ[0..|w|β1]:w[i][1]β©
(We are abusing the sequence notation with the assumption that the sequence will be built in the order of increasing i values.) The plot should have the same structure as Figure 1.
- exception: (Β¬(|w| = |t|) β ValueError) 2.3.1 Considerations
Implementation of Plot.py is facilitated by the matplotlib package.
22
SciPy Module 2.4 Module
SciPy
2.5 Uses
None
2.6 Syntax
2.6.1 Exported Access Programs
Name In
odeint (seq [4] of R) Γ R β seq [4] of R, seq [4] of R, seq of R
2.7 Semantics 2.7.1 State Variables None
2.7.2 Access Routine Semantics #Solving dy=f(y(t),t)
dt
Out
seq of (seq [4] of R)
Except.
ODE ERR
# Bold font is used to indicate variables that are a sequence type
odeint(f, y0, t):
β’ output: out := β¨i : N|i β [0..|t| β 1] : β¨yo(ti), y1(ti), y2(ti), y3(ti)β©β© where τ° tfin
y(t) = y0 +
β’ exception: exc := ( ODE Solver Fails β ODE ERR)
2.7.3 Considerations
This function is implemented by the Python library scipy. The syntax of odeint exactly matches what is given here. The output is a sequence of sequences. ODE ERR stands for any error that can be raised by the scipy implementation of odeint.
23
t0
f(s, y(s))ds



