代写MATH2601: Computer Tutorials and Assignments代做留学生Python程序

MATH2601: Computer Tutorials and Assignments

Academic Year 2024/25

Organisation

Tutorials

In the tutorials, we will introduce new tools and concepts in Python, in order to use methods from numerical analysis to solve a range of mathematical problems.

Assignments

Computer assignments will be set fortnightly. During the Computer Practical classes on Monday, you will be able to work independently on these assignments, under the supervision of academic staff.

You should submit your work by 4.pm on the Monday in the week following the week of the Practical  class to receive feedback. Write your work in a Python Jupyter Notebook called xyz_N .ipynb, where xyz is your ISS username (i.e., your login) and N the number of the assignment (1, 2, 3, 4, 5), then submit it to the Assessment area for MATH2601 on the VLE. Jupyter Notebooks will  naturally allow you to write a short report, i.e., to produce an analysis of your results and to comment on them.

Assessments

Two of the computer assignments, 3 and 5, will be assessed. They will be graded and you will get  feedback on your work. The overall Computer Assessment grade counts for 30% of the MATH2601 grade and students need to achieve at least 40% on the Computer Assessments to pass the module.

Chapter 1

Computational accuracy

1.1 Tutorial

1.1.1 Motivation

Suppose we wish to evaluate exp x to a very high accuracy. As discussed in the lecture, floating-point arithmetic provides only limited precision, which will limit the accuracy of calculation, so we need an alternative approach. One is based on the Taylor series

(1.1)

If we truncate the series and x is a rational number, then the right-hand side is also a rational number. In Python, integers can be arbitrarily large and there is no round-off error, so we have no problem, in principle, representing any accuracy in this way.

To make this work, we need to introduce a new type to represent rational numbers, complementing the int and float types in standard Python. We will achieve this be defining a new class. In fact, the real purpose of this lecture is to learn the Python class structure, which is a powerful and flexible programming technique.

1.1.2 Classes

Python has types like int and list, and instances of those types like 42 and [1, 4, 9]. A class is a mechanism for defining a new type. A class defines attributes (data associated to every object of that type) and methods (functions that act on the type). In this tutorial, we will define a class called Rational, the object are the rational numbers, the attributes are the numerator and the denominator (which define the rational number) and the methods are operations like addition.

class Rational:

def __init__(self, num, den):         # constructor: x = Rational(num, den)

self.num = num                           # num = numerator

self.den = den                             # den = denominator

def display(self):

print(str(self.num) + ' / ' + str(self.den))

This is a first attempt to create the class Rational. It defines two methods, a special method called __init__ and a normal method called display. Here is how to use the new class:

In [1]: two_thirds = Rational(2, 3) # construct variable of type Rational

In [2]: two_thirds.num                 # retrieve attribute called `num`

Out[2]: 2

In [3]: two_thirds.display()           # call `display` method

2 / 3

The special __init__ method must appear in any class definition and is used to construct instances of the class. When we write Rational(2, 3), the __init__ method of the class Rational is called. The first argument, customarily called self, is the instance being constructed. The other arguments are given by the user (in the example, they are 2 and 3). In our class, the __init__ method takes the arguments passed by the user and assigns them to the num and den attributes of the instance which is being constructed.

Once the new instance is constructed and assigned to the variable two_thirds, we can refer to the two attributes of the new object created as two_thirds.num and two_thirds.den. We use a similar syntax to call the display method, which displays the rational number on the screen. Note that the definition of the display method has one argument, self. This argument is set automatically by Python to the instance that the method is called on. The user should call the display method without any arguments.

Before we go any further, let us improve our class definition in two ways. Firstly, we ensure that rational numbers numbers are expressed in their lowest possible form, by dividing through by the highest common factor (hcf). Secondly, we want to display rational numbers using the print function, just like any other variable in Python. We can achieve this by defining another special method, called __repr__. Whenever Python prints a variable, it looks for this method to see how to display the variable.

class Rational:

def __init__(self, num, den):

hcf = gcd(num, den)

self.num = num // hcf

self.den = den // hcf

def __repr__(self):

return str(self.num) + ' / ' + str(self.den)

We now wish to endow our class with other methods, in order to manipulate rational numbers. For example, let us define a method for multiplying two rational numbers. Again, there is a special method which Python calls if we use the * operator. This method is called __mul__. We can define this method in our class as follows:

def __mul__(self, rhs):

new_num = self.num * rhs.num

new_den = self.den * rhs.den

return Rational(new_num, new_den)

The first argument is self and represents the instance on the left-hand side of the * operator, while the second argument is the right-hand side. To use this method we would need to type:

In [1]: x = Rational(3, 5)

In [2]: y = Rational(4, 7)

In [3]: x * y

12 / 35

In the Practical session, we will further extend the Rational class.

1.2 Assignment

1.2.1 Accuracy

The math module includes a function exp which computes the exponential of a floating point number. Import this function, and note how many decimal places are given in the evaluation of exp(1). Using Taylor series to approximate the exponential function, we could define the following function:

def exp_taylor(x, n):

exp_approx = 0

for i in range(n):

exp_approx += x ** i / factorial(i)

return exp_approx

which computes the value of n terms of the sum in equation (1.1) from the tutorial notes. How many terms are needed before this function offers no further increase in accuracy in the evaluation of exp(1)?

1.2.2 Defining the Rational class

Download the file rational_start.py from the VLE, which is the Rational class discussed during the tutorial. Test that it works by trying commands like in the tutorial.

Your task is to extend this class. Add a method __add__ which defines the + operation (note that it must be called __add__), which produces the sum of two rationals, self and rhs.

Next, add a method __neg__ which defines the negation operation -. (Remember, you only need to negate the numerator or the denominator!). Now define the subtraction operation (also -) with a method __sub__. You can use the fact that subtraction is the same as adding the negation.

After you defined the __sub__ method, the __gt__ method should work. Test that you can compare rational numbers using > and <. Finally, test the methods floor, frac and to_float. Check you understand what they do, and how they do it.

1.2.3 Partial sums

Adapt the function exp_taylor to compute the first n terms of exp x in rational numbers. The first term is then given by Rational(1, 1). You probably need to compute a rational number for 1/n! for each term of the sum.

Use this function to give the first ten rational approximants to e.

1.2.4 Arbitrary accuracy

Download the file expand.py from the VLE which contains the code for the three methods: expand, expand_integer_part and expand_fractional_part. Place them in the Rational class and check you understand how they are used to convert a rational number to any base (like decimal), and to any number of digits. For example,

In [1]: Rational(1, 4).expand(10, 4)

Out[1]: '0.25 (base 10)'

In [2]: Rational(1, 7).expand(10, 30)

Out[2]: '0.142857142857142857142857142857 (base 10)'

Experiment with these conversion functions. What is the 100th decimal place of e? How many terms in the partial sum are necessary to establish this?

1.2.5 Approximations of π

Leonhard Euler gave the following expression for π:

Write a function which computes the first n terms of this series, and use it to confirm that the 50th digit in the decimal expansion for π is 0.

1.2.6 Advanced material

Srinivasa Ramanujan was a self-taught Indian mathematician who had a remarkable affinity for numbers. He discovered many extraordinary series for π. For example,

where k!! is the double factorial, given by

k!! = k(k − 2)(k − 4)· · · 7 × 5 × 3 × 1 for odd k.

Write a function to compute the nth partial sum of this series, using the Rational class, and confirm that the 50th digit of π is zero. How many terms in the series are necessary to find this digit?

The current record for computation of decimal places of π is 62.8 trillion (6.28 · 1013) digits (established in August 2021). This was computed using a variation of the following infinite series given by Srinivasa Ramanujan in 1910:

Write a function to compute the nth partial sum of this series using the Rational class. You will need to obtain an exact rational approximation to √2, perhaps using continued fractions. How many terms are required to obtain the 50th digit of π?

Chapter 2

Root-finding

2.1 Tutorial

One topic that is endlessly useful in computational mathematics is root-finding. That is, given a function f, to find the value(s) of x for which f(x) = 0. In simple cases the root can be found explicitly by algebra, but in general a numerical technique is needed. There are several different ways to approach this problem, and in this workshop we investigate three well-known ones — bisection, secant, and Newton. Since we will always be finding roots of functions, we will take this opportunity to review and extend our knowledge of Python functions.

2.1.1 Functions

By now we are familiar with defining functions in Python, using the formulation

def function_name(argument_1, argument_2, argument_3, ...):

return value

The point of using a function is that often a block of code is to be used repeatedly, with varying input parameters. Functions can help organise a large program coherently, and can aid in debugging. A function always returns something; if there is no return statement, the function returns None.

2.1.2 Default argument values

It is possible to define a default value for one or more function arguments. For example,

def test(a, b=1, c='True'):

print(a, b, c)

which will produce

In [1]: test(4, 5, 6)

4 5 6

In [2]: test(3)

3 1 True

Note that the function test can now be called with fewer arguments than it is defined to allow. Here the arguments can be thought of as mandatory (in the case of a), or optional (in the case of b and c). The optional arguments need not be given, but if they are, they are viewed in order:

In [3]: test(4, 'False')

4 False True

One important point is that the default value is evaluated only once. For example, the function

def f(a, L=[]):

L.append(a)

return L

will produce

In [4]: print(f(1)); print(f(2)); print(f(3))

[1]

[1, 2]

[1, 2, 3]

since the list L is not emptied each time the function is called.

2.1.3 Variable numbers of arguments

Occasionally you might want to define a function which accepts different numbers of arguments. As a very simple example (and assuming that there is no better way to accomplish this), suppose we want a function to compute the mean of n numbers, where n may change. Python has a syntax to achieve this.

def mean_of_n_numbers(*args):

mean = 0

for i in args:

mean += i

return mean / len(args)

We can call this function as: mean_of_n_numbers(1, 2, 3, 4), for example, or with any number of arguments. Inside the function, args is interpreted as a Python tuple. Similarly, the function can be called using

numbers = [1, 2, 3, 4, 5]

mean_of_n_numbers(*numbers)

The * unpacks lists of variables into positional variables. Of course, this simple example could have been coded using only Python lists, but the *args syntax is a standard method to cope with arbitrary numbers of arguments.

2.1.4 Lambdas

There is another mechanism for defining functions in Python, designed for relatively simple, one-line procedures. This alternative to def is called a lambda. As an example, the equivalent of the function

def cube_plus_a(x, a):

return x ** 3 + a

is given by lambda x, a: x ** 3 + a.

The lambda formulation does not give a name to the function, so they are often called anonymous functions. Lambdas are intended for function declarations which will typically be used once, and then forgotten. Their simplicity is manifested in the fact that they must be a single expression only. It is not straightforward to define exactly what is meant by a “single expression”, but it must be a statement which returns something. Assignment statements (such as x = 3) do not return anything, so cannot be used in a lambda.

Lambdas do not offer anything that is not offered by def functions, apart from arguable simplicity, and so their use is largely down to personal preference. However, one natural place to use a lambda is when passing an arbitrary function to another function, such as a root-finder. Here is a function which does fixed-point iteration until two successive iterates differ by less than the user-supplied tolerance:

def fixed_point_iteration(function, x_0, tol):

x_old = x_0

x_new = function(x_0)

while abs(x_new - x_old) > tol:

x_old = x_new

x_new = function(x_old)

return x_new

To call this function we might first define the function we wish to finds roots of:

def my_function(x):

return 1 / x + x / 2

and then call the function with fixed_point_iteration(my_function, 1, 1e-10), to find a fixed point to within 10−10 with an initial guess of 1. However, if we want to repeatedly find roots of different functions, it will get tedious having to define a new function every time we want to call the rootfinder. Instead we can call it directly with a lambda as an argument: fixed_point_iteration(lambda x: 1 / x + x / 2, 1, 1e-10).

2.2 Assignment

2.2.1 Bisection method

The bisection method was discussed in the lecture. Write a function bisect(f, left, right, tol) which takes four arguments: the function you want to find a root of, the left and right endpoints of the interval at the start, and the tolerance. The function should apply the bisection method until endpoints of the interval are within the given tolerance.

Use lambda functions to call bisect with different input functions. Use it to solve the following to some reasonable tolerance:

1. Find three values of x for which f(x) = x3 + 2x2 − x − 1 is zero.

2. Find the cube root of 7.

3. Find both solutions to tan−1 (x) = 3 − x2.

4. Find all solutions to log(x4 ) = x3 − 1.

For each of these you may want to first plot the function in order to select sensible initial estimates for the roots. Remember, for the bisection method you must supply initial guesses which bracket the root.

Explain what happens when you try to apply bisection method to the function f(x) = 1/x, with initial guesses −2 and 3.

Try to rewrite your function so that it uses a default tolerance of 10−6 if the user does not specify the tolerance, and check that this works.

2.2.2 Secant method

Write a secant method root-finding function,secant(f, x0, x1, tol), based on the material from the lecture. Check that it works by verifying the solutions to the problems above.

The function g(x) = cos(πx) has roots at x = n + 1/2, n ∈ N. Why do the three function calls: secant(g, 0.1, 1,0.0001), secant(g, 0.1, 1.2, 0.0001) and secant(g, 0.1, 1.4, 0.0001) find three different roots?

Practise the syntax for variable numbers of arguments by adapting the secant method program to accept an arbitrary number of coefficients of a polynomial.

2.2.3 Newton’s method

Write a Newton method root-finding function. Remember that for the Newton method you only need to give a single initial estimate, but you also need to supply the derivative. You can give both input function and its derivative as lambdas.

1. Use Newton’s method to verify that the function h(x) = 4 tan−1 x has a root at x = 0.

2. Try to find this root with a starting guess of x0 = 1, and then with an starting guess of x0 = 1.5. What goes wrong in the second case?

3. Now consider the function h(x) = x2 − 2 (which clearly has a root at x = √2) with an initial guess of x0 = 0. What is the problem?

2.2.4 Convergence

Here we will investigate, briefly, the convergence properties of each root-finding method, by finding the cube root of 1/2 with increasing accuracy.

1. For each method, alter your root-finding function to return a list (or better a “numpy array”) of all iterations, rather than the final one only.

2. We shall solve f(x) = x3 − 1/2 = 0 to find sequences of approximations of the cube root of 1/2. Check that all three methods work, given sensible starting parameters.

3. For each method, run the algorithm for a small value of the tolerance (10−15, say).

4. Plot the exact error against the number of steps for the three methods on the same graph. You should find that the secant and Newton methods are markedly quicker than the bisection method. In particular, the bisection method should appear roughly linear on a semilogy plot, while the others are faster than linear. Explain these results and find a method to infer the rate of convergence of the secant and Newton methods from the data.







热门主题

课程名

mktg2509 csci 2600 38170 lng302 csse3010 phas3226 77938 arch1162 engn4536/engn6536 acx5903 comp151101 phl245 cse12 comp9312 stat3016/6016 phas0038 comp2140 6qqmb312 xjco3011 rest0005 ematm0051 5qqmn219 lubs5062m eee8155 cege0100 eap033 artd1109 mat246 etc3430 ecmm462 mis102 inft6800 ddes9903 comp6521 comp9517 comp3331/9331 comp4337 comp6008 comp9414 bu.231.790.81 man00150m csb352h math1041 eengm4100 isys1002 08 6057cem mktg3504 mthm036 mtrx1701 mth3241 eeee3086 cmp-7038b cmp-7000a ints4010 econ2151 infs5710 fins5516 fin3309 fins5510 gsoe9340 math2007 math2036 soee5010 mark3088 infs3605 elec9714 comp2271 ma214 comp2211 infs3604 600426 sit254 acct3091 bbt405 msin0116 com107/com113 mark5826 sit120 comp9021 eco2101 eeen40700 cs253 ece3114 ecmm447 chns3000 math377 itd102 comp9444 comp(2041|9044) econ0060 econ7230 mgt001371 ecs-323 cs6250 mgdi60012 mdia2012 comm221001 comm5000 ma1008 engl642 econ241 com333 math367 mis201 nbs-7041x meek16104 econ2003 comm1190 mbas902 comp-1027 dpst1091 comp7315 eppd1033 m06 ee3025 msci231 bb113/bbs1063 fc709 comp3425 comp9417 econ42915 cb9101 math1102e chme0017 fc307 mkt60104 5522usst litr1-uc6201.200 ee1102 cosc2803 math39512 omp9727 int2067/int5051 bsb151 mgt253 fc021 babs2202 mis2002s phya21 18-213 cege0012 mdia1002 math38032 mech5125 07 cisc102 mgx3110 cs240 11175 fin3020s eco3420 ictten622 comp9727 cpt111 de114102d mgm320h5s bafi1019 math21112 efim20036 mn-3503 fins5568 110.807 bcpm000028 info6030 bma0092 bcpm0054 math20212 ce335 cs365 cenv6141 ftec5580 math2010 ec3450 comm1170 ecmt1010 csci-ua.0480-003 econ12-200 ib3960 ectb60h3f cs247—assignment tk3163 ics3u ib3j80 comp20008 comp9334 eppd1063 acct2343 cct109 isys1055/3412 math350-real math2014 eec180 stat141b econ2101 msinm014/msing014/msing014b fit2004 comp643 bu1002 cm2030
联系我们
EMail: 99515681@qq.com
QQ: 99515681
留学生作业帮-留学生的知心伴侣!
工作时间:08:00-21:00
python代写
微信客服:codinghelp
站长地图