GATE CS & DA Preparation Guide Module 5 – Digital logic and computer organisation (CS sections 2-3)
Boolean minimisation: K-maps and the tabular method
Minimise Boolean functions for GATE CS with K-maps and the Quine-McCluskey tabular method: prime implicants, essential ones and don't-cares.
What you will learn
- Simplify expressions with Boolean algebra, duality and the consensus theorem
- Find minimal sums of products with don't-cares on 3-, 4- and 5-variable K-maps
- Run the Quine-McCluskey tabular method to find prime implicants, essential prime implicants and a minimal cover
- Count prime implicants, essential prime implicants and literals for numerical answer questions
Before you start
What you’ll learn · Before you start
What you will learn
- Simplify expressions with Boolean algebra, duality and the consensus theorem
- Find minimal sums of products with don't-cares on 3-, 4- and 5-variable K-maps
- Run the Quine-McCluskey tabular method to find prime implicants, essential prime implicants and a minimal cover
- Count prime implicants, essential prime implicants and literals for numerical answer questions
Before you start
On this page
Written as a sum of its eight minterm: A product of all of a function's variables, each plain or complemented once, which is 1 on exactly one row of the truth table: with A, B, C and D, minterm 5 is A'BC'D., the function F = Σm(1, 2, 3, 5, 7, 8, 13, 15), with don't-care: An input whose output does not matter, because it never occurs or its output is ignored. Written X on a K-map or d(…) in a list, it may be read as 1 or 0, whichever gives the simpler circuit. at 0 and 6, takes 8 product terms and 32 literal: A variable or its complement as it appears in an expression. A'B' + BD has four literals, and counting literals is how two expressions for the same function are compared.. Minimised, it takes 3 terms and 7 literals, A’B’ + BD + B’C’D’, and its circuit shrinks with it. Every minimisation method rests on one identity, xy + xy’ = x: two terms that differ in a single variable merge into one term without it.
A Karnaugh map (K-map) applies that identity by eye: it lays out the truth table in Gray-code order, so that cells which merge sit side by side, and you circle groups of 1, 2, 4 or 8 cells. The tabular method, also called the Quine-McCluskey method, applies it by bookkeeping: it merges minterms written in binary until nothing merges, then chooses a cover from a chart. A map is quicker up to five variables; the table works for any number.
Five identities do all the merging
AB + A’C + BC + A’B’C has four terms and 9 literals, yet BC and A’B’C add nothing. Five identities find such terms:
- Combining: xy + xy’ = x. Two terms that differ in exactly one variable merge.
- Absorption: x + xy = x, and its dual x(x + y) = x.
- Consensus: xy + x’z + yz = xy + x’z. The term yz is redundant, because any input that makes it 1 also makes xy or x’z equal to 1.
- De Morgan: (x + y)’ = x’y’ and (xy)’ = x’ + y’.
- Duality: swap AND with OR, and 0 with 1, in an identity, and the result is an identity too.
Step through the two removals:
The drawing shows the whole scene; its 4 steps are listed below.
Every step as text
- Four terms. The expression has four terms and 9 literals. Look first for two terms with one variable plain in one and complemented in the other: AB and A'C disagree on A.
- Consensus. Drop the variable they disagree on and multiply what is left: the consensus of AB and A'C is BC. When BC is 1, AB is 1 if A = 1 and A'C is 1 if A = 0, so BC adds nothing and goes.
- Absorption. A'B'C is A'C with one more literal, so wherever A'B'C is 1, A'C is 1 too. x + xy = x absorbs it.
- Nothing left to remove. Neither of AB and A'C contains the other, and their consensus BC has already gone, so 2 terms and 4 literals remain instead of 9. The result agrees with the start on all eight inputs.
Consensus removed BC and absorption removed A’B’C, leaving AB + A’C: 4 literals instead of 9.
Checkpoint
Check: Merging and removing terms by algebra
A K-map puts cells that merge side by side
Minterms 5 and 7 of F, A’BC’D and A’BCD, differ only in C, so they merge into A’BD, and on a K-map they sit side by side. A four-variable map has 16 cells, one per minterm, with rows labelled AB and columns CD in the Gray code: An order of binary numbers in which neighbours differ in exactly one bit, such as 00, 01, 11, 10. A K-map labels its rows and columns in this order, so cells that sit side by side can merge. order 00, 01, 11, 10. Neighbouring cells differ in one variable, and so do the cells at the two ends of a row or a column, so groups may wrap round the edges. Step through one group of F as it doubles:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- One cell. Cell 5 is the minterm A'BC'D. On its own it is a group of one cell, a product of all 4 literals.
- A pair. Cell 7, A'BCD, sits beside it in row 01: the columns 01 and 11 differ only in C. xy + xy' = x merges the two into A'BD, 3 literals.
- The same pair below. Cells 13 and 15, ABC'D and ABCD, are the same pair in row 11, where A = 1. Rows 01 and 11 differ only in A, so the two pairs merge as well.
- A square of four. The square drops A as well and leaves BD, 2 literals. A group of 2² cells on a 4-variable map is a product of 4 − 2 = 2 literals.
- Not a group. Cells 5 and 15 alone sit diagonally: they differ in A and in C, two variables, so no identity merges them. A group is a rectangle of 1, 2, 4 or 8 cells, never a diagonal.
A group is a rectangle of 1, 2, 4 or 8 cells, and each doubling removes one literal: in an n-variable map, a group of 2k cells is a product of n − k literals. A don’t-care (X) joins a group when it makes the group larger, and otherwise stays 0.
Checkpoint
Check: Groups on a K-map
Essential prime implicants come first
A group that cannot grow any larger is a prime implicant. A prime implicant that is the only group covering some 1 is essential, and every minimal answer contains it. So take the essential prime implicants first, then cover the remaining 1s with as few groups as possible, each as large as possible. The map shows F’s cover:
The minimal cover of F on its K-map: two essential groups and one more
Text description of the diagram
A Karnaugh map with rows labelled by AB and columns by CD, both in the Gray-code order 00, 01, 11, 10, so that any two neighbouring rows or columns differ in one bit. Each cell shows the value of F and, in small print in its top-left corner, its minterm number. A legend under the map names each group by its line style.
- Row AB = 00 holds minterms 0, 1, 3 and 2: a don't-care (X) at 0 and 1s at 1, 3 and 2.
- Row AB = 01 holds 4, 5, 7 and 6: 0, 1, 1 and a don't-care at 6.
- Row AB = 11 holds 12, 13, 15 and 14: 0, 1, 1 and 0.
- Row AB = 10 holds 8, 9, 11 and 10: 1, 0, 0 and 0.
Three groups are drawn, each with its own line style:
- A solid outline around the whole top row: the group A'B', four cells, which uses the don't-care at 0 as a 1.
- A dashed outline around the square of minterms 5, 7, 13 and 15: the group BD, essential because it is the only group that covers 13 and 15.
- A dotted outline that leaves the top edge above cell 0 and comes back in from the bottom edge below cell 8: the pair B'C'D', which wraps round the map and is essential because it is the only group that covers 8.
Together they give F = A'B' + BD + B'C'D', three terms and seven literals. The don't-care at 6 is not used, so the circuit makes F(6) = 0.
The program below tries all 81 possible groups of F and keeps the prime ones. Change ONES or DONT_CARES to run it
on a function of your own:
"""Every prime implicant of F(A,B,C,D) = Σm(1,2,3,5,7,8,13,15) + d(0,6), found by trying every K-map group.
A group is written as a cube: one character per variable, A first, with '-' where the group spans both values.
"""
from itertools import combinations, product
NAMES = "ABCD"
ONES = {1, 2, 3, 5, 7, 8, 13, 15}
DONT_CARES = {0, 6}
ALLOWED = ONES | DONT_CARES
def cells(cube):
"""The minterms a cube covers."""
return {m for m in range(16) if all(c in "-" + b for c, b in zip(cube, format(m, "04b")))}
def term(cube):
"""A cube as a product of literals: '0-1-' -> A'C."""
return "".join(n + ("'" if c == "0" else "") for n, c in zip(NAMES, cube) if c != "-") or "1"
def literals(cube):
return sum(c != "-" for c in cube)
# A group is allowed when every cell in it is a 1 or a don't-care; it is prime when no larger allowed group
# contains it, and it is only useful when it covers at least one 1.
groups = ["".join(t) for t in product("01-", repeat=4) if cells("".join(t)) <= ALLOWED]
primes = [g for g in groups if cells(g) & ONES and not any(cells(g) < cells(h) for h in groups)]
primes.sort(key=lambda g: (-len(cells(g)), g))
print("F(A,B,C,D) = Σm(1, 2, 3, 5, 7, 8, 13, 15) + d(0, 6)")
header = "cells (d = don't-care)"
print(f"{'cube':<6}{'term':<9}{header:<25}essential for")
essential = []
for p in primes:
shown = " ".join(("d" if m in DONT_CARES else "") + str(m) for m in sorted(cells(p)))
only = [m for m in sorted(cells(p) & ONES) if [q for q in primes if m in cells(q)] == [p]]
if only:
essential.append(p)
print(f"{p:<6}{term(p):<9}{shown:<25}{', '.join('m' + str(m) for m in only) or '-'}")
# Smallest covers: fewest terms first, then fewest literals.
best = None
for k in range(1, len(primes) + 1):
for combo in combinations(primes, k):
if ONES <= set().union(*(cells(p) for p in combo)):
cost = (k, sum(literals(p) for p in combo))
if best is None or cost < best[0]:
best = (cost, [combo])
elif cost == best[0]:
best[1].append(combo)
if best:
break
(terms, lits), covers = best
print(f"prime implicants: {len(primes)}, essential: {len(essential)}")
for combo in covers:
print(f"minimal SOP: {' + '.join(term(p) for p in combo)} ({terms} terms, {lits} literals)")
print("minimal covers found:", len(covers))
cover = covers[0]
agrees = all((m in ONES) == any(m in cells(p) for p in cover) for m in range(16) if m not in DONT_CARES)
print("agrees with F on all", 16 - len(DONT_CARES), "specified inputs:", agrees) Output
F(A,B,C,D) = Σm(1, 2, 3, 5, 7, 8, 13, 15) + d(0, 6) cube term cells (d = don't-care) essential for -1-1 BD 5 7 13 15 m13, m15 0--1 A'D 1 3 5 7 - 0-1- A'C 2 3 d6 7 - 00-- A'B' d0 1 2 3 - -000 B'C'D' d0 8 m8 prime implicants: 5, essential: 2 minimal SOP: BD + A'B' + B'C'D' (3 terms, 7 literals) minimal covers found: 1 agrees with F on all 14 specified inputs: True
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 kmap_primes.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
F has five prime implicants. Follow the choice of its cover:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- The list. The program found five prime implicants: BD, A'D, A'C, A'B' and B'C'D'. Before choosing any, look for the 1s that only one of them covers.
- Cells 13 and 15. Cells 13 and 15 lie in BD and in no other prime implicant, so every cover must contain BD: it is essential.
- Cell 8. Cell 8 lies only in B'C'D', the pair that wraps from the top row to the bottom row through the don't-care 0. B'C'D' is essential too.
- What is left. BD covers 5, 7, 13 and 15, and B'C'D' covers 8. The 1s still uncovered are 1, 2 and 3: A'B' covers all three, where A'D and A'C cover two each.
- The cover. Three terms and seven literals. The don't-care 0 lies in two chosen groups, so it reads as 1; the don't-care 6 lies in none, so the circuit makes F(6) = 0.
The don’t-care 0 is used and 6 is not, so the circuit makes F(6) = 0, and A’B’ + BD + B’C’D’ is the only minimal cover.
Checkpoint
Check: Prime and essential prime implicants
The tabular method does the same by bookkeeping
Follow the method on a function of three variables, f = Σm(0, 1, 3, 7):
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- Binary. Write the minterms 0, 1, 3 and 7 of A, B and C in binary and group them by their number of 1s: 000 has none, 001 one, 011 two and 111 three.
- Combine. Compare each term with the terms of the next group. 000 and 001 differ in the last bit and give 00-; 001 and 011 give 0-1; 011 and 111 give -11. Every term combined, so every term is ticked.
- Repeat. 00-, 0-1 and -11 have their dashes in different places, so no two of them combine. Nothing is ticked in this round, so all three are prime implicants: A'B', A'C and BC.
- The chart. Draw a row per prime implicant and a column per 1. A'B' has an X under 0 and 1, A'C under 1 and 3, and BC under 3 and 7.
- The cover. Column 0 has its only X in the row of A'B', and column 7 in the row of BC, so both are essential. Together they cover 0, 1, 3 and 7, so f = A'B' + BC. A'C is left out: it is the consensus of A'B' and BC.
In general, the five steps are:
- Write each minterm and don’t-care in binary, grouped by their number of 1s.
- Compare each term with every term of the next group: two terms that differ in exactly one bit combine, with a dash in that bit, and both are ticked.
- Repeat until nothing combines. The terms never ticked are the prime implicants.
- Draw the prime-implicant chart: a row per prime implicant, a column per 1 (never per don’t-care), and an X where the row covers the column.
- A column with a single X marks an essential prime implicant. Take those, delete the columns they cover, and cover the rest.
When no column has a single X, the chart is cyclic. Petrick’s method settles it by writing the chart as a product of sums, one sum per column, and multiplying out to list every cover. The two methods side by side:
| K-map | Tabular method | |
|---|---|---|
| Variables, in practice | up to 4, or 5 with two maps | any number |
| Groups found | by eye, in Gray-code order | by combining terms that differ in one bit |
| Cover chosen | by eye | from the prime-implicant chart |
| Typical slip | a missed wrap-around group | a missed combination |
Checkpoint
Check: The tabular method
Practise: minimise, then count
What the GATE 2027 syllabus asks
Section 2 of the CS syllabus now names “Boolean algebra and minimization – algebraic technique, Karnaugh map, tabular method”, where the 2026 syllabus said only “Minimization”. Expect minimal expressions and counts of prime implicants, essential ones or literals, often as numerical answers.
Exercise · Medium · Python
List the prime and essential prime implicants of a function
Write two functions in primes.py for a Boolean function of n variables given by its 1s and its don't-cares, both as lists of minterm numbers.
A cube describes a K-map group: one character per variable, the first variable first, 1 for the variable, 0 for its complement and - where the group spans both values. With four variables A, B, C, D, the cube 0-1- is the term A'C and covers the minterms 2, 3, 6 and 7.
prime_implicants(n, ones, dont_cares=())returns every prime implicant as a sorted list of cubes. A cube is an implicant when every minterm it covers is a 1 or a don't-care, and prime when no larger implicant contains it. Leave out a prime implicant that covers don't-cares only: it is never needed.essential_prime_implicants(n, ones, dont_cares=())returns, as a sorted list, the prime implicants that are the only prime implicant covering at least one of the 1s.
prime_implicants(2, [1, 2]) # ['01', '10']: XOR has nothing to group
prime_implicants(3, [7], [3, 5, 6]) # ['-11', '1-1', '11-']
essential_prime_implicants(3, [7], [3, 5, 6]) # []: three groups cover the one 1Starter code · primes.py
"""Prime implicants of a Boolean function, written as cubes.
A cube has one character per variable, the first variable first: '1' for the variable, '0' for its
complement and '-' where the variable is absent. With four variables A, B, C, D, '0-1-' is A'C.
"""
def prime_implicants(n, ones, dont_cares=()):
"""Every prime implicant that covers at least one 1, as a sorted list of cubes."""
# Replace this line with your code.
return []
def essential_prime_implicants(n, ones, dont_cares=()):
"""The prime implicants that alone cover some 1, as a sorted list of cubes."""
# Replace this line with your code.
return [] The sample tests · test_primes.py
from primes import essential_prime_implicants, prime_implicants
def test_the_lesson_function():
"""F = Σm(1,2,3,5,7,8,13,15) + d(0,6) has five prime implicants, two of them essential"""
ones, dcs = [1, 2, 3, 5, 7, 8, 13, 15], [0, 6]
assert prime_implicants(4, ones, dcs) == ["-000", "-1-1", "0--1", "0-1-", "00--"]
assert essential_prime_implicants(4, ones, dcs) == ["-000", "-1-1"]
def test_xor_does_not_group():
"""no two 1s of XOR are neighbours, so each 1 is its own essential prime implicant"""
assert prime_implicants(2, [1, 2]) == ["01", "10"]
assert essential_prime_implicants(2, [1, 2]) == ["01", "10"]
def test_constant_functions():
"""the 0 function has no implicant at all; the 1 function is one cube"""
assert prime_implicants(3, []) == []
assert prime_implicants(3, range(8)) == ["---"]
assert essential_prime_implicants(3, range(8)) == ["---"]
def test_dont_cares_make_groups_but_are_not_required():
"""the three groups each cover the single 1 with a don't-care, so none is essential"""
assert prime_implicants(3, [7], [3, 5, 6]) == ["-11", "1-1", "11-"]
assert essential_prime_implicants(3, [7], [3, 5, 6]) == []
def test_a_cyclic_chart():
"""G = Σm(0,2,6,8,9,11,14,15): eight prime implicants, every 1 covered twice, none essential"""
ones = [0, 2, 6, 8, 9, 11, 14, 15]
assert len(prime_implicants(4, ones)) == 8
assert essential_prime_implicants(4, ones) == []
def test_a_group_of_dont_cares_alone_is_left_out():
"""d(4,5,6,7) would form the group A, but it covers no 1"""
assert prime_implicants(3, [0], [4, 5, 6, 7]) == ["-00"] A hint
There are only 3 ** n cubes, so try them all: itertools.product("01-", repeat=n) lists them. Work out the minterms a cube covers by comparing it with format(m, f"0{n}b") for every m below 2 ** n: each character must be - or equal to the bit. Keep the cubes whose minterms are all 1s or don't-cares, then drop every cube whose minterms are a strict subset of another kept cube's.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Practice that adapts to you
Practise this lesson
15 questions about 9 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
The tabular method traced table by table, and cyclic charts solved Pro: opens with a Pro, Premium or Ultimate pass
The tabular method is mechanical, and that is its strength in an exam: every step can be checked. This part runs it on F one table at a time, proves why the cover only ever needs prime implicants, and settles a chart in which no column has a single X.
In this part:
- Every table of the tabular method on F, worked
- Why a minimal cover needs prime implicants only, proved
- A cyclic chart settled with Petrick’s method
2 runnable examples (Python) · about 5 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Counting implicants, literals and functions for numerical answers Pro: opens with a Pro, Premium or Ultimate pass
Numerical answer questions have no options to eliminate, so every count must be exact. This part counts implicants two independent ways, checks the formulas for counting Boolean functions by brute force, and extends maps to five variables.
In this part:
- Five functions counted two ways, with the numbers
- How many functions, self-dual and neutral, with the formulas checked
- Five-variable maps and complete gate sets, worked
3 runnable examples (Python) · about 5 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Three traps that cost marks, reproduced and corrected Pro: opens with a Pro, Premium or Ultimate pass
Most wrong answers on minimisation come from a handful of habits that work on easy maps and fail on others. This part reproduces three of them on original functions and shows the correct reasoning next to each.
In this part:
- The biggest group is not always in the answer
- Don’t-cares in a product of sums are decided separately
- XOR patterns never group, and the counts questions ask for
1 runnable example (Python) · about 4 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Interview questions
-
Fresher · Warm-up
What is the difference between a prime implicant and an essential prime implicant?
An implicant is a product term that is 1 only where the function is 1 (or a don't-care); on a K-map it is a group of 1, 2, 4 or 8 cells. A prime implicant is an implicant that cannot be made any larger: no bigger group containing it stays inside the 1s and don't-cares. An essential prime implicant is a prime implicant that is the only one covering at least one of the function's 1s, so every minimal sum of products must contain it. A function can have many prime implicants and no essential ones at all: in a cyclic chart every 1 is covered by two or more prime implicants. The usual procedure takes the essential prime implicants first and then chooses among the others to cover the 1s that are left.
-
Fresher to mid
A classmate's K-map program always circles the largest remaining group first. It passes every textbook example you try, then gives five terms where four are enough. What kind of function breaks it, and how would you change the algorithm so that it is always right?
-
Fresher to mid
For a function with don't-cares, your minimal sum of products and your minimal product of sums give different outputs on one input. A friend says one of them must be wrong. Is that true? Explain, and say how you would check both answers.
-
Fresher
A numerical answer question asks for the number of essential prime implicants of a four-variable function with two don't-cares. How do you get an exact count in about three minutes, and where do most candidates lose the mark?
Key takeaways
- Two terms that differ in one variable merge, and consensus and absorption remove terms that add nothing.
- On a K-map, a rectangle of 2k cells in Gray-code order, wrapping round the edges, is a product of n − k literals.
- Essential prime implicants go into every minimal cover first, and the fewest, largest groups cover the rest.
- The tabular method merges terms one bit apart until nothing merges, then picks a cover from a chart of the 1s.
Terms in this lesson
- don't-care
- An input whose output does not matter, because it never occurs or its output is ignored. Written X on a K-map or d(…) in a list, it may be read as 1 or 0, whichever gives the simpler circuit.
- essential prime implicant
- A prime implicant that is the only one covering some 1 of the function, so every minimal sum of products contains it.
- Gray code
- An order of binary numbers in which neighbours differ in exactly one bit, such as 00, 01, 11, 10. A K-map labels its rows and columns in this order, so cells that sit side by side can merge.
- literal
- A variable or its complement as it appears in an expression. A'B' + BD has four literals, and counting literals is how two expressions for the same function are compared.
- minterm
- A product of all of a function's variables, each plain or complemented once, which is 1 on exactly one row of the truth table: with A, B, C and D, minterm 5 is A'BC'D.
- prime implicant
- A product term that is 1 only where the function is 1 or a don't-care and cannot be made larger: on a K-map, a group that no bigger rectangle of 1s and don't-cares contains.
References
- GATE 2027 syllabus for Computer Science and Information Technology (CS), section 2 (Indian Institute of Technology Madras (GATE 2027))
- GATE 2026 syllabus for Computer Science and Information Technology (CS) (Indian Institute of Technology Guwahati (GATE 2026))
- M. Karnaugh: The map method for synthesis of combinational logic circuits (Transactions of the American Institute of Electrical Engineers, Part I)
- W. V. Quine: The problem of simplifying truth functions (The American Mathematical Monthly)
- E. J. McCluskey: Minimization of Boolean functions (Bell System Technical Journal)
- itertools: functions creating iterators for efficient looping (Python Software Foundation)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress