During development, the speed of homomorphic execution can be a blocker for fast prototyping. You could call the function you're trying to compile directly, of course, but it won't be exactly the same as FHE execution, which has a certain probability of error (see Exactness).
To overcome this issue, simulation is introduced:
After the simulation runs, it prints the following:
There are some operations which are not supported in simulation yet. They will result in compilation failures. You can revert to simulation using graph execution using circuit.graph(...)
instead of circuit.simulate(...)
, which won't simulate FHE, but it will evaluate the computation graph, which is like simulating the operations without any errors due to FHE.
Overflow can happen during an FHE computation, leading to unexpected behaviors. Using simulation can help you detect these events by printing a warning whenever an overflow happens. This feature is disabled by default, but you can enable it by setting detect_overflow_in_simulation=True
during compilation.
To demonstrate, we will compile the previous circuit with overflow detection enabled and trigger an overflow:
You will see the following warning after the simulation call:
If you look at the MLIR (circuit.mlir
), you will see that the input type is supposed to be eint4
represented in 4 bits with a maximum value of 15. Since there's an addition of the input, we used the maximum value (15) here to trigger an overflow (15 + 1 = 16 which needs 5 bits). The warning specifies the operation that caused the overflow and its location. Similar warnings will be displayed for all basic FHE operations such as add, mul, and lookup tables.