Ran Wei/Maths Series
中文
Mathematical Foundations for Computer Science and AI — Ran Wei

Mathematical language, numbers, and functions

Read a formula as a precise description of a computation. Learn to track domains, compose functions, expand sums, and challenge a claim before translating it into Python.

6 hours4 sessions3 labs12 exercises + 2 extensions10 quiz questions

By the end you can

  • Distinguish a definition, an assumption, and a claim.
  • Read number systems, intervals, and indexed notation without changing their meaning.
  • State a function's domain, codomain, and image; calculate a composition.
  • Expand finite sums and products, including empty and nested cases.
  • Translate a mathematical contract into code and refute a false identity with a counterexample.

Before you start

School arithmetic and simple algebra. Use the optional algebra refresher if fractions, signs, equations, or logarithms are unfamiliar. Read the Python primer before the labs; no third-party packages are required.

Contents

Study plan

6 hours

Times include practice and are estimates. Split a session when useful. Optional extension exercises add 25 minutes. Progress is stored in this browser and shared between language editions.

1

A formula is a small specification

Imagine an application that scores the first four results of a search. One developer starts counting at zero; another starts at one. One returns a total; another returns an average. Both implementations run, and both produce numbers, but they answer different questions. Before deciding which is correct, we need a precise description of the intended computation.

Mathematical notation gives us that description. It names the objects involved, says which inputs are allowed, and describes the relationship between an input and its result. A formula becomes useful when you can read those commitments. Recognising a symbol without understanding its role is insufficient: the meaning of a sum changes when its bounds change, and the meaning of a function changes when its domain changes.

Our running task is deliberately small. Given a nonnegative integer nn, add the first nn positive odd integers. For n=4n=4, the terms are 1,3,5,71,3,5,7 and the result is 1616. For n=0n=0, there are no terms and the result is 00. We will express this task as a formula, translate its indices into Python, and distinguish a few successful executions from a statement about every valid input.

Along the way, keep three questions beside each expression: What kind of object is this? Which values are permitted? What must the result mean? The same questions will later help you read a loss function, a probability model, a matrix transformation, or an algorithm’s cost. This module establishes the language; later modules develop proofs and the more specialised mathematics.

Before the labs, use the Python primer. If school algebra feels uncertain, try the entry diagnostic and the optional refresher. Neither resource is a gate: use it to identify what needs practice.

2

Mathematical objects and number systems

A mathematical object is something we can describe and reason about: a number, an ordered pair, a set, a function, or a sequence. The operations that make sense depend on the object. You can add two real numbers, but a library catalogue and a temperature are different kinds of objects. A programming language may allow many representations; the mathematical description supplies the meaning.

A definition gives a term its intended meaning. In this series, we define the natural numbers to include zero: N={0,1,2,…}\mathbb{N}=\{0,1,2,\ldots\}. A different book may reserve that symbol for {1,2,…}\{1,2,\ldots\}. Neither convention is universally compulsory; declare the convention before using it. We write N>0\mathbb{N}_{>0} when we specifically require a positive integer. The distinction matters when zero means an empty input, an initial counter, or an invalid count.

An assumption specifies the setting in which an argument or calculation applies. “Let n∈Nn\in\mathbb{N}” permits zero and excludes 2.52.5. A claim is a statement to examine, such as “the sum of the first nn odd integers is n2n^2.” That claim concerns every permitted nn; defining the sum does not make the claim true automatically. A theorem is a claim established by a proof from stated assumptions and accepted rules. Module 04 will develop proof methods systematically.

The main number systems form a useful hierarchy. The integers Z\mathbb{Z} add negative whole numbers. The rationals Q\mathbb{Q} contain fractions p/qp/q with integers p,qp,q and q≠0q\ne0. The reals R\mathbb{R} also contain irrational quantities such as 2\sqrt{2}. A decimal representation is a way to write a number, not a new number system: 0.5=1/20.5=1/2 is rational, whereas the infinite decimal expansion of 2\sqrt{2} does not terminate or repeat.

System Examples Typical role
N\mathbb{N} 0,1,40,1,4 Counts and nonnegative indices
Z\mathbb{Z} −3,0,7-3,0,7 Signed differences and integer positions
Q\mathbb{Q} 1/3,−7/2,0.1251/3,-7/2,0.125 Exact ratios and proportions
R\mathbb{R} 2,π,1/3\sqrt{2},\pi,1/3 Measurements and continuous models
C\mathbb{C} 2+3i2+3\mathrm{i} A later extension for rotations and spectral methods

Membership and containment use different symbols. The statement 3∈N3\in\mathbb{N} says that one object belongs to a set. The statement N⊆Z\mathbb{N}\subseteq\mathbb{Z} says that every element of the first set also belongs to the second. We need this small amount of set language to declare domains; Module 03 will study set operations in depth.

Nested number systemsN is a subset of Z, which is a subset of Q, which is a subset of R. Box sizes do not represent cardinality.Real numbers R: e.g. √2, πRational numbers Q: e.g. 1/3, −7/2Integers Z: e.g. −3, −1Natural numbers N: 0, 1, 2, …This series includes zero
Figure 1.1

The natural numbers, integers, rationals, and reals are nested. The labels give examples introduced at each level; the boxes represent inclusion, not a measurement of how many numbers each set contains.

Worked example
Classify a value without confusing its representation

The value −6/3=−2-6/3=-2 is an integer, a rational, and a real, but it is not natural under our convention. The value 00 belongs to all four systems. The finite decimal 1.4141.414 is the rational 707/500707/500; it is an approximation to 2\sqrt{2}, not another exact representation of 2\sqrt{2}.

A count of records must be a natural number. A measured voltage may be modelled as a real number, although a computer stores a finite approximation. Choosing the real-number model does not imply that every real value has an exact machine representation.

The complex numbers have the form a+bia+b\mathrm{i}, where a,b∈Ra,b\in\mathbb{R} and i2=−1\mathrm{i}^2=-1. This is a preview, not a prerequisite for the module’s labs. A real number is the special case with b=0b=0. Complex numbers will matter in spectral and Fourier methods; for now, our calculations use real numbers and integer indices.

When a formula uses a letter, declare its role rather than guessing from the shape of the letter. A variable may range over permitted values; a parameter is held fixed while a particular operation is studied; a constant has a specified value in the current setting. These roles are contextual. In fa(x)=ax+1f_a(x)=ax+1, we may treat aa as a parameter and xx as the input. Later, fitting aa from data makes it the quantity we vary.

Check your understanding

A record count is stored as the numeric value 4.0. Does that representation change the mathematical count into a non-integer? Would 4.5 be an admissible count?

Show answer

The value 4.0=44.0=4 is mathematically an integer, although a Python float and an integer are different software representations. A contract may require the integer representation explicitly. The value 4.54.5 is not an integer and is not an admissible count. Keep the mathematical domain and the software input-type policy distinct.

3

Symbols equality intervals and indices

The symbol == asserts that two expressions denote the same value. It is symmetric: if a=ba=b, then b=ab=a. It does not mean “do the next step” or “store a new value.” The symbol ≠\ne asserts inequality. The relations << and ≤\le compare ordered real values; x≤3x\le3 includes the boundary 33, while x<3x<3 excludes it. Read a chain such as 0≤x<10\le x<1 as two simultaneous conditions.

In mathematics, x=x+1x=x+1 has no real solution: subtracting xx would give 0=10=1. In Python, x = x + 1 evaluates the expression on the right using the current value and assigns the result to the name on the left. Python uses == for an equality comparison. A mathematical text may use x:=3x:=3 or “define xx to be 3” to distinguish a definition from an equation to solve. These notational differences express different operations.

Order of operations is another part of meaning. Exponentiation is evaluated before a leading minus in the conventional expression −32=−(32)=−9-3^2=-(3^2)=-9. Parentheses change the base: (−3)2=9(-3)^2=9. A fraction bar groups its numerator and denominator; writing 1/(x−2)1/(x-2) in code preserves that grouping. The code 1/x-2 represents a different expression. When translating a formula, add parentheses for clarity even if the language’s precedence would give the same answer.

An interval specifies a range of real inputs. Square brackets include an endpoint; round brackets exclude it. Thus [0,1][0,1] includes both boundaries, (0,1)(0,1) includes neither, and [0,1)[0,1) includes only zero. Infinity is not a real endpoint that can be included, so we use (0,∞)(0,\infty) for positive real numbers. An interval such as [0,4][0,4] is not the same as the five-element set {0,1,2,3,4}\{0,1,2,3,4\}: the interval also contains 1/21/2 and 2\sqrt{2}.

Absolute value measures distance from zero: ∣x∣=x|x|=x when x≥0x\ge0 and ∣x∣=−x|x|=-x when x<0x<0. It is always nonnegative. This is why ∣−3∣=3|-3|=3, rather than −3-3. A condition ∣x∣<2|x|<2 means that xx lies less than two units from zero, equivalently −2<x<2-2<x<2. This way of writing a distance will later appear in approximation errors and tolerances.

Worked example
Translate a boundary condition

A score is accepted when 0≤s<10\le s<1. The corresponding test is 0 <= s < 1. The values 00 and 0.50.5 satisfy it; 11 and −0.1-0.1 do not. Replacing < 1 with <= 1 changes the contract at a boundary, even if a typical dataset never happens to contain that value.

Subscripts label components or terms. For a sequence a0,a1,a2a_0,a_1,a_2, the symbol a2a_2 denotes the term labelled two; it is not the product a⋅2a\cdot2 and is not the square a2a^2. Superscripts often mean powers, but their meaning is also declared by context: a later text may write x(t)x^{(t)} for an iterate. Parentheses and explanations prevent the two meanings from being confused.

Our odd-number task uses ai=2i+1a_i=2i+1 for integer indices i=0,1,…,n−1i=0,1,\ldots,n-1. With n=4n=4, the indices are 0,1,2,30,1,2,3 and the terms are 1,3,5,71,3,5,7. There are four terms even though the final index is three. Starting at i=1i=1 without changing the formula would start at 33 and describe a different sequence.

The notation ∑i=03(2i+1)\sum_{i=0}^{3}(2i+1) means “substitute each permitted integer index, then add the terms.” It expands to (2⋅0+1)+(2⋅1+1)+(2⋅2+1)+(2⋅3+1)=16(2\cdot0+1)+(2\cdot1+1)+(2\cdot2+1)+(2\cdot3+1)=16. The large Greek sigma is an aggregation instruction. Section 5 will examine its scope and nested forms; you already know enough to trace Lab 1.

Note

Mathematical summation bounds are inclusive. Python’s range(start, stop) excludes stop. To express integer indices from zero through three, use range(4); to express one through four, use range(1, 5). The official Python range tutorial explains the convention.

Distinguish exact equality from approximation. Writing 2≈1.414\sqrt{2}\approx1.414 acknowledges a difference. A displayed decimal rounded to three places is not evidence that the underlying values are exactly equal. The labs use integer arithmetic for exact sums and explicit tolerances where floating-point calculations are involved. Module 29 will explain how to choose numerical comparisons in more demanding calculations.

Check your understanding

Translate i=1,2,…,4i=1,2,\ldots,4 into Python range notation. Explain the difference between a2a_2 and a2a^2, and between (0,1](0,1] and {0,1}\{0,1\}.

Show answer

Use range(1, 5). The first expression labels a term or component; the second squares the value aa. The interval contains every real value greater than zero and at most one, including 1/21/2 but excluding zero. The finite set contains exactly zero and one.

4

Functions domains and composition

A function assigns exactly one output to each input in its declared domain. We write f:D→Cf:D\to C to name its domain DD and codomain CC. Every output must belong to CC, but not every element of CC needs to be produced. The set of outputs that are actually produced is the image f(D)={f(x):x∈D}f(D)=\{f(x):x\in D\}. This distinction affects whether an inverse exists and whether a proposed output can ever occur.

A formula is one way to describe a function. It is not the whole specification: the same expression with different domains can describe different functions. The rule f(x)=x2f(x)=x^2 on all real inputs has image [0,∞)[0,\infty). On the domain {0,1,2}\{0,1,2\} it has image {0,1,4}\{0,1,4\}. In both cases, we could choose R\mathbb{R} as the codomain, but the unused values in that codomain are not outputs of the function.

Domain codomain and image0 maps to 1, 1 maps to 3, and 2 maps to 5. The codomain also contains the unused value 9.Domain DCodomain C0113259Image = {1, 3, 5}; 9 is not attained
Figure 1.2

The mapping f(x)=2x+1f(x)=2x+1 on the domain {0,1,2}\{0,1,2\} produces {1,3,5}\{1,3,5\}. The declared codomain also contains 99, which is not attained. One arrow leaves each input; an unused codomain value is permitted.

Domain restrictions may come from an expression or from the problem. The reciprocal r(x)=1/(x−2)r(x)=1/(x-2) cannot accept x=2x=2 as a real input because division by zero is undefined. A real square-root function requires a nonnegative argument. A count-based function may exclude negative inputs even when its algebraic formula could be evaluated there. Declare the restriction that belongs to the problem before relying on a formula’s mechanical evaluability.

A function can also be piecewise. For example,

h(x)={2x+1,x<0,x2,x≥0.h(x)=\begin{cases}2x+1,&x<0,\\x^2,&x\ge0.\end{cases}

The conditions select the applicable rule. They must assign one result to every input in the domain. Here every real number belongs to exactly one branch, including the boundary x=0x=0. Overlapping branches with inconsistent values would fail to define a function; a missing branch would leave part of a proposed domain uncovered.

Worked example
Evaluate a piecewise function at its boundary

The first branch gives h(−2)=2(−2)+1=−3h(-2)=2(-2)+1=-3. The second gives h(3)=9h(3)=9 and h(0)=0h(0)=0. We do not use the first branch at zero: its condition is strict. A Python implementation uses if x < 0: return 2*x + 1 followed by return x*x. Testing the boundary is part of checking the mathematical specification.

Composition means applying one function to the output of another. The notation (f∘g)(x)=f(g(x))(f\circ g)(x)=f(g(x)) places the outer function on the left, but evaluation begins with gg. An input is valid only when it belongs to the domain of gg and the intermediate output belongs to the domain of ff. If all outputs of gg lie in ff’s domain, the composition is defined on all of gg’s domain. Otherwise, restrict the composition to the inputs that satisfy both checks.

Worked example
Composition order changes the result

Let f(t)=2t+1f(t)=2t+1 and g(t)=t2g(t)=t^2, both with real domain. Then

f(g(x))=2x2+1,g(f(x))=(2x+1)2.f(g(x))=2x^2+1,\qquad g(f(x))=(2x+1)^2.

At x=3x=3, the first produces g(3)=9g(3)=9, then f(9)=19f(9)=19. The second produces f(3)=7f(3)=7, then g(7)=49g(7)=49. These are different functions. Composition generally cannot be reordered simply because both rules accept the same types of input.

Two composition ordersStarting at 3, square then double and add one to obtain 19; reversing the rules obtains 49.g first, then f: f(g(3))f first, then g: g(f(3))3g(t) = t²9f(t) = 2t+1193f(t) = 2t+17g(t) = t²49
Figure 1.3

The two routes start with the same input and use the same rules, yet produce different outputs. Read the arrows in evaluation order rather than reading the written composition from left to right.

Suppose instead that f(t)=ln⁡(t−1)f(t)=\ln(t-1) and g(x)=x2g(x)=x^2. The outer rule requires t>1t>1, so the composition requires x2>1x^2>1, or x<−1x<-1 or x>1x>1. Although the inner square accepts zero, the composition does not. Checking only the original input against the inner domain misses the failure at the intermediate value.

Interactive

Choose two rules, change the order, and enter an input from −4-4 to 44. First reproduce 1919 and 4949 at x=3x=3. Then choose f(t)=ln⁡(t−1)f(t)=\ln(t-1) and g(t)=t2g(t)=t^2; compare x=0x=0, x=1x=1, and x=2x=2. The plot shows only values inside its displayed vertical range. An absent point can mean an invalid domain or a value outside the visible range; inspect the calculation message.

Without JavaScript, use the worked calculations above: f(g(0))f(g(0)) is undefined, f(g(1))f(g(1)) is undefined, and f(g(2))=ln⁡3f(g(2))=\ln3 in the logarithmic example.

An inverse function reverses a mapping uniquely. The inverse of f(x)=2x+1f(x)=2x+1 on R\mathbb{R} is f−1(y)=(y−1)/2f^{-1}(y)=(y-1)/2: substituting it in either direction restores the original value. The notation f−1f^{-1} denotes the inverse mapping, not the reciprocal 1/f1/f. A square on all real inputs has no inverse function to recover the input: 22 and −2-2 both produce 44. Restricting both the square’s domain and codomain to [0,∞)[0,\infty) gives the inverse y\sqrt{y}.

Do not infer that an implementation is a mathematical function of its displayed argument alone. A procedure that reads a clock, a mutable global variable, or a random generator may return different results on repeated calls with the same explicit input. Include the additional state in the model when you need a deterministic mapping. Later probability modules will model random outputs directly.

Check your understanding

For f(t)=1/(t−2)f(t)=1/(t-2) and g(x)=x+1g(x)=x+1, state the domain and formula of f(g(x))f(g(x)). Does checking that gg accepts the input suffice?

Show answer

The composition is 1/(x−1)1/(x-1), defined for real x≠1x\ne1. At x=1x=1, the inner rule is valid but produces 22, which the outer rule rejects. Both the original input and the intermediate output need domain checks.

5

Powers logarithms and growth

Powers describe repeated multiplication when the exponent is a positive integer. Thus a3=aaaa^3=aaa. For a nonzero base, the zero power is a0=1a^0=1 and a negative integer power is a−k=1/aka^{-k}=1/a^k. The restriction on the base matters: a negative power of zero would require division by zero. Expressions such as 000^0 have context-specific conventions; this module does not assign them a general real-valued interpretation.

Within their valid domains, powers obey aras=ar+sa^r a^s=a^{r+s} and (ar)s=ars(a^r)^s=a^{rs}. For positive real bases these rules extend naturally to real exponents. When a base is negative and an exponent is non-integer, the real-domain question becomes more delicate: (−1)1/2(-1)^{1/2} is not real. Do not apply a positive-base identity to every possible expression merely because the symbols look similar.

Exponential functions fix the base and vary the exponent. In 2x2^x, xx is the input. This differs from the power function x2x^2, whose base varies and whose exponent is fixed. At x=2x=2 both yield 44, but at x=3x=3 they yield 88 and 99, and at x=4x=4 both again yield 1616. A few coincidences do not make the functions identical. The plot in Lab 2 lets you compare them on a declared interval; their eventual growth is studied more carefully in Module 06.

A logarithm asks which exponent would produce a positive value. For a real base a>0a>0 with a≠1a\ne1, log⁡ax=y\log_a x=y means ay=xa^y=x, with x>0x>0. The function is the inverse of axa^x on the corresponding real domain and positive codomain. The natural logarithm ln⁡x\ln x uses the base ee, a positive irrational constant approximately 2.718282.71828. In this series, an unqualified mathematical log⁡\log means the natural logarithm unless a different base is stated.

The domains are part of these identities. For any real yy, ln⁡(ey)=y\ln(e^y)=y. For positive xx, eln⁡x=xe^{\ln x}=x. The second expression is undefined as a real calculation at x=0x=0 or at a negative input. A calculator error there is not a random software inconvenience: it reflects the domain of the specified real function.

Worked example
A shifted logarithm has a shifted domain

Let q(x)=ln⁡(x−1)q(x)=\ln(x-1). The argument of the logarithm must be positive, so x−1>0x-1>0, hence x>1x>1. Its domain is (1,∞)(1,\infty), not (0,∞)(0,\infty). We obtain q(2)=ln⁡1=0q(2)=\ln1=0 and q(1+e)=1q(1+e)=1. At x=1x=1, the argument is zero and the expression is undefined over the reals.

For positive real u,vu,v, logarithms convert multiplication into addition:

ln⁡(uv)=ln⁡u+ln⁡v,ln⁡(u/v)=ln⁡u−ln⁡v.\ln(uv)=\ln u+\ln v,\qquad \ln(u/v)=\ln u-\ln v.

The multiplication identity follows from the exponential rule: writing u=eru=e^r and v=esv=e^s gives uv=er+suv=e^{r+s}, so its natural logarithm is r+sr+s. The arguments and the quotient must remain in the valid domain. A corresponding real-power identity is ln⁡(ur)=rln⁡u\ln(u^r)=r\ln u for u>0u>0. These relationships will later turn products of independent probabilities into sums of log-likelihoods.

There is no corresponding general identity for addition. At u=v=1u=v=1, ln⁡(u+v)=ln⁡2\ln(u+v)=\ln2 is positive, while ln⁡u+ln⁡v=0\ln u+\ln v=0. One valid counterexample disproves a claimed identity over all positive inputs. It does not establish a replacement formula; the product identity needs its own explanation.

Worked example
Change the base without changing the function’s information

For a>0a>0, a≠1a\ne1, and x>0x>0,

log⁡ax=ln⁡xln⁡a.\log_a x=\frac{\ln x}{\ln a}.

To see this, let y=log⁡axy=\log_a x, so ay=xa^y=x. Taking natural logarithms gives yln⁡a=ln⁡xy\ln a=\ln x; divide by ln⁡a\ln a, which is nonzero because a≠1a\ne1. Thus log⁡28=ln⁡8/ln⁡2=3\log_2 8=\ln8/\ln2=3. The ratio, rather than either rounded decimal alone, expresses the exact relationship.

Growth comparisons need an input range and a purpose. Multiplying ln⁡n\ln n by the positive constant 1/ln⁡21/\ln2 changes its numeric values but not its broad growth pattern as nn increases. In a coding or information calculation, the base still matters because the units change: base-two logarithms express bits, while natural logarithms express nats. We will return to these units in information theory.

A graph is evidence about its displayed window, not a proof about all positive inputs. An exponential can appear smaller than a polynomial over a limited range and later grow faster. Also check the axes: a logarithmic axis changes the spacing of plotted values. Lab 2 uses shared ordinary axes so you can inspect the values directly. A curve leaving the visible rectangle has not ceased to exist.

Check your understanding

Which inputs are valid for ln⁡(3−x)\ln(3-x)? Does ln⁡(a+b)=ln⁡a+ln⁡b\ln(a+b)=\ln a+\ln b hold for every positive a,ba,b? Explain with a calculation rather than a slogan.

Show answer

Require 3−x>03-x>0, so x<3x<3. For the proposed identity, choose a=b=1a=b=1: its left side is ln⁡2>0\ln2>0 and its right side is 00. Both sides are defined, so this is a valid counterexample.

6

Finite sums products and scope

A finite sum combines terms over a declared index range. The summation symbol binds the index inside its expression: in ∑i=1nai\sum_{i=1}^n a_i, the letter ii takes each integer value from one through nn, while nn remains a parameter controlling the range. An occurrence of a letter outside that binding has its own meaning. This is the mathematical counterpart of a loop variable with a specified scope.

To read a sum reliably, identify four pieces: the index name, its start, its end, and the term being evaluated. Then expand a small case before trying to simplify. For example,

∑i=14(i+2)=(1+2)+(2+2)+(3+2)+(4+2)=18.\sum_{i=1}^{4}(i+2)=(1+2)+(2+2)+(3+2)+(4+2)=18.

This expression contains four terms. Neither the index nor the term is multiplied by the upper bound as a shortcut. Replacing the sum with 4(4+2)=244(4+2)=24 would incorrectly use the final term four times.

The index is a bound or dummy variable. Renaming it consistently does not change the sum: ∑i=14i2=∑j=14j2\sum_{i=1}^4 i^2=\sum_{j=1}^4 j^2. But a rename must not capture a variable already doing another job. In ∑i=1n(x+i)\sum_{i=1}^n(x+i), xx is free and ii is bound. Renaming the bound index to xx without changing the original free variable would silently alter the expression. Choose distinct names, just as you would avoid overwriting a parameter in code.

Finite sums can be rearranged and distributed using ordinary addition. For constant cc,

∑i=1n(cai+bi)=c∑i=1nai+∑i=1nbi.\sum_{i=1}^n(ca_i+b_i)=c\sum_{i=1}^n a_i+\sum_{i=1}^n b_i.

Expand both sides to see each term appear once. This is a property of the addition and multiplication used here; it is not evidence that every function satisfies f(a+b)=f(a)+f(b)f(a+b)=f(a)+f(b). Infinite sums require further convergence conditions before similar rearrangements are justified. The present section concerns finite sums only.

The empty sum is zero. This convention means that adding no contributions leaves an accumulated total unchanged. In our task, n=0n=0 makes the range from zero to n−1n-1 empty. There is no final term with a negative index to evaluate. The result is defined by the aggregation rule, not by pretending that a nonexistent term has the value zero.

A finite product uses ∏\prod instead of ∑\sum. For example, ∏i=14i=1⋅2⋅3⋅4=24\prod_{i=1}^4 i=1\cdot2\cdot3\cdot4=24. The empty product is one, because multiplying by no factors leaves a product unchanged. Setting it to zero would make every ordinary product vanish whenever it was split into a nonempty part and an empty part. These two identity values explain Python’s sum([]) and math.prod([]) results.

Worked example
Express the same four odd terms with different index conventions

Starting at zero gives ∑i=03(2i+1)=16\sum_{i=0}^{3}(2i+1)=16. Starting at one requires a changed term: ∑j=14(2j−1)=16\sum_{j=1}^{4}(2j-1)=16. The translation is j=i+1j=i+1. Keeping both the old term and the new start would give 3+5+7+9=243+5+7+9=24, which is a different task.

A double sum has two aggregation instructions. In

∑i=12∑j=13(10i+j),\sum_{i=1}^{2}\sum_{j=1}^{3}(10i+j),

fix the outer index ii, complete the inner sum over jj, and then add the inner results. At i=1i=1, the terms are 11,12,1311,12,13 and total 3636. At i=2i=2, they are 21,22,2321,22,23 and total 6666. The whole sum is 102102. There are six terms because each of two outer values has three inner values.

Rectangular double sumRow one contains 11, 12, 13 and totals 36. Row two contains 21, 22, 23 and totals 66. Combined total is 102.Term = 10i + jj = 1j = 2j = 3i = 1111213= 36i = 2212223= 66Total: 36 + 66 = 102
Figure 1.4

The rectangular index grid makes all six terms visible. A row corresponds to one outer index; adding the row totals completes the outer sum. This is an indexing diagram, not a prerequisite in matrix algebra.

Because this range is a finite rectangle, summing columns first gives the same result: (11+21)+(12+22)+(13+23)=32+34+36=102(11+21)+(12+22)+(13+23)=32+34+36=102. A nonrectangular range needs more care. In ∑i=13∑j=1ij\sum_{i=1}^3\sum_{j=1}^i j, the inner upper bound depends on ii. The rows contain 11, then 1,21,2, then 1,2,31,2,3, for a total 1010. Simply switching the two written summation symbols without translating the valid index pairs changes the range.

The variable remaining after a sum tells you what kind of output it defines. In s(x)=∑i=13(x+i)s(x)=\sum_{i=1}^3(x+i), the bound index disappears after aggregation, but xx remains as the function input. Expanding gives s(x)=3x+6s(x)=3x+6. In tj=∑i=12aijt_j=\sum_{i=1}^2 a_{ij}, jj remains free and labels which column total is being described. These distinctions will prevent shape and axis mistakes when arrays appear in Module 09.

To translate the rectangular double sum, use range(1, 3) for the outer indices and range(1, 4) for the inner ones. To translate the triangular example, use range(1, 4) outside and range(1, i + 1) inside. Check a tiny example and an empty range before trying a large input. A large, plausible result does not expose which indices were omitted.

Check your understanding

Expand ∑i=02∑j=12(i+j)\sum_{i=0}^{2}\sum_{j=1}^{2}(i+j). Which symbols are bound? What would remain free in ∑i=02(x+i)\sum_{i=0}^{2}(x+i)?

Show answer

The rows are 1+21+2, 2+32+3, and 3+43+4, so the total is 1515. Both ii and jj are bound in the double sum. In the second expression, ii is bound and xx is free; expansion gives 3x+33x+3.

7

Contracts claims and translation into code

A mathematical contract states what inputs are allowed and what relationship the result must satisfy. For the odd-number task, an input is a nonnegative integer nn. The output is the integer total

S(n)=∑i=0n−1(2i+1),S(n)=\sum_{i=0}^{n-1}(2i+1),

with the empty sum interpreted as zero. The input is not modified. Negative counts, fractional counts, and a request to average rather than total the terms are outside this specification. A separate software policy determines how invalid inputs are handled; the labs raise a clear ValueError.

Break the translation into explicit decisions. The mathematical count nn becomes a Python integer. The inclusive range ending at n−1n-1 becomes range(n). Each term becomes 2 * i + 1; multiplication needs its own operator in code. The total starts at zero and receives one term per iteration. This describes the computation more faithfully than copying symbols into a language that interprets them differently.

Worked example
Trace the contract before running the program

For n=4n=4, the successive indices are 0,1,2,30,1,2,3. The terms are 1,3,5,71,3,5,7 and the running totals are 1,4,9,161,4,9,16. For n=0n=0, there are no iterations and the initial total 00 is already the required output. For n=1n=1, one iteration contributes the term at index zero, producing 11.

The trace checks the boundary cases that often reveal an incorrect start or stop. It does not prove the program correct for all possible nonnegative counts. We will later use an invariant to make that general argument.

The formula defining SS and the claim S(n)=n2S(n)=n^2 have different roles. The definition tells us what to compute. The identity claims that an apparently different expression gives the same value for every valid nn. A test at n=4n=4 confirms one case. To establish the general identity, one can use induction in Module 04 or an algebraic finite-sum argument like the optional exercise at the end of this module.

Disproving a universal claim is often cheaper than proving one. To refute “every real function is additive,” choose f(x)=x2f(x)=x^2, a=2a=2, and b=3b=3. Then f(a+b)=25f(a+b)=25 but f(a)+f(b)=13f(a)+f(b)=13. Both inputs and all intermediate values lie in the declared domain, so the counterexample is valid. A supposed counterexample using an undefined logarithm would not be valid evidence about an identity stated only for positive arguments.

Distinguish three possible faults. A specification fault means the formula describes the wrong task: an average where a total was required. A translation fault means the program implements the wrong expression: range(1, n) where range(n) was required. A numerical fault means the machine arithmetic does not sufficiently approximate the intended calculation: an overflowing exponential or an unsuitable equality check. Different faults require different repairs.

When an AI paper writes an objective such as L(θ)=1n∑i=1nℓi(θ)L(\theta)=\frac1n\sum_{i=1}^n\ell_i(\theta), these basic skills still apply. The parameter θ\theta is free; ii is bound; nn is a positive count because division by zero would make the average undefined; and changing a sum to a mean changes its scale. You do not yet need to know how to minimise the objective to read its declared relationship. Differentiation and optimisation will supply those later steps.

Do not add a case to a formula silently. If the task later needs n=0n=0 to return “no score” rather than zero, update the contract and its tests. If a function must accept an array instead of a scalar, state its new input and output shapes. Mathematical precision is useful precisely because it makes these choices visible enough to discuss and verify.

Check your understanding

Why is sum(2*i+1 for i in range(1,n)) inconsistent with the contract? Give the smallest positive input that exposes the mistake.

Show answer

It omits index zero, whose term is 11. At n=1n=1 the faulty range is empty and returns 00, while the contract requires 11. At n=0n=0 both happen to return zero, so the empty case alone would miss the fault.

8

Common misconceptions

Symptom Cause Repair
“The count is 4, so the last zero-based index is 4” Confusing a count with a label Write the index list 0,1,2,3
An outer function fails after a valid inner call Checking only the original input Check the intermediate value against the outer domain
A codomain value is assumed reachable Confusing codomain with image Compute the attained values or describe the image
A claim is accepted after a few examples Confusing evidence with proof State the quantifier and seek an argument or a valid counterexample
Logarithms are distributed over addition Applying the product rule to a different operation Compare both expressions at positive inputs such as 1,1
“The plotted curve ends here” Confusing a display range with a function’s domain State the domain and inspect whether values leave the axes
A floating result is treated as exact Ignoring representation and rounding Label approximation and use a justified tolerance
9

Prepare the labs

Read the Python primer if any notation in the scripts is unfamiliar. Download each script into a folder you can find, open a terminal in that folder, and run python lab1_sums.py, python lab2_functions.py, or python lab3_diagnose.py. On Windows, py may be the appropriate command; on macOS/Linux it is often python3. Check that the selected interpreter is Python 3.11 or later. These scripts use only the standard library.

Each block below is the complete distributed script followed by output captured by the page builder. Read the questions and predict the important numbers before executing it. Changing a script locally should change its output; the published output describes the unmodified version. The figures generated by Lab 2 can be opened directly in a browser.

10

Lab 1 Expand and trace a finite sum

Goal: connect a declared integer range to its terms and total. Predict the terms and totals at n=0,1,4,6n=0,1,4,6, then run the code.

Download lab1_sums.py

"""Read finite sums and products. Run with Python 3.11+; no packages needed."""
from math import prod


def odd_sum(n):
    """Sum the first n positive odd integers; n must be a nonnegative int."""
    if isinstance(n, bool) or not isinstance(n, int) or n < 0:
        raise ValueError("n must be a nonnegative integer")
    terms = [2 * i + 1 for i in range(n)]
    return terms, sum(terms)


def rectangular_sum(rows, columns):
    """Sum 10*i+j for mathematical indices 1..rows and 1..columns."""
    return [[10 * i + j for j in range(1, columns + 1)]
            for i in range(1, rows + 1)]


if __name__ == "__main__":
    for n in (0, 1, 4, 6):
        terms, total = odd_sum(n)
        assert total == n * n
        print(f"n={n}: terms={terms}, sum={total}, n*n={n*n}")
    grid = rectangular_sum(2, 3)
    total = sum(sum(row) for row in grid)
    assert total == 102
    print(f"grid={grid}, double_sum={total}")
    assert sum([]) == 0 and prod([]) == 1
    print(f"empty_sum={sum([])}, empty_product={prod([])}")
    print("Checks passed on these inputs; examples alone are not a general proof.")
Output
n=0: terms=[], sum=0, n*n=0
n=1: terms=[1], sum=1, n*n=1
n=4: terms=[1, 3, 5, 7], sum=16, n*n=16
n=6: terms=[1, 3, 5, 7, 9, 11], sum=36, n*n=36
grid=[[11, 12, 13], [21, 22, 23]], double_sum=102
empty_sum=0, empty_product=1
Checks passed on these inputs; examples alone are not a general proof.

Investigate: change the test values to n=2,3,8n=2,3,8 and predict the totals. Explain why the two-dimensional table has six entries and why their total is 102102. Check the empty product and explain why one is the relevant identity.

Written result: show one complete expansion and trace. State exactly which inputs the assertions checked. Explain why these checks do not establish the identity for every nn.

11

Lab 2 Compare functions and their domains

Goal: connect values, formulas, and a plot. Predict the row for x=0x=0 and the two compositions at x=3x=3. The logarithm uses its real domain x>0x>0.

Download lab2_functions.py

"""Compare four functions and write an SVG plot using only the standard library.

Run: python lab2_functions.py
Optional: python lab2_functions.py --output functions.svg
"""
import argparse
from html import escape
import math
from pathlib import Path


def logarithm(x):
    if x <= 0:
        raise ValueError("ln(x) requires x > 0")
    return math.log(x)


FUNCTIONS = [("2*x+1", lambda x: 2 * x + 1, "#2563eb"),
             ("x*x", lambda x: x * x, "#7e22ce"),
             ("2**x", lambda x: 2 ** x, "#15803d"),
             ("ln(x)", logarithm, "#c2410c")]


def make_plot(destination):
    width, height = 760, 420
    left, right, top, bottom = 60, 720, 45, 335
    x_min, x_max, y_min, y_max = -2, 4, -4, 18
    def px(x):
        return left + (x - x_min) / (x_max - x_min) * (right - left)
    def py(y):
        return bottom - (y - y_min) / (y_max - y_min) * (bottom - top)
    parts = [f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {width} {height}" role="img" aria-labelledby="title desc">',
             '<title id="title">Four functions over stated domains</title>',
             '<desc id="desc">Linear, square, exponential and natural logarithm. The logarithm has no curve at nonpositive inputs. All curves share the same axes.</desc>',
             '<rect width="760" height="420" fill="white"/>',
             '<g font-family="sans-serif" font-size="13" fill="#475569">']
    for x in range(-2, 5):
        parts.append(f'<path d="M{px(x):.2f},{top} V{bottom}" stroke="#e2e8f0"/>')
        parts.append(f'<text x="{px(x):.2f}" y="355" text-anchor="middle">{x}</text>')
    for y in range(-4, 19, 2):
        parts.append(f'<path d="M{left},{py(y):.2f} H{right}" stroke="#e2e8f0"/>')
        parts.append(f'<text x="48" y="{py(y)+4:.2f}" text-anchor="end">{y}</text>')
    parts.extend([f'<path d="M{left},{py(0):.2f} H{right} M{px(0):.2f},{top} V{bottom}" stroke="#475569"/>',
                  '<text x="735" y="355">x</text><text x="35" y="30">y</text></g>'])
    for index, (label, function, colour) in enumerate(FUNCTIONS):
        commands = []
        connected = False
        for step in range(601):
            x = x_min + step * (x_max - x_min) / 600
            try:
                y = function(x)
            except ValueError:
                connected = False
                continue
            if not y_min <= y <= y_max:
                connected = False
                continue
            commands.append(f'{"L" if connected else "M"}{px(x):.2f},{py(y):.2f}')
            connected = True
        parts.append(f'<path d="{" ".join(commands)}" fill="none" stroke="{colour}" stroke-width="2.5"/>')
        legend_x = 70 + index * 170
        parts.append(f'<path d="M{legend_x},387 h20" stroke="{colour}" stroke-width="3"/>')
        parts.append(f'<text x="{legend_x+27}" y="391" font-family="monospace" font-size="14">{escape(label)}</text>')
    parts.append('</svg>')
    destination.parent.mkdir(parents=True, exist_ok=True)
    destination.write_text('\n'.join(parts), encoding='utf-8')


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--output', type=Path, default=Path('functions.svg'))
    args = parser.parse_args()
    print('x      2*x+1      x*x      2**x      ln(x)')
    for x in (-2, -1, 0, 1, 2, 4):
        values = []
        for _, function, _ in FUNCTIONS:
            try:
                values.append(f'{function(x):9.4f}')
            except ValueError:
                values.append('undefined')
        print(f'{x:2d} ' + ' '.join(values))
    f = lambda x: 2 * x + 1
    g = lambda x: x * x
    assert f(g(3)) == 19 and g(f(3)) == 49
    print(f'f(g(3))={f(g(3))}; g(f(3))={g(f(3))}')
    assert math.isclose(logarithm(4) / logarithm(2), 2.0)
    try:
        logarithm(0)
    except ValueError as error:
        print(f'domain check: {error}')
    else:
        raise AssertionError('zero must be rejected')
    make_plot(args.output)
    print(f'Plot written: {args.output.name}')
Output
x      2*x+1      x*x      2**x      ln(x)
-2   -3.0000    4.0000    0.2500 undefined
-1   -1.0000    1.0000    0.5000 undefined
 0    1.0000    0.0000    1.0000 undefined
 1    3.0000    1.0000    2.0000    0.0000
 2    5.0000    4.0000    4.0000    0.6931
 4    9.0000   16.0000   16.0000    1.3863
f(g(3))=19; g(f(3))=49
domain check: ln(x) requires x > 0
Plot written: functions.svg
Linear, square, exponential and logarithmic curves on shared axes; the logarithm is defined only for positive inputs.
Plot generated by the downloadable Python script.

Investigate: open functions.svg. Locate the curve for each rule and inspect where the logarithm begins. Change the sampled table inputs to 0.5, 1, 3; update the integer-format input label to a floating format if you do so. Explain why the plot’s absence at x≤0x\le0 differs from a valid curve lying above its vertical limit.

Written result: show the intermediate values leading to 1919 and 4949. Describe the four functions’ domains and explain why a plot over [−2,4][-2,4] is insufficient to prove an eventual-growth claim.

12

Lab 3 Diagnose invalid translations and identities

Goal: use valid counterexamples to locate a fault before repairing it. Predict the off-by-one total and the square-function counterexample.

Download lab3_diagnose.py

"""Find counterexamples and repair a contract, an index range, and an identity."""
import math


def bad_odd_sum(n):
    return sum(2 * i + 1 for i in range(1, n))


def odd_sum(n):
    if isinstance(n, bool) or not isinstance(n, int) or n < 0:
        raise ValueError('n must be a nonnegative integer')
    return sum(2 * i + 1 for i in range(n))


def shifted_log(x):
    if x <= 1:
        raise ValueError('ln(x-1) requires x > 1')
    return math.log(x - 1)


if __name__ == '__main__':
    n = 4
    print(f'off-by-one: n={n}, faulty={bad_odd_sum(n)}, repaired={odd_sum(n)}, expected={n*n}')
    assert bad_odd_sum(n) != n * n and odd_sum(n) == n * n
    f = lambda x: x * x
    a, b = 2, 3
    print(f'non-additive square: f(a+b)={f(a+b)}, f(a)+f(b)={f(a)+f(b)}')
    assert f(a + b) != f(a) + f(b)
    lhs, rhs = math.log(a + b), math.log(a) + math.log(b)
    print(f'false log identity: ln(a+b)={lhs:.6f}, ln(a)+ln(b)={rhs:.6f}')
    assert not math.isclose(lhs, rhs)
    assert math.isclose(math.log(a * b), rhs)
    print(f'correct product identity: ln(a*b)={math.log(a*b):.6f}')
    for x in (1, 2):
        try:
            print(f'shifted_log({x})={shifted_log(x):.6f}')
        except ValueError as error:
            print(f'shifted_log({x}) rejected: {error}')
    for invalid in (-1, 2.5, True):
        try:
            odd_sum(invalid)
        except ValueError:
            print(f'odd_sum({invalid!r}) rejected')
        else:
            raise AssertionError('invalid input accepted')
    print('Repairs preserve the stated domains; counterexamples refute the false claims.')
Output
off-by-one: n=4, faulty=15, repaired=16, expected=16
non-additive square: f(a+b)=25, f(a)+f(b)=13
false log identity: ln(a+b)=1.609438, ln(a)+ln(b)=1.791759
correct product identity: ln(a*b)=1.791759
shifted_log(1) rejected: ln(x-1) requires x > 1
shifted_log(2)=0.000000
odd_sum(-1) rejected
odd_sum(2.5) rejected
odd_sum(True) rejected
Repairs preserve the stated domains; counterexamples refute the false claims.

Investigate: use n=1n=1 as the minimal positive boundary case; choose other positive a,ba,b for the logarithm comparison; use shifted_log(0) and shifted_log(3) to test both sides of the domain boundary. Do not disable the domain checks to make the program appear to succeed.

Written result: distinguish the index-range fault, the false mathematical identity, and the invalid input. Explain each repair in terms of the original contract. Python booleans are deliberately rejected as counts even though Python treats them as an integer subtype.

13

Exercises with complete solutions

Exercises 1–12 are required and take about 80 minutes. Exercises 13–14 are optional extensions adding about 25 minutes. Try a written solution before revealing the answer.

Exercise 1★★★conceptual4 min

Classify 0,−3,5/2,20,-3,5/2,\sqrt{2} in N,Z,Q,R\mathbb{N},\mathbb{Z},\mathbb{Q},\mathbb{R}. Can one number belong to several systems?

Show solution

00 belongs to all four; −3-3 belongs to Z,Q,R\mathbb{Z},\mathbb{Q},\mathbb{R}; 5/25/2 belongs to Q,R\mathbb{Q},\mathbb{R}; 2\sqrt2 belongs to R\mathbb{R} and is irrational. The systems are nested, so membership can overlap. Our natural-number convention includes zero.

Exercise 2★★★calculation4 min

Evaluate −32-3^2, (−3)2(-3)^2, and ∣−3∣|-3|. Explain a Python assignment x = x + 1 without reading it as a real equation.

Show solution

The values are −9,9,3-9,9,3. The minus is outside the square in the first expression. Assignment reads the current value on the right, adds one, then associates the resulting value with x. It does not assert that the old value equals the new value.

Exercise 3★★★conceptual4 min

List which of 0,1/2,1,20,1/2,1,2 belong to (0,1](0,1]. Translate integer indices from one through four into a Python range.

Show solution

1/21/2 and 11 belong. Zero is excluded by the round bracket; two exceeds the upper bound. Use range(1,5) because the stop is excluded. The interval contains other real values too, not just the listed candidates.

Exercise 4★★★calculation4 min

Expand ∑i=03(2i+1)\sum_{i=0}^3(2i+1) and ∏i=13(i+1)\prod_{i=1}^3(i+1). State the values for their corresponding empty index ranges.

Show solution

The sum is 1+3+5+7=161+3+5+7=16. The product is 2⋅3⋅4=242\cdot3\cdot4=24. An empty sum is zero and an empty product is one. Do not substitute an invalid endpoint when the range has no terms.

Exercise 5★★★derivation5 min

For f(t)=3t−2f(t)=3t-2 and g(x)=x2+1g(x)=x^2+1, derive f(g(x))f(g(x)) and g(f(x))g(f(x)). Evaluate both at x=2x=2.

Show solution

f(g(x))=3(x2+1)−2=3x2+1f(g(x))=3(x^2+1)-2=3x^2+1, so its value is 1313. The other order gives g(f(x))=(3x−2)2+1=9x2−12x+5g(f(x))=(3x-2)^2+1=9x^2-12x+5, with value 1717 at x=2x=2. Both have real domain, but they differ as functions.

Exercise 6★★★derivation6 min

Expand and simplify s(x)=∑i=13(x+i)s(x)=\sum_{i=1}^3(x+i). Identify free and bound variables. Rename the bound variable safely.

Show solution

Expansion gives (x+1)+(x+2)+(x+3)=3x+6(x+1)+(x+2)+(x+3)=3x+6. The input xx is free; ii is bound by the sum. Writing ∑k=13(x+k)\sum_{k=1}^3(x+k) preserves the expression. Writing ∑x=13(x+x)\sum_{x=1}^3(x+x) would capture the original input and change the meaning.

Exercise 7★★★derivation6 min

Derive the inverse of f(x)=4x−3f(x)=4x-3 on R\mathbb{R}. Verify both composition directions, and explain why the square needs a domain restriction before it has an inverse.

Show solution

Solve y=4x−3y=4x-3 for xx: f−1(y)=(y+3)/4f^{-1}(y)=(y+3)/4. Then f−1(f(x))=(4x−3+3)/4=xf^{-1}(f(x))=(4x-3+3)/4=x and f(f−1(y))=4(y+3)/4−3=yf(f^{-1}(y))=4(y+3)/4-3=y. The real square maps both 22 and −2-2 to 44, so recovering a unique input is impossible. Restrict its domain and codomain to nonnegative reals to obtain the inverse square root.

Exercise 8★★★calculation8 min

Compute ∑i=12∑j=13(10i+j)\sum_{i=1}^2\sum_{j=1}^3(10i+j) by rows and by columns. Explain why the same reordering argument does not automatically apply to ∑i=13∑j=1ij\sum_{i=1}^3\sum_{j=1}^i j.

Show solution

Rows total 3636 and 6666, giving 102102. Columns total 32,34,3632,34,36, also giving 102102. The rectangular calculation includes each of six pairs exactly once in either order. In the triangular range, the valid pairs depend on the outer index. Its total is 1+(1+2)+(1+2+3)=101+(1+2)+(1+2+3)=10; a reordered expression must preserve that triangular set of pairs rather than use an arbitrary rectangle.

Exercise 9★★★coding8 min

Specify and implement h(x)=2x+1h(x)=2x+1 for x<0x<0, otherwise x2x^2, on real scalar inputs. Give three checks including the boundary and describe the possible output signs.

Show solution

Contract: one real scalar input, one real scalar output, no mutation. Implementation:

def h(x):
    if x < 0:
        return 2 * x + 1
    return x * x

Checks: h(−2)=−3h(-2)=-3, h(0)=0h(0)=0, h(3)=9h(3)=9. The negative-input branch can produce negative, zero, or positive values: at x=−1,−1/2,−1/4x=-1,-1/2,-1/4 the outputs are −1,0,1/2-1,0,1/2. The other branch produces nonnegative outputs. The sign of the input does not alone determine the sign of the first branch’s result.

Exercise 10★★★conceptual8 min

Let f(t)=ln⁡(t−1)f(t)=\ln(t-1) and g(x)=x2g(x)=x^2. State the composition’s domain and evaluate it at x=−2,0,2x=-2,0,2. If its codomain is declared as R\mathbb{R}, is every real output attained?

Show solution

Require x2−1>0x^2-1>0, giving (−∞,−1)∪(1,∞)(-\infty,-1)\cup(1,\infty). At −2-2 and 22, the result is ln⁡3\ln3; at zero it is undefined. Every real yy is attained: choose x=ey+1>1x=\sqrt{e^y+1}>1, then ln⁡(x2−1)=y\ln(x^2-1)=y. In this particular example the image equals the codomain; that needs an argument and is not true of every function.

Exercise 11★★★coding11 min

A programmer implements the first nn positive odd integers using range(1,n). Find a minimal positive counterexample, repair it, and specify invalid-input behaviour.

Show solution

At n=1n=1, the range is empty and returns zero instead of one. Use range(n) with term 2*i+1, or range(1,n+1) with term 2*i-1. Require a nonnegative integer and reject negative/fractional inputs clearly. If the contract excludes booleans, check them explicitly because Python’s bool is a subclass of int. Check zero, one, and a larger count after the repair.

Exercise 12★★★conceptual12 min

Diagnose two claims: “every function distributes over addition” and “ln⁡(a+b)=ln⁡a+ln⁡b\ln(a+b)=\ln a+\ln b for positive inputs.” Give valid counterexamples and explain why successful checks cannot prove either universal claim.

Show solution

For the first, choose f(x)=x2f(x)=x^2, a=2a=2, b=3b=3: 25≠1325\ne13. For the second, choose a=b=1a=b=1: ln⁡2≠0\ln2\ne0. Every involved expression is defined on its declared domain. A universal statement fails when one valid input contradicts it; a finite collection of successful cases still leaves other inputs unexamined. The valid logarithm identity involves a product, not a sum.

Exercise 13★★★derivation10 min

Optional: derive ∑i=0n−1(2i+1)=n2\sum_{i=0}^{n-1}(2i+1)=n^2 using a reversed finite sum. Include n=0n=0.

Show solution

For n>0n>0, let A=0+1+⋯+(n−1)A=0+1+\cdots+(n-1). Reverse its order and add termwise. Each of the nn paired terms equals n−1n-1, so 2A=n(n−1)2A=n(n-1). Therefore ∑(2i+1)=2A+n=n(n−1)+n=n2\sum(2i+1)=2A+n=n(n-1)+n=n^2. At n=0n=0, the sum is empty and both sides are zero. The derivation covers the declared domain rather than only observed examples.

Exercise 14★★★derivation15 min

Optional: correctly reverse the order of ∑i=1n∑j=1ij\sum_{i=1}^n\sum_{j=1}^i j. Give the new bounds and verify n=3n=3.

Show solution

Valid pairs satisfy 1≤j≤i≤n1\le j\le i\le n. Fixing jj first means that ii ranges from jj through nn, so the equivalent expression is ∑j=1n∑i=jnj=∑j=1n(n−j+1)j\sum_{j=1}^n\sum_{i=j}^n j=\sum_{j=1}^n(n-j+1)j. At n=3n=3, this is 3⋅1+2⋅2+1⋅3=103\cdot1+2\cdot2+1\cdot3=10, agreeing with the original. The index-pair description explains why the bounds change.

14

Self check quiz

Nine choices are checked automatically. Question 10 requires an explanation; compare it with the model answer and mark your own reasoning. The automatic score concerns the nine choices only. The written response and its review mark are saved in this browser, alongside session progress.

1
Under this series’ convention, is zero a natural number?
2
What does Python range(1,5) generate?
3
What is the image of the real square function?
4
If f(t)=2t+1f(t)=2t+1 and g(t)=t2g(t)=t^2, what is f(g(3))f(g(3))?
5
What is the real domain of ln⁡(x−1)\ln(x-1)?
6
Which general identity holds for positive a,ba,b?
7
What is an empty product?
8
In ∑i=13(x+i)\sum_{i=1}^3(x+i), which variable remains free?
9
A proposed universal identity succeeds on ten inputs. What follows?
Show answer

For f(t)=1/(t−2)f(t)=1/(t-2) and g(x)=x+1g(x)=x+1, every real xx is valid for gg, but x=1x=1 produces g(1)=2g(1)=2, outside ff’s domain. The composition is 1/(x−1)1/(x-1) on R∖{1}\mathbb{R}\setminus\{1\}. Award the written point only when the response states the intermediate failure and the resulting domain; a different correct example is acceptable.

15

Guided reading

Required, 10 minutes: use the functions material in MIT Mathematics for Computer Science. Read the definitions of a function, its domain, and its codomain in the linked textbook; stop before the later relation/proof material. Write a mapping whose codomain has one unused value and explain why it is still a function.

Required, 15 minutes: read the notation and mathematical-language introduction in Mathematics for Machine Learning, alongside the notation summary below. Locate a finite indexed expression, name each symbol’s role, and expand a three-term instance. This is a preview of the book’s notation; you are not expected to understand its later linear algebra yet.

Optional: read the official Python range examples and math logarithm documentation when comparing code with notation. Use the documentation matching your installed interpreter if behaviour matters. The mathematical exposition and exercises here are original; external sources supply further reading.

16

Review and readiness for logic

The chain of ideas is: declare an object and its permitted values; name the operation; inspect its domain; expand a small case; translate the scope and indices; then check a claim using a valid argument. A function’s image is the output it actually attains, while its codomain is the declared target set. A finite sum binds its index; its other inputs may remain free.

Exit task: specify the piecewise function from Exercise 9, give its Python implementation, expand a small double sum, and refute the logarithm addition identity on valid inputs. Explain these without merely reproducing the answer. Use the proposed course rubric: written exercises 60 points, lab explanations 30, and quiz 10 including your reviewed written response.

Module 02 makes the words “every,” “some,” “if,” and “only if” precise. Before proceeding, explain the difference between a definition and a statement claiming something about every input. Keep the counterexample from this module: it is the first step towards logical reasoning.

17

Notation and bilingual terms

Symbol or term Meaning 中文
Domain Allowed inputs 定义域
Codomain Declared target set 陪域
Image Attained outputs 像
Composition f∘gf\circ g Apply g then f 复合函数
Inverse f−1f^{-1} Unique reversal of a mapping 反函数
∈\in / ⊆\subseteq Membership / set inclusion 属于 / 包含于
[a,b)[a,b) Include a, exclude b 左闭右开区间
∑\sum / ∏\prod Sum / product 求和 / 乘积
Bound / free variable Scoped index / remaining input 绑定变量 / 自由变量
Definition / assumption / claim Meaning / setting / statement to establish 定义 / 假设 / 主张
Counterexample Valid case refuting a universal claim 反例
Contract Allowed inputs and promised result 约定