Level budget & the modulus chain
On the Ciphertext state page we saw that every multiplication grows a ciphertext's scale, and that a mod-switch is what brings it back down. What we deferred until now: bringing scale down isn't free. Each mod-switch permanently spends a piece of the ciphertext's modulus chain, and once the chain is spent, no further multiplications are possible. Planning a pipeline means making sure the chain you configure is long enough for the multiplications you intend to do. That plan is your level budget, and this page is about how to make it.
The chain: rows and columns
full_q_list_precision. The digit recognizer on Build the Pipeline uses ((61,), (45,)). The illustration below adds extra columns so you can see both rows and columns:full_q_list_precision = ( (61,), # row 0: one prime ≈ 2^61 (61, 30), # row 1: two primes ≈ 2^61 and 2^30 (61,), # row 2: one prime )
Removes one prime from within a row. The cheaper, finer-grained option: the row survives with a smaller modulus.
Removes the entire row at once. Coarser, and what happens when a row has no spare columns left to give.
HomModSwitch has a variant parameter (0 = row, 1 = column); you're choosing which of these two spends to make. Most of the time you won't choose manually; see Mod-switch below.Rules when writing the tuple: every bit-size must be in 20–61, values within a row must be strictly descending, and the difference between adjacent values must itself fall in 20–61. Break any of these and the context refuses to initialize.
Multiplicative depth
HomAdd, HomConstAdd, etc.), slot sums (HomSumSlots), and everything client-only (HomRelu, HomReshape, etc.).HomSquare, HomConstMul, etc.) each spend one level through their built-in mod-switch (with_modswitch, on by default).HomExpand and HomRunningSum consume roughly len(stage_sizes) / stages_per_level levels; see Level collapse below. Or, HomPolyEval consumes multiple levels depending on the polynomial degree you give it.The exact level cost of every operator is stated in the Level budget field of its reference page. That field is the source of truth; the types above are how to think about it.
q=[…]), so you can watch the budget shrink op by op and see exactly where a too-short chain runs dry. You can also inspect each HomValue in the debugger for active rows and active columns on the q-list (remaining levels = their counts multiplied). See Inspecting the pipeline.Mod-switch: automatic vs. explicit
HomMul, HomConstMul, HomSquare, etc.) takes with_modswitch=True by default: after the operation, the cheapest available spend is made for you: a spare column from the first row that has one, otherwise a whole row.HomModSwitch when you want control over what gets dropped and when, for example, to spend a specific row before a section of your pipeline that needs the remaining ones intact.pt_scale is multiplied by new_q / prev_q; that's the mechanism by which scale comes back down.Level adjustment
HomAdd or HomMul, they must be on compatible chains: one's active rows and columns must be a subset of the other's. If they aren't, the higher-level ciphertext is automatically trimmed down to match the lower one before the operation runs. No parameter controls this; it simply means that combining a fresh ciphertext with a heavily-spent one costs the fresh one its advantage. Keep parallel branches at similar depths if you want to avoid paying for it.Restricting the spend: rows_budget
HomPolyEval, accepts a rows_budget parameter: a list of row indices that automatic mod-switch is allowed to spend from. Rows outside the budget are off-limits. Leave it unset unless you need to pin which rows may be spent.Level collapse
HomExpand, HomRunningSum) work through multiple internal rounds of multiplications, and would normally mod-switch between rounds. Their stage_sizes and stages_per_level parameters let you merge rounds:stage_sizes = (2, 2, 2)stage_sizes = (8,)stages_per_level tunes the same trade from the other side: how many rounds to group together before each mod-switch. The exact knobs for each operator are on its reference page.Next
full_q_list_precision.