Exponents in Concrete

Hi, is it possible to perform an operation with a negative exponent (e.g. 2^(-10))? It throws the following error message when I try:

ValueError: Integers to negative integer powers are not allowed.
The above exception was the direct cause of the following exception:

RuntimeError: Evaluation of the graph failed

I’m also having issues even with a positive exponent, e.g.:

import numpy as np
from concrete import fhe

@fhe.compiler({"x": "encrypted"})
def f(x):
    arr1 = np.array([2] * len(x))
    return arr1 ** x # i.e. np.power(arr1, x)

inputset = [[2**8,2**8,1]]
circuit = f.compile(inputset)
circuit.keygen()

test_data = ([1, 2, 3])
print(circuit.encrypt_run_decrypt(test_data))

Returns [2, 4, 0], and the following:

import numpy as np
from concrete import fhe

@fhe.compiler({"x": "encrypted"})
def f(x):
    arr2 = []
    for i in x:
        arr2.append(2**i)

    return fhe.array(arr2)

Returns [2, 4, 6] for the same test data.

Thank you!

Hey @ac2421,

You’re doing (2**8) ** (2**8) which is 256**256, which cannot fit into numpy.int64 type we use. This expression overflows into 0, and that’s reflected in the measured bounds:

Computation Graph
--------------------------------------------------------------------------------
%0 = x                    # EncryptedTensor<uint9, shape=(3,)>        ∈ [1, 256]
%1 = [2 2 2]              # ClearTensor<uint2, shape=(3,)>            ∈ [2, 2]
%2 = power(%1, %0)        # EncryptedTensor<uint2, shape=(3,)>        ∈ [0, 2]
return %2
--------------------------------------------------------------------------------

Due to bounds, result is assigned two bits, and you get overflow in runtime.

I’d recommend using an appropriate inputset, and maybe hints!

Hope this helps.

Thank you for your help! It seems to run for smaller values after I changed the input set.

Is it possible to have a negative exponent on Concrete at all? I keep on getting the errors I mentioned above - I’d appreciate any advice.

1 Like

Negative exponent would mean a floating point result, which is not supported. What’s your use case, maybe we can find a workaround.

It’s essentially a sum of powers which have a negative exponent - I have some int() casts to avoid float values, but I’m trying to do something like:

2**(-255)a + 2**(-254)b + ...

At the moment, I’m just trying to find a way to calculate something as simple as 2**(-1), which throws the errors about not being able to have an integer to a negative integer power - I was then going to extend to my particular usecase.

Given that you mentioned that the numpy.int64 type is used, and the absolute value of my exponents are larger than that, I don’t think I could use a positive exponent and a division, as I’d still be calculating values like 2**(255). I’m assuming that using negative exponents is the easiest way around this.

Thank you!

2 ** (-1) is 0.5 which is not an integer. In fact every negative exponent would result in a value in range [0, 1), so none of them are integers. What you want is quantization! I’d recommend checking Quantization | 1.5 | Concrete ML for ideas. I’ll ask my fellow concrete-ml developers to give you some pointers as well :raised_hands:

Hello @ac2421 . Before going into the details of the quantization, could I ask what kind of function you want to compute and for which use, please?

I see your 2**(-255)a + 2**(-254)b + ... but it’s not obvious to me why you want to compute this. Could you show us the python function you would like to move to Concrete Python? In particular, what is a variable here and what is a constant? In your expression, 2**(-255) and friends are constant? If yes, it would not be related to the 2**x that you asked about, in the beginning of the question, is it?

Also in Concrete, there is the concept of table lookup (TLU), which is very useful to handle a lot of computation. I don’t know if it’s what you’re trying, but we shouldn’t use polynomial approximations in Concrete, it’s better to directly go for a TLU.

Once we know more (give ideally a lot of details), we should be able to help you.
Cheers

Thank you both! Apologies for the delay.
I’m basically trying to do a variant of the log-sum-exp function, which involves computing the very small powers:

For my usecase the powers decrease sequentially, but they are also multiplied by another number (hence I can’t simplify the expression further). I was just trying to see if Concrete could handle the negative exponents somehow?

Thanks!

So:

  • you could chose a parameter D
  • to compute x*, you could use the trick https://docs.zama.ai/concrete/core-features/workarounds#maximum-for-two-values, it will cost you about n PBS
  • and then, you can compute exp(x_i-x*) as first d_i = x_i-x* which is linear so easy, and then one PBS with table T where T[i] = int(D * exp(i)); and you will add the results; that’s another n PBS
  • and finally, you can compute log() with another PBS, this time with T’[i] = int(log(i / D))

and add with x*. You will have to select D such that it’s precise enough.

It would cost about 2n PBS.