Array broadcasting and mod / floor_divide operation - fusing error

Hi!

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)

Hey

That’s a funny one, I think it appears since one of the inputs (b) is clear. You can do the following

b_enc = fhe.zeros(b.shape) + b
c = fhe.multivariate(lambda a, b: a % b)(a, b_enc).reshape((-1, 1, 1))

and it should work. Warning, in your inputset, you have b=0 sometimes, it’s bad

1 Like

@benoit thank you for the fast reply!

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.

Cheers

1 Like

Ah now it’s clear, thank you again for the explanation! :slight_smile:

1 Like