Skip to content
The Lumenary

Math laboratory

Moving graphs and splitting functions into even and odd parts

Checks with exact fractions that points of y = f(x) move to points of y = a f(b(x - h)) + k by (x, y) -> (x/b + h, ay + k), shows that y = f(x - 2) moves the graph right, and splits several functions into even and odd parts, testing parity on a finite grid of rational points.

Back to the labExact computationExhaustive finite check
Moving graphs and splitting functions into even and odd partsPythonExact computationExhaustive finite checkComputationally tested
"""Transformations of graphs and the even/odd splitting, checked exactly.

The lesson proves that the graph of y = a f(b(x - h)) + k is the graph of f
moved by the rule (x, y) -> (x/b + h, a y + k). Here we test that rule with
exact fractions on sample points, see which way y = f(x - 2) moves, and split
functions into even and odd parts, checking the parts on a grid of points.
"""

from fractions import Fraction

def transform(f, a, b, h, k):
    """The function x -> a f(b(x - h)) + k."""
    return lambda x: a * f(b * (x - h)) + k

def move_point(point, a, b, h, k):
    """Where the transformation rule sends the point (x, y)."""
    x, y = point
    return (x / b + h, a * y + k)

def rule_holds(f, a, b, h, k, xs):
    """True if every moved point (x/b + h, a f(x) + k) lies on the new graph."""
    g = transform(f, a, b, h, k)
    for x in xs:
        u, v = move_point((x, f(x)), a, b, h, k)
        if g(u) != v:
            return False
    return True

def even_part(f):
    """x -> (f(x) + f(-x)) / 2."""
    return lambda x: (f(x) + f(-x)) / 2

def odd_part(f):
    """x -> (f(x) - f(-x)) / 2."""
    return lambda x: (f(x) - f(-x)) / 2

def parity(f, xs):
    """'even', 'odd', 'zero' or 'neither', judged on the points xs only.

    A function that is both even and odd is 0 at every checked point.
    """
    is_even = all(f(-x) == f(x) for x in xs)
    is_odd = all(f(-x) == -f(x) for x in xs)
    if is_even and is_odd:
        return "zero"
    return "even" if is_even else ("odd" if is_odd else "neither")

GRID = [Fraction(n, 4) for n in range(-12, 13)]

def main():
    def f(x):
        return x ** 3 - x

    a, b, h, k = Fraction(-1), Fraction(2), Fraction(1), Fraction(3)
    print("f(x) = x^3 - x and g(x) = -f(2(x - 1)) + 3; rule (x, y) ->"
          " (x/2 + 1, -y + 3)")
    for x in [-2, -1, 0, 1, 2]:
        x = Fraction(x)
        u, v = move_point((x, f(x)), a, b, h, k)
        g = transform(f, a, b, h, k)
        print(f"  ({x}, {f(x)}) -> ({u}, {v});  g({u}) = {g(u)}")
    print(f"rule holds on all {len(GRID)} grid points:",
          rule_holds(f, a, b, h, k, GRID))
    print()

    def square(x):
        return x * x

    right = transform(square, 1, 1, 2, 0)
    zeros = ", ".join(str(x) for x in GRID if right(x) == 0)
    print(f"y = x^2 has its zero at x = 0; y = (x - 2)^2 has it at x = {zeros}:")
    print("  replacing x by x - 2 moves the graph 2 units to the RIGHT.")
    print()
    print(f"parity on the grid {GRID[0]}..{GRID[-1]} (steps of 1/4):")
    examples = [
        ("x^4 - 3x^2", lambda x: x ** 4 - 3 * x ** 2),
        ("x^3 - 5x", lambda x: x ** 3 - 5 * x),
        ("x^2 + x", lambda x: x ** 2 + x),
        ("1/(1 + x^2)", lambda x: 1 / (1 + x ** 2)),
        ("x/(1 + x^2) + 1", lambda x: x / (1 + x ** 2) + 1),
    ]
    for name, fn in examples:
        e, o = even_part(fn), odd_part(fn)
        two = Fraction(2)
        odd2 = f"({o(two)})" if o(two) < 0 else f"{o(two)}"
        print(f"  {name:16s} {parity(fn, GRID):8s} even part {parity(e, GRID):5s}"
              f" odd part {parity(o, GRID):5s} f(2) = {e(two)} + {odd2}")
    print()
    print("Epistemic status: every value above is exact rational arithmetic, but")
    print("only finitely many points are checked. A function could pass on the")
    print("grid and fail elsewhere; the lesson's proofs (and the Lean versions)")
    print("establish the transformation rule and the even/odd splitting for all")
    print("real numbers.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Used in