Wrong results: Too narrow parameters?

Thanks for v.1.0 – it was a great improvement.

I’ve been playing around a bit with it. However, in this case, what I view as reasonable a inputset does not appear to generate sufficiently large parameters:

from concrete import fhe
from itertools import product

inputset = [
        (1, 7, 1, 7), 
        (2, 9, 1, 7), 
        (3, 7, 2, 8), 
        (2, 8, 2, 8), 
        (3, 9, 2, 8), 
        (3, 9, 3, 9), 
        (2, 9, 3, 9), 
        (3, 9, 3, 7),
        (3, 9, 2, 8), 
        (3, 9, 3, 9), 
        (2, 9, 3, 9), 
        (1, 9, 1, 9),
        (1, 9, 3, 7),
        (1, 10, 1, 10), # Not really in range, but let's try to expand the parameters a bit
        (2, 10, 1, 10), 
        (3, 10, 2, 9), 
    ]

@fhe.compiler({"start": "encrypted", "end": "encrypted", "pstart": "clear", "pend": "clear"})
def check_two_equalities(start, end, pstart, pend):
    '''
    Check if both start and end are equal.
    Possible start values: 1, 2, 3
    Possible end values: 7, 8, 9
    '''

    correct_start = (start - pstart == 0)
    correct_end = (end - pend == 0)

    correct = correct_start * correct_end

    return correct

configuration = fhe.Configuration(p_error=0.2, loop_parallelize=True, show_graph=True)
circuit = check_two_equalities.compile(inputset, configuration)

start_end_pairs = [(1, 8), (2, 8), (3, 8), (1, 7)]
candidates = [(1, 7), (2, 7), (3, 7), (1, 8), (2, 8), (3, 8), (1, 9), (2, 9), (3, 9)]
for correct, cand in product(start_end_pairs, candidates):
    clear_evaluation = check_two_equalities(cand[0], cand[1], correct[0], correct[1])
    homomorphic_evaluation = circuit.encrypt_run_decrypt(cand[0], cand[1], correct[0], correct[1])
    print(correct, cand, clear_evaluation, homomorphic_evaluation)

When run, it will produce four columns of output. The two first is just the input. The third correctly prints 1 whenever the inputs are equal, but the fourth (which should be identical) does not.

I’ve tried to create sufficient variation inside the inputset to represent most of the cases, and I even went outside the formal domain of the function. (In principle, I shouldn’t have to, right?)

Is this a case of too aggressive parameter generation, or am I doing something silly somewhere? (For the latter, I suspect that me using multiplication as a proxy for AND could be an issue.)

Hi @MartinStrand,

You’re using the p_error of 0.2, and you have 4 TLUs in the circuit. Which results in the global probability of error of 0.5862676322948275 so yes it is expected that up to 58% of the results are incorrect. You can do print(circuit.global_p_error) to see it! If you change p_error to a reasonable value, the errors go away :slight_smile:

Let us know if this helps!

2 Likes

I … am embarrassed. I even read about that parameter, and convinced myself that I hadn’t touched that when I wrote the original code months ago. Actually reading that line of code was … completely unnecessary.

Thank you. It obviously worked. On a related note, p_error = 0.2 clearly also works.

(From now on, I know for sure that :slightly_smiling_face: means :man_facepalming:.)

3 Likes

No worries Martin, it’s just normal to miss some details of the code you haven’t touched in months! We’re always here to help :wink:

(And :slightly_smiling_face: is something I use for pretty much all answers, it doesn’t have a significance :sweat_smile:)

1 Like