mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
[ckks] polynomial evaluation return an error when ciphertext level doesn't enable full evaluation (closes #71)
In addition to the partially evaluated result, the homomorphic polynomial evaluation methods return an error if the ciphertext level does not enable full evaluation.
This commit is contained in:
committed by
GitHub
parent
6202936e00
commit
f023ff529d
@@ -502,7 +502,7 @@ func (btp *Bootstrapper) evaluateCheby(ct *Ciphertext) (res *Ciphertext) {
|
||||
eval.AddConst(C[1], -0.5/(scfac*(cheby.b-cheby.a)), C[1])
|
||||
}
|
||||
|
||||
res = eval.evalCheby(cheby, C, btp.relinkey)
|
||||
res, _ = eval.evalCheby(cheby, C, btp.relinkey)
|
||||
|
||||
sqrt2pi := math.Pow(0.15915494309189535, 1.0/float64(int(1<<btp.SinRescal)))
|
||||
|
||||
|
||||
@@ -75,7 +75,9 @@ func TestBootstrapp(t *testing.T) {
|
||||
|
||||
//fmt.Println(ciphertext.Level() - 1)
|
||||
//start := time.Now()
|
||||
ciphertext = testContext.evaluator.EvaluateCheby(ciphertext, cheby, testContext.rlk)
|
||||
if ciphertext, err = testContext.evaluator.EvaluateCheby(ciphertext, cheby, testContext.rlk); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
//fmt.Printf("Elapsed : %s \n", time.Since(start))
|
||||
//fmt.Println(ciphertext.Level())
|
||||
|
||||
@@ -132,7 +134,9 @@ func TestBootstrapp(t *testing.T) {
|
||||
|
||||
//fmt.Println(ciphertext.Level(), ciphertext.Scale())
|
||||
//start := time.Now()
|
||||
ciphertext = testContext.evaluator.EvaluateChebySpecial(ciphertext, scFac, cheby, testContext.rlk)
|
||||
if ciphertext, err = testContext.evaluator.EvaluateChebySpecial(ciphertext, scFac, cheby, testContext.rlk); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
//fmt.Println(ciphertext.Level(), ciphertext.Scale())
|
||||
|
||||
for i := 0; i < scNum; i++ {
|
||||
@@ -193,7 +197,9 @@ func TestBootstrapp(t *testing.T) {
|
||||
|
||||
//fmt.Println(ciphertext.Level(), ciphertext.Scale())
|
||||
//start := time.Now()
|
||||
ciphertext = testContext.evaluator.EvaluateChebySpecial(ciphertext, scFac, cheby, testContext.rlk)
|
||||
if ciphertext, err = testContext.evaluator.EvaluateChebySpecial(ciphertext, scFac, cheby, testContext.rlk); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
//fmt.Println(ciphertext.Level(), ciphertext.Scale())
|
||||
|
||||
for i := 0; i < scNum; i++ {
|
||||
|
||||
@@ -733,6 +733,8 @@ func testFunctions(testContext *testParams, t *testing.T) {
|
||||
|
||||
func testEvaluatePoly(testContext *testParams, t *testing.T) {
|
||||
|
||||
var err error
|
||||
|
||||
t.Run(testString(testContext, "EvaluatePoly/Exp/"), func(t *testing.T) {
|
||||
|
||||
if testContext.params.MaxLevel() < 3 {
|
||||
@@ -758,7 +760,9 @@ func testEvaluatePoly(testContext *testParams, t *testing.T) {
|
||||
values[i] = cmplx.Exp(values[i])
|
||||
}
|
||||
|
||||
ciphertext = testContext.evaluator.EvaluatePoly(ciphertext, poly, testContext.rlk)
|
||||
if ciphertext, err = testContext.evaluator.EvaluatePoly(ciphertext, poly, testContext.rlk); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
verifyTestVectors(testContext, testContext.decryptor, values, ciphertext, t)
|
||||
})
|
||||
@@ -766,6 +770,8 @@ func testEvaluatePoly(testContext *testParams, t *testing.T) {
|
||||
|
||||
func testChebyshevInterpolator(testContext *testParams, t *testing.T) {
|
||||
|
||||
var err error
|
||||
|
||||
t.Run(testString(testContext, "ChebyshevInterpolator/Sin/"), func(t *testing.T) {
|
||||
|
||||
if testContext.params.MaxLevel() < 5 {
|
||||
@@ -780,7 +786,9 @@ func testChebyshevInterpolator(testContext *testParams, t *testing.T) {
|
||||
values[i] = cmplx.Sin(values[i])
|
||||
}
|
||||
|
||||
ciphertext = testContext.evaluator.EvaluateCheby(ciphertext, cheby, testContext.rlk)
|
||||
if ciphertext, err = testContext.evaluator.EvaluateCheby(ciphertext, cheby, testContext.rlk); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
verifyTestVectors(testContext, testContext.decryptor, values, ciphertext, t)
|
||||
})
|
||||
|
||||
@@ -56,9 +56,9 @@ type Evaluator interface {
|
||||
PowerNew(op *Ciphertext, degree uint64, evakey *EvaluationKey) (opOut *Ciphertext)
|
||||
Power(ct0 *Ciphertext, degree uint64, evakey *EvaluationKey, res *Ciphertext)
|
||||
InverseNew(ct0 *Ciphertext, steps uint64, evakey *EvaluationKey) (res *Ciphertext)
|
||||
EvaluatePoly(ct *Ciphertext, coeffs *Poly, evakey *EvaluationKey) (res *Ciphertext)
|
||||
EvaluateCheby(ct *Ciphertext, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (res *Ciphertext)
|
||||
EvaluateChebySpecial(ct *Ciphertext, n complex128, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (res *Ciphertext)
|
||||
EvaluatePoly(ct *Ciphertext, coeffs *Poly, evakey *EvaluationKey) (res *Ciphertext, err error)
|
||||
EvaluateCheby(ct *Ciphertext, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (res *Ciphertext, err error)
|
||||
EvaluateChebySpecial(ct *Ciphertext, n complex128, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (res *Ciphertext, err error)
|
||||
}
|
||||
|
||||
// evaluator is a struct that holds the necessary elements to execute the homomorphic operations between Ciphertexts and/or Plaintexts.
|
||||
@@ -1243,10 +1243,19 @@ func (eval *evaluator) RescaleNew(ct0 *Ciphertext, threshold float64) (ctOut *Ci
|
||||
// in ctOut. Since all the moduli in the moduli chain are generated to be close to the
|
||||
// original scale, this procedure is equivalent to dividing the input element by the scale and adding
|
||||
// some error.
|
||||
// Returns an error if "threshold <= 0", ct.Scale() = 0, ct.Level() = 0, ct.IsNTT() != true or if ct.Leve() != ctOut.Level()
|
||||
func (eval *evaluator) Rescale(ct0 *Ciphertext, threshold float64, ctOut *Ciphertext) (err error) {
|
||||
|
||||
ringQ := eval.ringQ
|
||||
|
||||
if threshold <= 0 {
|
||||
return errors.New("cannot Rescale: threshold is 0")
|
||||
}
|
||||
|
||||
if ct0.Scale() == 0 {
|
||||
return errors.New("cannot Rescale: ciphertext scale is 0")
|
||||
}
|
||||
|
||||
if ct0.Level() == 0 {
|
||||
return errors.New("cannot Rescale: input Ciphertext already at level 0")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ckks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/bits"
|
||||
)
|
||||
@@ -25,6 +26,21 @@ func NewPoly(coeffs []complex128) (p *Poly) {
|
||||
return
|
||||
}
|
||||
|
||||
func checkEnoughLevels(levels uint64, pol *Poly, c complex128) (err error) {
|
||||
|
||||
logDegree := uint64(math.Log2(float64(len(pol.coeffs))) + 0.5)
|
||||
|
||||
if real(c) != float64(int64(real(c))) || imag(c) != float64(int64(imag(c))) {
|
||||
logDegree++
|
||||
}
|
||||
|
||||
if levels < logDegree {
|
||||
return fmt.Errorf("%d levels < %d log(d) -> cannot evaluate", levels, logDegree)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Degree returns the degree of the polynomial
|
||||
func (p *Poly) Degree() uint64 {
|
||||
return uint64(len(p.coeffs) - 1)
|
||||
@@ -61,7 +77,13 @@ func computeSmallPoly(split uint64, coeffs *Poly) (polyList []*Poly) {
|
||||
}
|
||||
|
||||
// EvaluatePoly evaluates a polynomial in standard basis on the input Ciphertext in ceil(log2(deg+1)) levels.
|
||||
func (eval *evaluator) EvaluatePoly(ct0 *Ciphertext, pol *Poly, evakey *EvaluationKey) (res *Ciphertext) {
|
||||
// Returns an error if the input ciphertext does not have enough level to carry out the full polynomial evaluation.
|
||||
// Returns an error if something is wrong with the scale.
|
||||
func (eval *evaluator) EvaluatePoly(ct0 *Ciphertext, pol *Poly, evakey *EvaluationKey) (opOut *Ciphertext, err error) {
|
||||
|
||||
if err := checkEnoughLevels(ct0.Level(), pol, 1); err != nil {
|
||||
return ct0, err
|
||||
}
|
||||
|
||||
C := make(map[uint64]*Ciphertext)
|
||||
|
||||
@@ -78,15 +100,19 @@ func (eval *evaluator) EvaluatePoly(ct0 *Ciphertext, pol *Poly, evakey *Evaluati
|
||||
computePowerBasis(1<<i, C, eval, evakey)
|
||||
}
|
||||
|
||||
res = recurse(eval.scale, logSplit, logDegree, pol, C, eval, evakey)
|
||||
|
||||
opOut, err = recurse(eval.scale, logSplit, logDegree, pol, C, eval, evakey)
|
||||
C = nil
|
||||
|
||||
return
|
||||
return opOut, nil
|
||||
}
|
||||
|
||||
// EvaluateCheby evaluates a polynomial in Chebyshev basis on the input Ciphertext in ceil(log2(deg+1))+1 levels.
|
||||
func (eval *evaluator) EvaluateCheby(op *Ciphertext, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (opOut *Ciphertext) {
|
||||
// Returns an error if the input ciphertext does not have enough level to carry out the full polynomial evaluation.
|
||||
// Returns an error if something is wrong with the scale.
|
||||
func (eval *evaluator) EvaluateCheby(op *Ciphertext, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (opOut *Ciphertext, err error) {
|
||||
|
||||
if err := checkEnoughLevels(op.Level(), &cheby.Poly, 2/(cheby.b-cheby.a)); err != nil {
|
||||
return op, err
|
||||
}
|
||||
|
||||
C := make(map[uint64]*Ciphertext)
|
||||
|
||||
@@ -101,11 +127,17 @@ func (eval *evaluator) EvaluateCheby(op *Ciphertext, cheby *ChebyshevInterpolati
|
||||
|
||||
// EvaluateChebyFastSpecial evaluates the input Chebyshev polynomial with the input ciphertext.
|
||||
// Slower than EvaluateChebyFast but consumes ceil(log(deg)) + 1 levels.
|
||||
func (eval *evaluator) EvaluateChebySpecial(ct *Ciphertext, n complex128, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (res *Ciphertext) {
|
||||
// Returns an error if the input ciphertext does not have enough level to carry out the full polynomial evaluation.
|
||||
// Returns an error if something is wrong with the scale.
|
||||
func (eval *evaluator) EvaluateChebySpecial(op *Ciphertext, n complex128, cheby *ChebyshevInterpolation, evakey *EvaluationKey) (opOut *Ciphertext, err error) {
|
||||
|
||||
if err := checkEnoughLevels(op.Level(), &cheby.Poly, 2/((cheby.b-cheby.a)*n)); err != nil {
|
||||
return op, err
|
||||
}
|
||||
|
||||
C := make(map[uint64]*Ciphertext)
|
||||
|
||||
C[1] = ct.CopyNew().Ciphertext()
|
||||
C[1] = op.CopyNew().Ciphertext()
|
||||
|
||||
eval.MultByConst(C[1], 2/((cheby.b-cheby.a)*n), C[1])
|
||||
eval.AddConst(C[1], (-cheby.a-cheby.b)/(cheby.b-cheby.a), C[1])
|
||||
@@ -114,27 +146,31 @@ func (eval *evaluator) EvaluateChebySpecial(ct *Ciphertext, n complex128, cheby
|
||||
return eval.evalCheby(cheby, C, evakey)
|
||||
}
|
||||
|
||||
func (eval *evaluator) evalCheby(cheby *ChebyshevInterpolation, C map[uint64]*Ciphertext, evakey *EvaluationKey) (res *Ciphertext) {
|
||||
func (eval *evaluator) evalCheby(cheby *ChebyshevInterpolation, C map[uint64]*Ciphertext, evakey *EvaluationKey) (opOut *Ciphertext, err error) {
|
||||
|
||||
logDegree := uint64(bits.Len64(cheby.Degree()))
|
||||
logSplit := (logDegree >> 1) //optimalSplit(logDegree) //
|
||||
|
||||
for i := uint64(2); i < (1 << logSplit); i++ {
|
||||
computePowerBasisCheby(i, C, eval, evakey)
|
||||
if err = computePowerBasisCheby(i, C, eval, evakey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for i := logSplit; i < logDegree; i++ {
|
||||
computePowerBasisCheby(1<<i, C, eval, evakey)
|
||||
if err = computePowerBasisCheby(1<<i, C, eval, evakey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
res = recurseCheby(eval.scale, logSplit, logDegree, &cheby.Poly, C, eval, evakey)
|
||||
opOut, err = recurseCheby(eval.scale, logSplit, logDegree, &cheby.Poly, C, eval, evakey)
|
||||
|
||||
C = nil
|
||||
|
||||
return
|
||||
return opOut, err
|
||||
}
|
||||
|
||||
func computePowerBasis(n uint64, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) {
|
||||
func computePowerBasis(n uint64, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) (err error) {
|
||||
|
||||
if C[n] == nil {
|
||||
|
||||
@@ -143,17 +179,25 @@ func computePowerBasis(n uint64, C map[uint64]*Ciphertext, evaluator *evaluator,
|
||||
b := n >> 1
|
||||
|
||||
// Recurses on the given indexes
|
||||
computePowerBasis(a, C, evaluator, evakey)
|
||||
computePowerBasis(b, C, evaluator, evakey)
|
||||
if err = computePowerBasis(a, C, evaluator, evakey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = computePowerBasis(b, C, evaluator, evakey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Computes C[n] = C[a]*C[b]
|
||||
C[n] = evaluator.MulRelinNew(C[a], C[b], evakey)
|
||||
|
||||
evaluator.Rescale(C[n], evaluator.scale, C[n])
|
||||
if err = evaluator.Rescale(C[n], evaluator.scale, C[n]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func computePowerBasisCheby(n uint64, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) {
|
||||
func computePowerBasisCheby(n uint64, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) (err error) {
|
||||
|
||||
// Given a hash table with the first three evaluations of the Chebyshev ring at x in the interval a, b:
|
||||
// C0 = 1 (actually not stored in the hash table)
|
||||
@@ -171,18 +215,26 @@ func computePowerBasisCheby(n uint64, C map[uint64]*Ciphertext, evaluator *evalu
|
||||
c := uint64(math.Abs(float64(a) - float64(b)))
|
||||
|
||||
// Recurses on the given indexes
|
||||
computePowerBasisCheby(a, C, evaluator, evakey)
|
||||
computePowerBasisCheby(b, C, evaluator, evakey)
|
||||
if err = computePowerBasisCheby(a, C, evaluator, evakey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = computePowerBasisCheby(b, C, evaluator, evakey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since C[0] is not stored (but rather seen as the constant 1), only recurses on c if c!= 0
|
||||
if c != 0 {
|
||||
computePowerBasisCheby(c, C, evaluator, evakey)
|
||||
if err = computePowerBasisCheby(c, C, evaluator, evakey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Computes C[n] = C[a]*C[b]
|
||||
//fmt.Println("Mul", C[a].Level(), C[b].Level())
|
||||
C[n] = evaluator.MulRelinNew(C[a], C[b], evakey)
|
||||
evaluator.Rescale(C[n], evaluator.scale, C[n])
|
||||
if err = evaluator.Rescale(C[n], evaluator.scale, C[n]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Computes C[n] = 2*C[a]*C[b]
|
||||
evaluator.Add(C[n], C[n], C[n])
|
||||
@@ -195,6 +247,8 @@ func computePowerBasisCheby(n uint64, C map[uint64]*Ciphertext, evaluator *evalu
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitCoeffs(coeffs *Poly, split uint64) (coeffsq, coeffsr *Poly) {
|
||||
@@ -261,7 +315,7 @@ func splitCoeffsCheby(coeffs *Poly, split uint64) (coeffsq, coeffsr *Poly) {
|
||||
return coeffsq, coeffsr
|
||||
}
|
||||
|
||||
func recurse(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) (res *Ciphertext) {
|
||||
func recurse(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) (res *Ciphertext, err error) {
|
||||
// Recursively computes the evalution of the Chebyshev polynomial using a baby-set giant-step algorithm.
|
||||
if coeffs.Degree() < (1 << logSplit) {
|
||||
|
||||
@@ -295,10 +349,14 @@ func recurse(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C ma
|
||||
//fmt.Printf("X^%2d: %f %f\n", nextPower, targetScale, targetScale* currentQi / C[nextPower].Scale())
|
||||
//fmt.Printf("X^%2d : qi %d %t %d %d\n", nextPower, level, coeffsq.lead, coeffsq.maxDeg, 1<<(logDegree-1))
|
||||
//fmt.Println()
|
||||
var tmp *Ciphertext
|
||||
if res, err = recurse(targetScale*currentQi/C[nextPower].Scale(), logSplit, logDegree, coeffsq, C, evaluator, evakey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = recurse(targetScale*currentQi/C[nextPower].Scale(), logSplit, logDegree, coeffsq, C, evaluator, evakey)
|
||||
|
||||
tmp := recurse(targetScale, logSplit, logDegree, coeffsr, C, evaluator, evakey)
|
||||
if tmp, err = recurse(targetScale, logSplit, logDegree, coeffsr, C, evaluator, evakey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.Level() > tmp.Level() {
|
||||
for res.Level() != tmp.Level()+1 {
|
||||
@@ -310,13 +368,18 @@ func recurse(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C ma
|
||||
evaluator.MulRelin(res, C[nextPower], evakey, res)
|
||||
|
||||
if res.Level() > tmp.Level() {
|
||||
evaluator.Rescale(res, evaluator.scale, res)
|
||||
if err = evaluator.Rescale(res, evaluator.scale, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//fmt.Printf("%f = %d) + (%d %f) = ", res.Scale(), res.Level(), tmp.Level(), tmp.Scale())
|
||||
evaluator.Add(res, tmp, res)
|
||||
//fmt.Printf("(%d %f) %f\n", res.Level(), res.Scale(), res.Scale()-tmp.Scale())
|
||||
} else {
|
||||
evaluator.Add(res, tmp, res)
|
||||
evaluator.Rescale(res, evaluator.scale, res)
|
||||
if err = evaluator.Rescale(res, evaluator.scale, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tmp = nil
|
||||
@@ -324,7 +387,7 @@ func recurse(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C ma
|
||||
return
|
||||
}
|
||||
|
||||
func recurseCheby(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) (res *Ciphertext) {
|
||||
func recurseCheby(targetScale float64, logSplit, logDegree uint64, coeffs *Poly, C map[uint64]*Ciphertext, evaluator *evaluator, evakey *EvaluationKey) (res *Ciphertext, err error) {
|
||||
// Recursively computes the evalution of the Chebyshev polynomial using a baby-set giant-step algorithm.
|
||||
if coeffs.Degree() < (1 << logSplit) {
|
||||
|
||||
@@ -359,10 +422,14 @@ func recurseCheby(targetScale float64, logSplit, logDegree uint64, coeffs *Poly,
|
||||
//fmt.Printf("X^%2d : qi %d %t %d %d\n", nextPower, level, coeffsq.lead, coeffsq.maxDeg, 1<<(logDegree-1))
|
||||
//fmt.Println()
|
||||
|
||||
res = recurseCheby(targetScale*currentQi/C[nextPower].Scale(), logSplit, logDegree, coeffsq, C, evaluator, evakey)
|
||||
if res, err = recurseCheby(targetScale*currentQi/C[nextPower].Scale(), logSplit, logDegree, coeffsq, C, evaluator, evakey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tmp *Ciphertext
|
||||
tmp = recurseCheby(targetScale, logSplit, logDegree, coeffsr, C, evaluator, evakey)
|
||||
if tmp, err = recurseCheby(targetScale, logSplit, logDegree, coeffsr, C, evaluator, evakey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.Level() > tmp.Level() {
|
||||
for res.Level() != tmp.Level()+1 {
|
||||
@@ -374,13 +441,17 @@ func recurseCheby(targetScale float64, logSplit, logDegree uint64, coeffs *Poly,
|
||||
evaluator.MulRelin(res, C[nextPower], evakey, res)
|
||||
|
||||
if res.Level() > tmp.Level() {
|
||||
evaluator.Rescale(res, evaluator.scale, res)
|
||||
if err = evaluator.Rescale(res, evaluator.scale, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//fmt.Printf("%f = %d) + (%d %f) = ", res.Scale(), res.Level(), tmp.Level(), tmp.Scale())
|
||||
evaluator.Add(res, tmp, res)
|
||||
//fmt.Printf("(%d %f) %f\n", res.Level(), res.Scale(), res.Scale()-tmp.Scale())
|
||||
} else {
|
||||
evaluator.Add(res, tmp, res)
|
||||
evaluator.Rescale(res, evaluator.scale, res)
|
||||
if err = evaluator.Rescale(res, evaluator.scale, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
tmp = nil
|
||||
@@ -389,7 +460,7 @@ func recurseCheby(targetScale float64, logSplit, logDegree uint64, coeffs *Poly,
|
||||
|
||||
}
|
||||
|
||||
func evaluatePolyFromPowerBasis(targetScale float64, coeffs *Poly, C map[uint64]*Ciphertext, evaluator *evaluator) (res *Ciphertext) {
|
||||
func evaluatePolyFromPowerBasis(targetScale float64, coeffs *Poly, C map[uint64]*Ciphertext, evaluator *evaluator) (res *Ciphertext, err error) {
|
||||
|
||||
if coeffs.Degree() == 0 {
|
||||
|
||||
@@ -430,7 +501,9 @@ func evaluatePolyFromPowerBasis(targetScale float64, coeffs *Poly, C map[uint64]
|
||||
}
|
||||
}
|
||||
|
||||
evaluator.Rescale(res, evaluator.scale, res)
|
||||
if err = evaluator.Rescale(res, evaluator.scale, res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -153,7 +153,9 @@ func example() {
|
||||
|
||||
poly := ckks.NewPoly(coeffs)
|
||||
|
||||
ciphertext = evaluator.EvaluatePoly(ciphertext, poly, rlk)
|
||||
if ciphertext, err = evaluator.EvaluatePoly(ciphertext, poly, rlk); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Done in %s \n", time.Since(start))
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ func randomComplex(min, max float64) complex128 {
|
||||
|
||||
func chebyshevinterpolation() {
|
||||
|
||||
var err error
|
||||
|
||||
// This example packs random 8192 float64 values in the range [-8, 8]
|
||||
// and approximates the function 1/(exp(-x) + 1) over the range [-8, 8].
|
||||
// The result is then parsed and compared to the expected result.
|
||||
@@ -79,7 +81,9 @@ func chebyshevinterpolation() {
|
||||
chebyapproximation := ckks.Approximate(f, -8, 8, 33)
|
||||
|
||||
// We evaluate the interpolated Chebyshev interpolant on the ciphertext
|
||||
ciphertext = evaluator.EvaluateCheby(ciphertext, chebyapproximation, rlk)
|
||||
if ciphertext, err = evaluator.EvaluateCheby(ciphertext, chebyapproximation, rlk); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Done... Consumed levels:", params.MaxLevel()-ciphertext.Level())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user