How to evaluate approximate 1/x function with high precision

Hello,
I’m attempting to evaluate the 1/x function on ciphertext.
I’ve used the EvalDivide() function from the library, but the results seem to have some errors.
Could you please review my code to see if there are any issues with how I’m using this function?

This is the code.

void EvalFunctionExample() {
    CCParams<CryptoContextCKKSRNS> parameters;

    parameters.SetSecurityLevel(HEStd_NotSet);
    parameters.SetRingDim(1 << 10);
#if NATIVEINT == 128
    usint scalingModSize = 78;
    usint firstModSize   = 89;
#else
    usint scalingModSize = 50;
    usint firstModSize   = 60;
#endif
    parameters.SetScalingModSize(scalingModSize);
    parameters.SetFirstModSize(firstModSize);

    uint32_t polyDegree = 50;
    uint32_t multDepth = 10;

    parameters.SetMultiplicativeDepth(multDepth);
    CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
    cc->Enable(PKE);
    cc->Enable(KEYSWITCH);
    cc->Enable(LEVELEDSHE);
    cc->Enable(ADVANCEDSHE);

    auto keyPair = cc->KeyGen();
    cc->EvalMultKeyGen(keyPair.secretKey);

    std::vector<double> input{1,2,3,4}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   ;
    size_t encodedLength = input.size();
    Plaintext plaintext  = cc->MakeCKKSPackedPlaintext(input);
    auto ciphertext      = cc->Encrypt(keyPair.publicKey, plaintext);

    double lowerBound = 0;
    double upperBound = 5;

    auto result = cc->EvalDivide(ciphertext, lowerBound, upperBound, polyDegree);

    Plaintext plaintextDec;
    cc->Decrypt(keyPair.secretKey, result, &plaintextDec);
    plaintextDec->SetLength(encodedLength);

    std::vector<double> finalResult = plaintextDec->GetRealPackedValue();
    std::cout << "Actual output\n\t" << finalResult << std::endl << std::endl;
}

This is the result.
image

Additionally, I’d like to learn how to achieve accurate evaluations of the 1/x function on ciphertext. Furthermore, I’m curious about the meaning of the upperbound parameter in the EvalDivide() function. Can this parameter have a large value, such as 100 or above?

Thank you for reading.

By setting the bounds to [1, 4] you will get almost perfect results:

Actual output
	[ 1 0.5 0.333333 0.25 ]

Of course, encode your values in a four-slots plaintexts:

Plaintext plaintext  = cc->MakeCKKSPackedPlaintext(input,1, 0, nullptr, 4);

Otherwise you would have a lot of zeros, which are not included in your interval.

In order to understand why this happens, think about 1 /x near zero:

y-1-x

Using polynomials to approximate that interval is really a hard problem, also because that function does not even exist in 0!
If you instead approximate it starting from 1 (or maybe also from 0.2/0.3, something like that) you will have less issues for sure.

1 Like