When counting the jobs a CI build matrix expands to, how do you decide between multiplying axis sizes and adding case counts?
answer
- two rules, two conditions
- one object or separate cases
- independent choices multiply
- disjoint cases add
- product inside, sum across
basics
~20 sMultiply when a job is built by making one independent choice on each axis, so the options on one axis never depend on another. Add when the jobs split into cases that no single job can belong to twice.
solid answer
~50 sA build matrix job is a tuple: one runtime version, one operating system, one architecture. If the options on each axis are the same whatever you picked elsewhere, the jobs correspond one-to-one with tuples, and the product rule counts them — `3 * 4 * 2 = 24`. The addition rule applies across cases instead of within a job: two job families that can never produce the same job are counted separately and added. So the two questions to ask are: does fixing one choice change what remains available on another axis (if so the plain product overcounts), and can one job be produced by two of my cases (if so the plain sum overcounts)? When an axis does depend on another, partition by the dependent axis, take a product inside each part, and add the parts.
code
pseudocode · 9 lines// product rule: one choice per axis, axes independent
count = 0
for each version in versions: // 3 options
for each os in operating_systems: // 4 options
for each arch in architectures: // 2 options
count = count + 1 // ends at 24
// sum rule: two families that share no job
total = count_of(matrix_jobs) + count_of(nightly_jobs)go deeper
Remember the shape: choices combined inside one job multiply, separate groups of jobs add. A matrix with three, four and two options on its axes runs twenty-four jobs, not nine.
Explain the condition on each rule, not just the arithmetic: independence for the product, disjointness for the sum. Show the combined pattern where a constrained axis forces a split into cases that are multiplied and then added.
Be the person who states the correspondence before quoting a number, and who notices that a restricted axis makes the plain product wrong. In review, ask what a job maps to and whether two cases can produce the same one.
The multiplicative growth is a planning fact: each new axis multiplies pipeline cost and feedback time. Decide deliberately which axes belong in the full product and which belong in a separate, smaller family.
## The two rules, stated precisely Counting a build matrix rests on exactly two principles, and both have a condition attached that is easy to skip past. - **Product (multiplication) rule.** If every object is built by making one choice on each of `k` axes, and the number of options available on each axis does not depend on the choices made on the others, the number of objects is the product of the axis sizes. - **Sum (addition) rule.** If the objects split into cases such that every object belongs to **exactly one** case, the total is the sum of the case counts. Neither is an approximation. Both are exact whenever their condition holds, and both give a wrong number — silently — when it does not. ## Independence is a condition, not a formality Take a pipeline with three runtime versions, four operating systems and two architectures, every combination permitted. A job is one choice per axis, the axes do not constrain each other, so the matrix expands to `3 * 4 * 2 = 24` jobs. Adding a fourth operating system does not add one job; it adds `3 * 1 * 2 = 6`. That multiplicative growth is the whole practical point of the rule: a matrix grows by a factor when an axis grows, not by a term. Now suppose the oldest runtime version is only supported on one of the two architectures. The second axis is no longer free: its size is 2 for two of the versions and 1 for the third. `3 * 4 * 2` now counts four jobs that will never be scheduled. | | Product rule | Sum rule | |---|---|---| | Applies to | choices combined **within** one object | cases that **partition** the objects | | Condition | option counts independent across axes | cases pairwise disjoint, covering everything | | Failure signature | count too high when an axis restricts another | count too high when one object matches two cases | | Typical fix | split into cases, multiply inside each | redefine the cases so they cannot overlap | ## Counting by bijection: what makes the number trustworthy The reliable way to defend a count is to name the correspondence it assumes. State it out loud: *every scheduled job maps to exactly one tuple `(version, os, arch)`, and every tuple maps to exactly one scheduled job*. That is a bijection, and once you believe it, counting jobs is counting tuples — a mechanical product. This matters because most counting mistakes are not arithmetic mistakes. They are a broken correspondence: an object the enumeration can reach two ways, or a tuple that corresponds to no real job. If you can point at the bijection, you can point at exactly where it breaks. ## Combining the rules when an axis depends on another The combination is the workhorse pattern, and it is always the same three steps: 1. **Partition** the objects by the axis that does the constraining, choosing cases that cannot overlap. 2. **Multiply** inside each case, where the remaining axes are independent again. 3. **Add** the per-case products. For the matrix above, partition by runtime version. Two versions support both architectures: `2 * 4 * 2 = 16`. The legacy version supports one: `1 * 4 * 1 = 4`. Total `16 + 4 = 20` jobs, against the naive `24`. Notice the shape of the argument — product **inside** a case, sum **across** cases — and notice that step 1 earns step 3: disjointness is what licenses the addition. ## What these two rules do not cover They are the foundation, not the whole of counting, and it is worth knowing where each of the other tools takes over. - When the cases genuinely **do** overlap and you cannot redefine them, the correction that adds back what was subtracted twice is the **inclusion-exclusion principle** — a separate principle with its own alternating-sign machinery. - When the objects you are counting have a **symmetry** the enumeration does not respect, such as a ring that has no first element, the product overcounts by a fixed factor and you divide it out. - When a choice is *which `k` of `n`*, order irrelevant, the count is a binomial coefficient rather than a product of axis sizes. - One more property worth stating because candidates occasionally doubt it: multiplication is commutative and associative, so the order in which you take the axes cannot change the total. If two people multiply the same axes in different orders and disagree, one of them has a different set of axes, not a different rule. The practical habit to leave with: before multiplying, say why the axes are independent; before adding, say why the cases are disjoint. A count whose author can state both conditions is a count you can review.
- If one axis's available options depend on the choice made on another axis, can you still multiply?Not across the whole matrix. Split the objects into cases by the constraining axis, chosen so no job falls in two cases, multiply inside each case where the remaining axes are free again, then add the per-case products. Product inside a case, sum across cases.
- What does counting by bijection add beyond multiplying the axis sizes?It makes the assumption explicit and checkable: every scheduled job corresponds to exactly one tuple and every tuple to exactly one job. Most wrong counts are a broken correspondence rather than bad arithmetic, so naming it tells you where to look when the number disagrees with reality.
- Does adding a fifth operating system add one job to the matrix?No. With the other axes at three versions and two architectures, it adds a whole slice: 3 * 1 * 2 = 6 jobs. An axis grows the matrix by a factor, not by a term, which is why matrices outgrow their budget faster than teams expect.
saying these in an interview costs you the question
- Multiplies every axis size even when one axis restricts another
- Adds the counts of two case families that can contain the same job
- Thinks the product rule requires all axes to be the same size
- Says the order the axes are multiplied in changes the total
- Treats the addition rule as an estimate rather than an exact count