I wonder about the size and form of Plaintext in CKKS Encoding for real number, taking small N for example:
Input vector array = [1.1, 2.2]
N = 8, scale Delta = 2^2 = 4
Number of slot = N/2 = 4
Form of Plaintext:
ptx = [4.4 8.8 0.0 0.0] with size of N/2
or:
ptx = [4.4 8.8 0.0 0.0 | 0.0 0.0 0.0 0.0] with size of N
or:
ptx = [4.4 8.8 0.0 0.0 | 4.4 8.8 0.0 0.0] with size of N
Thank you for your help!
First, in CKKS the number of slots is always N/2 where N is poly_modulus_degree. When you encode a vector shorter than that, the rest of the slots are simply set to zero. Therefore, in your case the plaintext slot values would be [1.1, 2.2, 0.0, 0.0], with a scale of 4. There is an important special case, however: when you encode a single value, then all the slots will hold that value.
However, this is not at all what the actual plaintext data looks like. There isn't an easy way to read the slot values from the plaintext coefficient data: none of the options you suggest match with what is happening in CKKS encoding:
the input vector is doubled in length with its complex conjugates;
an FFT-like transform is computed to convert the input vector into a complex-coefficient polynomial;
the complex coefficients are scaled the designated scale;
the real part of the coefficients is extracted as an integer modulo coeff_modulus (really this is in the RNS representation, i.e., modulo each coeff_modulus prime);
The resulting RNS polynomial is converted to NTT form, which is the default state for Plaintexts when using CKKS.
Without scaling, step 4. would introduce so much error that the process would become totally irreversible.
I really appreciate your help. I was vague how to encode and encrypt a message vector into a ciphertext using CKKS scheme, which I cannot print out in SEAL code. Anyway, I wonder that:
Steps from 2 to 5 transform a N-size vector into a N-size NTT-form ciphertext.
What is different between doubling a vector of real numbers and a vector of complex numbers in step 1,
How can we map real & image parts of complex numbers into N/2 slots in step 2?
Please don't laugh at me if the question is stupid :). Thanks for your help.
Related
Here is an example of convolution given:
I have two questions here:
Why is the vector 𝑥 padded with two 0s on each side? As, the length of kernel ℎ is 3. If 𝑥 is padded with one 0 on each side, the middle element of convolution output would be within the range of the length of 𝑥, why not one 0 on each side?
Explain the following output to me:
>> x = [1, 2, 1, 3];
>> h = [2, 0, 1];
>> y = conv(x, h, 'valid')
y =
3 8
>>
What is valid doing here in the context of the previously shown mathematics on vectors 𝑥 and ℎ?
I can't speak as to the amount of zero padding that is proper .... That being said, any zero padding is making up data that is not there. This isn't necessarily wrong, but you should be aware that the values computing this information may be biased. Sometimes you care about this, sometimes you don't. Introducing 1 zero (in this case) would leave the middle kernel value always in the data, but why should that be a stopping criteria? Importantly, adding on 2 zeros still leaves one multiplication of values that are actually present in the data and the kernel (the x[0]*h[0] and x[3]*h[2] - using 0 based indexing). Adding on a 3rd zero (or more) would just yield zeros in the output since 3 is the length of the kernel. In other words zero padding will always yield an output that is partially based on the actual data (but not completely) for any zero padding from n=1 to n = length(h)-1 (in this case either 1 or 2).
Even though zero padding with length 2 or 1 still has multiplications based on real data, some values are summed over "fake" data (those multiplied with a padded zero). In this case Matlab gives you 3 options for how you want the data returned. First, you can get the full convolution, which includes values that are biased because they include adding in 0 values that aren't really in the data. Alternatively you can get same, which means the length of the output is the length of the data y = [4 3 8 1]. This corresponds to 1 zero but note that for longer kernels you could technically get other lengths between full and same, Matlab just doesn't return those for you.
Finally, and probably most important to understand out of all this, you have the valid option. In your example only 2 samples of the output are computed from summations that occur only from multiplications over real data (i.e. from multiplying samples of the kernel with samples from x and not from zeros). More specifically:
y[2] = h[2]*x[0] + h[1]*x[1] + h[2]*x[2] = 3 //0 based indexing like example
y[3] = h[2]*x[1] + h[1]*x[2] + h[2]*x[3] = 8
Note none of the other y values are computed with only h and x, they all involve a padded zero which is not necessarily indicative of the real data. For example:
y[4] = h[2]*x[2] + h[1]*x[3] + h[2]*0 <= padded zero
Does anybody know an efficent way to retrieve such a result?
I could of course use rand(n,1) and then replace by iterating over the array values with zeros until the number of zeros is sufficient. (as written above atleast X% zeros it can also be more but not less)
I would prefer a completly random distribution but also a uniform distribution would be fine. (So I have no real clue how the distribution effects the result)
(Currently using MATLAB 2017a)
Use A=rand(n); to generate random vector, then use num = randi([n*proc,n]); to figure out how many of the numbers should be changed for 0 (proc is the minimum fraction of numbers which should be 0). Substitute for 0 with A(1:num)=0; and then shuffle the array with B = A(randperm(n));.
In total:
A=rand(n);
proc = 0.3;
num = randi([n*proc,n]);
A(1:num)=0;
B = A(randperm(n));
So I'm trying to figure out why my code doesn't seem to be displaying the properly uniformed quantized image into 4 levels.
Q1 =uint8(zeros(ROWS, COLS, CHANNELS));
for band = 1 : CHANNELS,
for x = 1 : ROWS,
for y = 1 : COLS,
Q1(ROWS,COLS,CHANNELS) = uint8(double(I1(ROWS,COLS,CHANNELS) / 2^4)*2^4);
end
end
end
No5 = figure;
imshow(Q1);
title('Part D: K = 4');
It is because you are not quantifying. You divide a double by 16, then multiply again by 16, then convert it to uint8. The right way to quantize is to divide by 16, throw away any decimals, then multiply by 16:
Q1 = uint8(floor(I1 / 16) * 16);
In the code snippet above, I assume I1 is a double. Convert it to double if its not: I1=double(I1).
Note that you don't need the loops, MATLAB will apply the operation to each element in the matrix.
Note also that if I1 is an integer type, you can do something like this:
Q1 = (uint8(I1) / 16) * 16;
but this is actually equivalent to replacing the floor by round in the first example. This means you get an uneven distribution of values: 0-7 are mapped to 0, 8-23 are mapped to 16, etc. and 248-255 are all mapped to 255 (not a multiple of 16!). That is, 8 numbers are mapped to 0, and 8 are mapped to 255, instead of mapping 16 numbers to each possible multiple of 16 as the floor code does.
The 16 in the code above means that there will be 256/16=16 different grey levels in the output. If you want a different number, say n, use 256/n instead of 16.
It's because you are using ROWS, COLS, CHANNELS as your index, it should be x,y,band. Also, the final multiplication of 2^4 has be after the uint8 cast otherwise no rounding ever takes place.
In practice you should avoid the for loops in Matlab since matrix operations are much faster. Replace your code with
Q1=uint8(double(I1/2^4))*2^4
No5 = figure;
imshow(Q1);
title('Part D: K = 4');
i need to quantize and encode an input signal using matlab so i will use uencode function . The problem is that i am confused about its process , the description says that it quantize and encode the input as integer and then he has displayed an example :
u = -1:0.01:1;
y = uencode(u,3);
plot(u,y,'.')
The output is just integers , can somebody just explain what this integers exactly are ?? and if i need the binary codes of the input u what i must do to get them ?
uencode takes the range of floating point numbers between -1.0 and 1.0, and maps it to the integers from 0 to (2^n)-1.
For example, with n=8, the possible integers are 0 to 255. -1.0 gets mapped to 0, +1.0 gets mapped to 255, and all decimal values in between get mapped to the closest integer.
In the code example you gave, n=3, so it is mapping to the integers 0 to 7. The plot shows horizontal lines because with so few integers available to map to, many floating point values map to the same integer.
To convert a base 10 integer to a base 2 binary string, use the function dec2bin.
>> dec2bin(5)
ans =
101
>> dec2bin(17)
ans =
10001
If you wanting leading zeros, say so that they are always 8 bits long, use the minimum length as a second argument:
>> dec2bin(5, 8)
ans =
00000101
I'm working in Matlab using Non-negative Matrix factorization to decompose a matrix into two factors. Using this I get from A two double precision floating point matrices, B and C.
sample results are
B(1,1) = 0.118
C(1,1) = 112.035
I am now trying to modify specific bits within these values but using the bitset function on either values I get an error because bitset requires unsigned integers.
I have also tried using dec2bin function, which I assumed would convert decimals to binary but it returns '0' for B(1,1).
Does anyone know of any way to deal with floats at bit level without losing precision?
You should look into the typecast and bitset functions. (Doc here and here respectively). That lets you do stuff like
xb = typecast( 1.0, 'uint64' );
xb = bitset( xb, 10, 1 );
typecast( xb, 'double' );
The num2hex and hex2num functions are your friends. (Though not necessarily very good friends; hexadecimal strings aren't the best imaginable form for working on binary floating-point numbers. You could split them into, say, 8-nybble chunks and convert each to an integer.)
From the MATLAB docs:
num2hex([1 0 0.1 -pi Inf NaN])
returns
ans =
3ff0000000000000
0000000000000000
3fb999999999999a
c00921fb54442d18
7ff0000000000000
fff8000000000000
and
num2hex(single([1 0 0.1 -pi Inf NaN]))
returns
ans =
3f800000
00000000
3dcccccd
c0490fdb
7f800000
ffc00000