fhelium.compile.passes.ckks
Transform logical operations into scheduled CKKS operations.
AggregateRotationSumsPass
class View source
AggregateRotationSumsPass(combine_rescale: bool = True, name: str = 'aggregate-rotation-sums')Replace compatible rotation/add trees with a shared QP quotient.
Including this pass is the caller's choice to change intermediate CKKS rounding. Matching uses SSA values and represented state. Independent intermediate users are preserved. Unknown effects, caller assignments, mismatched tables/state or partial required facts leave the region unchanged.
combine_rescale also recognizes uniformly rescaled inputs and divides the aggregate by P times the complete dropped Q group. Otherwise each original input rescale remains before the aggregate key switching.
Measured on RTX PRO 6000 Blackwell Server Edition: 128x128 @ 128x8 BSGS matrices, baby step 8, N=16384, Q=8, P=1, int64 residues, scale 2^40. Latencies include device synchronization, using resident inputs; values are medians of three process medians, with 30 samples per process.
| Execution / implementation | Matrix | Baseline (ms) | Aggregate (ms) |
|---|---|---|---|
| CUDA Graph / default fusion | PT x CT | 9.947 | 8.539 |
| CUDA Graph / default fusion | CT x CT | 17.901 | 16.444 |
| No Graph / whole operation | PT x CT | 12.702 | 11.835 |
| No Graph / whole operation | CT x CT | 21.132 | 25.383 |
Both matrix workloads improved with Graph replay. Without Graph, PT x CT improved, but CT x CT became 20.1% slower.
Attributes
| Name | Type | Default/value |
|---|---|---|
combine_rescale | bool | True |
name | str | 'aggregate-rotation-sums' |
run
method
def run(compilation): ...AssignCkksDepthsPass
class View source
AssignCkksDepthsPass(entry_depth: int | None = None)Assign depths and align add/sub joins after rescale placement.
Existing rescale nodes advance one public depth. At add/sub fan-in, only the lower-depth consumer edge is advanced through a real ModSwitchOp. Repeated application does not duplicate either transition.
Attributes
| Name | Type | Default/value |
|---|---|---|
entry_depth | int | None | None |
name | str | field(default='assign-ckks-depths', init=False) |
run
method
def run(compilation: 'Compilation') -> PassResult: ...AssignCkksScalesPass
class View source
AssignCkksScalesPass(entry_scale: float | None = None)Propagate actual scales through an already scheduled CKKS Program.
The pass updates represented scale metadata while preserving the arithmetic operations. Add/sub joins require equal binary64 scales. Rescale divides the input scale by config.rescale_divisor(depth), the product of the dropped Q group.
Attributes
| Name | Type | Default/value |
|---|---|---|
entry_scale | float | None | None |
name | str | field(default='assign-ckks-scales', init=False) |
run
method
def run(compilation: 'Compilation') -> PassResult: ...InsertMultiplyNttTransitionsPass
class View source
InsertMultiplyNttTransitionsPass(name: str = 'insert-multiply-ntt-transitions')Insert typed CKKS NTT transitions at registered logical multiplies.
The transformed operand type records NTT/Montgomery state, so repeated application is idempotent without a marker attribute. Unrealized casts preserve visible type-changing edges from logical values to CKKS values.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'insert-multiply-ntt-transitions' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...Insert missing transitions or return a legal no-op report.
InsertPlaintextPreparationPass
class View source
InsertPlaintextPreparationPass(name: str = 'insert-plaintext-preparation')Insert typed plaintext preparation at registered mixed logical ops.
Existing CKKS plaintext operands make repeated application a legal no-op. The visible unrealized cast on the ciphertext edge records the still-open logical-to-CKKS type conversion without mutating its producer.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'insert-plaintext-preparation' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...Prepare supported public operands across all function blocks.
InsertRelinearizationPass
class View source
InsertRelinearizationPass(name: str = 'insert-relinearization')Relinearize each CT3 multiplication before its first non-transition use.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'insert-relinearization' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...InsertRescalePass
class View source
InsertRescalePass(name: str = 'insert-rescale')Rescale each multiplication before its first non-transition use.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'insert-rescale' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...LateRelinearizationPass
class View source
LateRelinearizationPass(name: str = 'late-relinearization')Coalesce compatible CT3 add/sub/negate regions before relinearization.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'late-relinearization' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...LateRescalePass
class View source
LateRescalePass(name: str = 'late-rescale')Coalesce compatible add/sub/negate regions before rescaling.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'late-rescale' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...LowerLogicalToCkksPass
class View source
LowerLogicalToCkksPass(name: str = 'lower-logical-to-ckks')Lower registered logical arithmetic through visible typed CKKS edges.
Unrealized conversion casts preserve mixed-level result types for consumers that have not been lowered. Locally unresolved patterns remain legal no-ops and leave their original operations unchanged with diagnostics.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'lower-logical-to-ckks' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...Lower locally ready registered operations and report blockers.
LowerMessagePlaintextPreparationPass
class View source
LowerMessagePlaintextPreparationPass(name: str = 'lower-message-plaintext-preparation')Expand concrete message preparation into visible CKKS operations.
Depth, scale, ordered prime ids, and modulus basis must already be assigned by a caller-selected CKKS scheduling pass. Missing state is an error rather than a request for this pass to choose a depth or scale.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | 'lower-message-plaintext-preparation' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...ResolveRotationKeyOperandsPass
class View source
ResolveRotationKeyOperandsPass()Replace logical rolls with CKKS rotations bound to named key resources.
The pass normalizes each step using the CKKS slot count and names its resource rotation-key:<step>. It reads CkksConfig from the Compile workspace and records the resolved coefficient automorphism on the key operand. It writes symbolic references only; key creation and live binding remain caller responsibilities.
Attributes
| Name | Type | Default/value |
|---|---|---|
name | str | field(default='resolve-rotation-key-operands', init=False) |
run
method
def run(compilation: 'Compilation') -> PassResult: ...RotationHoistingPass
class View source
RotationHoistingPass(max_group_size: int | None = None, name: str = 'rotation-hoisting')Share preparation among rotations of the same ciphertext data.
A rotation has the form Finish(c0, Prepare(c1, tables), key, step). Rotations with the same input SSA value, parameter operands, and compatible attributes can share Prepare despite interleaved consumers or rotations of other inputs. The emitted RotateManyOp retains each key operand, result type, and rotation step. Its common output domain and execution attributes must agree across the group.
Matching and placement stay inside a block's known-pure effect interval. Unknown operations, effects, control flow, and assigned implementations end that interval; known nested regions are processed independently. Every group is placed after its computed operands and before its first result use. Material references may move within the interval, but producer computations are not speculated or reordered.
max_group_size bounds the number of results produced together. Grouping can extend result lifetimes.
Attributes
| Name | Type | Default/value |
|---|---|---|
max_group_size | int | None | None |
name | str | 'rotation-hoisting' |
run
method
def run(compilation: 'Compilation') -> PassResult: ...Identify compatible rotations and place legal multi-result groups.