The gradient and directional derivatives
The gradient and directional derivatives (lesson 4.2.1)
0 of 8 correct
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
How to type answers
- Powers with
^:x^7,2^(1/3),a^-2. - Multiply with
*or by writing side by side:3x^2,2(x+1). ln(x)is the natural log,log(x, 2)is log base 2,eis Euler's number,sqrt(x)is a square root.sin(x),cos(x)andtan(x)take radians; writepifor π andsin(x)^2for sin²x.- Your first answer to each question is saved: it counts towards your score and brings the question back for review.
- Exact answers like
ln(20)/ln(3)are best. Decimals need about 4 significant figures.
The chain rule and the total differential
The multivariable chain rule and the total differential (lesson 4.2.2)
0 of 7 correct
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
How to type answers
- Powers with
^:x^7,2^(1/3),a^-2. - Multiply with
*or by writing side by side:3x^2,2(x+1). ln(x)is the natural log,log(x, 2)is log base 2,eis Euler's number,sqrt(x)is a square root.sin(x),cos(x)andtan(x)take radians; writepifor π andsin(x)^2for sin²x.- Your first answer to each question is saved: it counts towards your score and brings the question back for review.
- Exact answers like
ln(20)/ln(3)are best. Decimals need about 4 significant figures.
Coding exercise
A numerical gradient and directional derivative
Write two functions, using lessons 4.1.2 and 4.2.1. Each takes a function f of one NumPy array and a point p, given as a list or an array.
gradient(f, p, h=1e-5)returns as a float array, by central differences: component is . It works for any number of inputs and leavespunchanged.directional_derivative(f, p, v, h=1e-5)returns the slope offatpin the direction of the arrowv, which need not have length 1. RaiseValueErrorifvis the zero vector or has a different number of components fromp.
The tests use the tilted bowl and a function of three variables.
They pass points as whole numbers, such as np.array([0, 1]). An integer array cannot hold a bump of 0.00001, so turn the point into floats first. They also check that the array you are given is the same afterwards.
See the tests
import math
import numpy as np
def _tilted(q):
x, y = q
return x**2 + x * y + y**2 - 3 * x
def _three(q):
x, y, z = q
return x**2 + y * z
def _raises_value_error(f, *args):
try:
f(*args)
except ValueError:
return True
return False
def test_gradient_tilted():
"""The tilted bowl has gradient (−2, 2) at (0, 1)"""
expect_close(gradient(_tilted, np.array([0.0, 1.0])), np.array([-2.0, 2.0]), what="gradient at (0, 1)", abs_tol=1e-6)
def test_gradient_three_variables():
"""x² + yz has gradient (2, 3, 2) at (1, 2, 3)"""
expect_close(gradient(_three, np.array([1.0, 2.0, 3.0])), np.array([2.0, 3.0, 2.0]), what="gradient at (1, 2, 3)", abs_tol=1e-6)
def test_gradient_whole_numbers():
"""A point of whole numbers, as a list or an integer array, still gives (−2, 2)"""
expect_close(gradient(_tilted, [0, 1]), np.array([-2.0, 2.0]), what="gradient(f, [0, 1])", abs_tol=1e-6)
expect_close(gradient(_tilted, np.array([0, 1])), np.array([-2.0, 2.0]), what="gradient(f, np.array([0, 1]))", abs_tol=1e-6)
def test_point_unchanged():
"""gradient leaves the array it is given unchanged"""
p = np.array([0.5, 1.5])
before = p.copy()
gradient(_tilted, p)
expect_close(p, before, what="the point after calling gradient", rel=0, abs_tol=0)
def test_zero_at_lowest_point():
"""At the lowest point (2, −1) the gradient is (0, 0)"""
expect_close(gradient(_tilted, [2, -1]), np.array([0.0, 0.0]), what="gradient at (2, −1)", abs_tol=1e-6)
def test_directional_unit():
"""Along the unit vector (0.6, 0.8) the slope at (0, 1) is 0.4"""
expect_close(directional_derivative(_tilted, [0, 1], [0.6, 0.8]), 0.4, what="slope along (0.6, 0.8)")
def test_directional_normalises():
"""Along the arrow (3, 4) the slope at (0, 1) is still 0.4, not 2"""
expect_close(directional_derivative(_tilted, [0, 1], [3, 4]), 0.4, what="slope along (3, 4)")
def test_steepest_and_level():
"""At (0, 1) the slope is 2√2 along the gradient and 0 along the level curve, (1, 1)"""
expect_close(directional_derivative(_tilted, [0, 1], [-2, 2]), 2 * math.sqrt(2), what="slope along the gradient (−2, 2)")
expect_close(directional_derivative(_tilted, [0, 1], [1, 1]), 0.0, what="slope along (1, 1)", abs_tol=1e-6)
def test_three_variable_direction():
"""x² + yz at (1, 2, 3) has slope 4 along the arrow (1, 2, 2)"""
expect_close(directional_derivative(_three, [1, 2, 3], [1, 2, 2]), 4.0, what="slope along (1, 2, 2)")
def test_zero_direction():
"""The zero vector has no direction: ValueError"""
assert _raises_value_error(directional_derivative, _tilted, [0, 1], [0, 0]), "expected ValueError for the direction (0, 0)"
def test_wrong_size():
"""A direction with three components for a point with two: ValueError"""
assert _raises_value_error(directional_derivative, _tilted, [0, 1], [1, 0, 0]), "expected ValueError for a direction of the wrong size"