During development, speed of homomorphic execution is a big blocker for fast prototyping. Furthermore, it might be desirable to experiment with more bit-widths, even though they are not supported yet, to get insights about the requirements of your system (e.g., we would have an XYZ model with 95% accuracy if we have 25-bits).
To simplify this process, we've introduces virtual circuits:
import concrete.numpy as cnp
import numpy as np
return np.sqrt(x * 100_000).round().astype(np.int64)
inputset = range(100_000, 101_000)
circuit = f.compile(inputset, enable_unsafe_features=True, virtual=True)
print(circuit.encrypt_run_decrypt(100_500), "~=", np.sqrt(100_500 * 100_000))
%0 = x # EncryptedScalar<uint17> ∈ [100000, 100999]
%1 = 100000 # ClearScalar<uint17> ∈ [100000, 100000]
%2 = multiply(%0, %1) # EncryptedScalar<uint34> ∈ [10000000000, 10099900000]
%3 = subgraph(%2) # EncryptedScalar<uint17> ∈ [100000, 100498]
%3 = subgraph(%2):
%0 = input # EncryptedScalar<uint1>
%1 = sqrt(%0) # EncryptedScalar<float64>
%2 = around(%1, decimals=0) # EncryptedScalar<float64>
%3 = astype(%2, dtype=int_) # EncryptedScalar<uint1>
100250 ~= 100249.6882788171
and it doesn't perform any homomorphic computation. It just simulates execution.
compileare configuration options.
virtaul=Trueenables makes the circuit virtual, and because virtual circuits are highly experimental, unsafe features must be enabled using
enable_unsafe_features=Trueto utilize virtual circuits. See How to Configure to learn more about configuration options.
Virtual circuits still check for operational constraints and type constraints. Which means you cannot have floating points, or unsupported operations. They just ignore bit-width constraints.