I try to use the mod operation in conjunction with array broadcasting, but get the following fusing error:
RuntimeError: A subgraph within the function you are trying to compile cannot be fused because it has multiple input nodes
In clear everything works as expected. I get the same error for floor_divide, but everything works fine for add, sub and mul. I expected these operations to work similar? Is there a reason for this behavior, or am I missing something? Thank you!
This code reproduces my problem:
from concrete import fhe
import numpy as np
a = np.random.randint(0, 10, (4, 2, 1))
b = np.random.randint(0, 10, 4)
print(a)
print(a.shape)
def m(a, b):
# error
c = a % b.reshape((-1, 1, 1))
#c = a // b.reshape((-1, 1, 1))
# no error
#c = a + b.reshape((-1, 1, 1))
#c = a - b.reshape((-1, 1, 1))
#c = a * b.reshape((-1, 1, 1))
return c
print("CLEAR")
c = m(a, b)
print(c)
print(c.shape)
print("FHE")
compiler = fhe.Compiler(m, {"a": "encrypted", "b": "clear"})
inputset = [(a*i, b*i) for i in range(10)]
circuit = compiler.compile(inputset)
print(circuit)
circuit.keygen()
en_input = circuit.encrypt(a, b)
en_output = circuit.run(en_input)
output = circuit.decrypt(en_output)
print("output")
print(output)
Actually, I want to reshape b, before the modul operation. Adapting your code works for me, but is there a reason why both inputs must be encrypted and why I must use the fhe.multivariate extension for this to work?
Under the hood, we’ll have to use a table lookup, to replace the non linear function, as always with TFHE. Here, the non linear part is a % b. This function depends on a and b, so we have to use a kind of
T[a || b] = a % b
where || stands for concatenation. It could certainly work for non encrypted b, but it wasn’t implement in Concrete so far, so what I have done is coming back to something which is available. Replacing the a % b by a call to this T table is done automatically for you in Concrete, in the multivariate function. Have a look to docs.zama.ai/concrete and you’ll have more info on this operator.