ECF 1.5
QuantumEvalOp.cpp
1#define GATE_SET3
2
3#include <ecf/ECF.h>
4#include "QuantumEvalOp.h"
5#include "IntGenotype.h"
6#include <list>
7#include <sstream>
8
9
10// global constants (extracted from computeFitness)
11const int keyA = 0;
12const int arA = 1;
13const int extraA = 2;
14const int numExtraA = 0;
15
16const int T = extraA+numExtraA;
17
18const int keyB = T+1;
19const int arB = T+2;
20const int extraB = T+3;
21const int numExtraB = 0;
22
23const int E = extraB+numExtraB;
24
25const int NUM_WIRES = E+1;
26
27const int ASpace = T; // largest wire (inclusive) A is allowed access to
28
29
30// algorithm variants related to fitness
31bool CONDITIONING = true;
32bool COMPUTE_ACTUAL_RATE = false;
33
34
35// parts not included in Win environment
36#ifndef WIN32
37
38#include "Quantum/Quantum.h"
39#include "attack.h"
40
41QKD::Attack* atk;
42std::vector <algebra::mat> EVec;
43
44void setupAttackVectors(QKD::Stats& stats) // run this once at startup!
45{
46 EVec.resize(4);
47 for(int i=0; i<EVec.size(); ++i)
48 EVec[i].create(4,1);
49
50 atk = new QKD::Attack(stats);
51}
52
53#endif
54
55
56namespace QKD
57{
58#ifdef GATE_SET1
59 const int nGateTypes = 3;
60 enum GateType
61 {
62 NOT=0,
63 Hadamard,
64 Measure
65 };
66#endif
67
68#ifdef GATE_SET2
69 const int nGateTypes = 4;
70 enum GateType
71 {
72 NOT=0,
73 Pi8,
74 Hadamard,
75
76 Measure
77 };
78#endif
79
80#ifdef GATE_SET3
81 const int nGateTypes = 4;
82 enum GateType
83 {
84 NOT=0,
85 Rotation,
86 Hadamard,
87
88 Measure
89 };
90#endif
91
92 struct Gate
93 {
94 Gate()
95 {
96 type = 0;
97 controlMode = false;
98 target = 0;
99 control = 0;
100 p = 0;
101 theta = 0;
102 psi = 0;
103 }
104 int type;
105 bool controlMode;
106 int target, control;
107 double p, theta, psi;
108 };
109}
110
111double SafeLog(double x)
112{
113 if(x < 0.000000001)
114 return 0;
115 return log(x) / log(2.0);
116}
117double entropy(double x)
118{
119 return -x*SafeLog(x) - (1-x)*SafeLog(1-x);
120}
121double entropy(double a, double b, double c, double d)
122{
123 return -a*SafeLog(a) - b*SafeLog(b) - c*SafeLog(c) - d*SafeLog(d);
124}
125
126#ifdef WIN32
127
128double ComputeFitness(std::list <QKD::Gate>& A, std::list <QKD::Gate>& B)
129{
130 return 1;
131}
132
133#else
134
135void applyGate(quantum::DensityList dl, int target, int control, QKD::Gate& G)
136{
137#ifdef GATE_SET1
138 switch(G.type){
139 case QKD::Hadamard: dl.applyHadamard(target, control);
140 break;
141
142 case QKD::NOT: dl.applyNOT(target, control);
143 break;
144
145 case QKD::Measure: Measure: dl.measure(target);
146 break;
147 }
148#endif
149#ifdef GATE_SET2
150 switch(G.type){
151 case QKD::Hadamard: dl.applyHadamard(target, control);
152 break;
153
154 case QKD::NOT: dl.applyNOT(target, control);
155 break;
156
157 case QKD::Pi8: dl.applyPiOver8(target, control);
158 break;
159
160 case QKD::Measure: dl.measure(target);
161 break;
162 }
163#endif
164#ifdef GATE_SET3
165 switch(G.type){
166 case QKD::Hadamard: dl.applyHadamard(target, control);
167 break;
168
169 case QKD::NOT: dl.applyNOT(target, control);
170 break;
171
172 case QKD::SU2: dl.applySU2(target, control, G.p, G.theta, G.psi);
173 break;
174
175 case QKD::Measure: dl.measure(target);
176 break;
177 }
178#endif
179}
180
181double ComputeFitness(std::list <QKD::Gate>& A, std::list <QKD::Gate>& B)
182{
184
185 for(int i=0; i<NUM_WIRES; ++i){
186 if(i != E)
187 dl.dimension.push_back(2);
188 else
189 dl.dimension.push_back(4);
190 }
191
192 quantum::KetBra kb(NUM_WIRES);
193 kb.p = 1;
194 dl.density.push_back(kb);
195
196 // run A:
197 if(!A.empty()){
198 std::list<QKD::Gate>::iterator Iter;
199 for(Iter = A.begin(); Iter != A.end(); ++Iter){
200 int target = Iter->target;
201 int control = Iter->control;
202 if(!Iter->controlMode)
203 control = -1;
204
205 // ensure that gates aren't applied to wires that cannot be accessed:
206 if(target > ASpace || control > ASpace)
207 continue;
208 if(target == E || control == E)
209 continue;
210
211 if(Iter->controlMode && control == target)
212 continue;
213
214 applyGate(dl, target, control, *Iter);
228 }
229 }
230
231 dl.applyAttackOp(T, E); // E attacks
232
233 // Run B:
234 if(!B.empty()){
235 std::list<QKD::Gate>::iterator Iter;
236 for(Iter = B.begin(); Iter != B.end(); ++Iter){
237 int target = Iter->target;
238 int control = Iter->control;
239 if(!Iter->controlMode)
240 control = -1;
241
242 // ensure that gates aren't applied to wires that cannot be accessed:
243 if(target < T || (control < T && control >= 0))
244 continue;
245 if(target == E || control == E)
246 continue;
247
248 if(Iter->controlMode && control == target)
249 continue;
250
251 applyGate(dl, target, control, *Iter);
265 }
266 }
267
268 // now A measures key
269 dl.measure(keyA);
270
271 // B measures key
272 dl.measure(keyB);
273
274 // project to both users accepting (conditioning):
275 if(CONDITIONING == true) {
276 dl.project(arA, 1);
277 dl.project(arB, 1);
278 }
279
280 // check that there is something here (always possible to "reject" with probability 1)
281 if(dl.density.empty())
282 return 0; // both parties are always saying 'reject' so no key so key-rate = 0.
283
284 atk->begin();
285
286 quantum::DensityList saveDL = dl;
287 double bestRate = 2;
288
289 while(!atk->getNext(EVec[0], EVec[1], EVec[2], EVec[3])){
290 dl = saveDL;
291 double paccept = dl.trace(EVec, E);
292 if(paccept <= 0.00000001)
293 return 0;
294 // compute H(A|B):
295
296 double p00 = dl.calculatePr(keyA, 0, keyB, 0, EVec, E);
297 double p01 = dl.calculatePr(keyA, 0, keyB, 1, EVec, E);
298 double p10 = dl.calculatePr(keyA, 1, keyB, 0, EVec, E);
299 double p11 = dl.calculatePr(keyA, 1, keyB, 1, EVec, E);
300
301 double HAB = entropy(p00, p01, p10, p11);
302 double HB = entropy(p00 + p10);
303
304 // compute S(A|E):
305 // trace out B's wires:
306 for(int w=keyA+1; w<E; ++w)
307 dl.trace(w);
308
309 // trace out A's extra wires:
310 //for(int w=keyA+1; w<=T; ++w)
311 // dl.trace(w);
312
313 double SAE = dl.entropy(EVec, E);
314 dl.trace(keyA);
315 double SE = dl.entropy(EVec, E);
316 double rate = 100;
317
318 if(COMPUTE_ACTUAL_RATE)
319 rate = (SAE - SE) - (HAB - HB);
320 else
321 rate = paccept * ( (SAE-SE) - (HAB-HB) );
322
323 if(rate < bestRate)
324 bestRate = rate;
325 }
326
327 return bestRate;
328}
329
330#endif
331
332void testSimple()
333{
334 std::list <QKD::Gate> A, B;
335 QKD::Gate g;
336 g.type = QKD::NOT;
337 g.target = 2;
338 A.push_back(g);
339 ComputeFitness(A,B);
340}
341
342void testBB84()
343{
344 std::list <QKD::Gate> A, B;
345 QKD::Gate g;
346 g.type = QKD::NOT;
347 g.target = 1;
348 g.controlMode = false;
349
350 A.push_back(g); // g1
351
352 g.type = QKD::Hadamard;
353 g.target = 0;
354 g.controlMode = false;
355
356 A.push_back(g); // g2
357
358 g.type = QKD::NOT;
359 g.target = 2;
360 g.controlMode = true;
361 g.control = 0;
362
363 A.push_back(g); // g3
364
365
366 g.type = QKD::NOT;
367 g.target = 3;
368 g.control = 2;
369 g.controlMode = true;
370
371 B.push_back(g); // h1
372
373 g.type = QKD::NOT;
374 g.target = 4;
375 g.controlMode = false;
376
377 B.push_back(g); // h2
378
379
380 std::cout << "Test 1: key-rate (should be 1) = " << ComputeFitness(A,B) << "\n\n";
381}
382
383void test()
384{
385 std::list <QKD::Gate> A, B;
386 QKD::Gate g;
387 g.type = 2;
388 g.target = 0;
389 g.control = 1;
390 g.controlMode = false;
391 A.push_back(g); // g1
392
393 g.type = 2;
394 g.target = 0;
395 g.controlMode = true;
396 g.control = 0;
397 A.push_back(g); // g2
398
399 g.type = 1;
400 g.target = 2;
401 g.controlMode = false;
402 g.control = 1;
403 A.push_back(g); // g3
404
405
406 g.type = 1;
407 g.target = 4;
408 g.control = 4;
409 g.controlMode = true;
410 B.push_back(g); // h1
411
412 g.type = 1;
413 g.target = 4;
414 g.controlMode = false;
415 g.control = 3;
416 B.push_back(g); // h2
417
418
419 std::cout << "Test 1: key-rate = " << ComputeFitness(A,B) << "\n\n";
420}
421
422
423//
424// evaluation code
425//
426
428{
429 state->getRegistry()->registerEntry("noise", (voidP) (new double(0.1)), ECF::DOUBLE, "symmetric channel noise level");
430 state->getRegistry()->registerEntry("CONDITIONING", (voidP) (new uint(1)), ECF::UINT, "conditioning");
431 state->getRegistry()->registerEntry("COMPUTE_ACTUAL_RATE", (voidP) (new uint(0)), ECF::UINT, "COMPUTE_ACTUAL_RATE");
432 state->getRegistry()->registerEntry("CHANNEL", (voidP) (new std::string("symmetric")), ECF::STRING, "symmetric testChannel1 testChannel2");
433}
434
435
437{
438 nWires = NUM_WIRES;
439
440 nWiresA = T + 1;
441 nWiresB = E - T;
442
443 nGatesA = 3;
444 nGatesB = 2;
445
446 state_ = state;
447
448 voidP sptr = state->getRegistry()->getEntry("noise");
449 double noise = *((double*)sptr.get());
450
451 sptr = state->getRegistry()->getEntry("CONDITIONING");
452 CONDITIONING = *((uint*)sptr.get()) ? true : false;
453
454 sptr = state->getRegistry()->getEntry("COMPUTE_ACTUAL_RATE");
455 COMPUTE_ACTUAL_RATE = *((uint*)sptr.get()) ? true : false;
456
457 sptr = state->getRegistry()->getEntry("CHANNEL");
458 std::string channel = *((std::string*)sptr.get());
459
460#ifndef WIN32
461 QKD::Stats stats;
462
463 if(channel == "testChannel1")
464 stats.testChannel1();
465 else if(channel == "testChannel2")
466 stats.testChannel2();
467 else
468 stats.symmetric(noise); // Test EA with different values between .01 and .5.
469
470 setupAttackVectors(stats);
471
472 testBB84();
473
474 std::cout << "Above value should be = " << stats.BB84Rate() << "\n";
475#endif
476
477 return true;
478}
479
480
481extern bool evaluateVerbose;
482
483FitnessP QuantumEvalOp::evaluate(IndividualP individual)
484{
485 FitnessP fitness (new FitnessMax);
486
487 IntGenotype::IntGenotype* genType = (IntGenotype::IntGenotype*) individual->getGenotype(0).get();
488 IntGenotype::IntGenotype* genTarget = (IntGenotype::IntGenotype*) individual->getGenotype(1).get();
489 BitString::BitString* bitstr = (BitString::BitString*) individual->getGenotype(2).get();
490 IntGenotype::IntGenotype* genControl = (IntGenotype::IntGenotype*) individual->getGenotype(3).get();
491 FloatingPoint::FloatingPoint* flpoint = (FloatingPoint::FloatingPoint*) individual->getGenotype(4).get();
492
493 std::list <QKD::Gate> A, B;
494 QKD::Gate gate;
495
496 for(uint i = 0; i < nGatesA; i++) {
497 // decode gate type, target, control mode
498 gate.type = genType->intValues[i] % QKD::nGateTypes;
499 gate.target = genTarget->intValues[i] % nWiresA;
500 gate.controlMode = bitstr->bits[i];
501 gate.control = genControl->intValues[i] % nWiresA;
502
503 if(gate.type == QKD::Rotation) {
504 gate.p = flpoint->realValue[i * 3 + 0];
505 gate.theta = flpoint->realValue[i * 3 + 1] * 2 * 3.1415926535;
506 gate.psi = flpoint->realValue[i * 3 + 2] * 2 * 3.1415926535;
507 }
508
509 A.push_back(gate);
510 }
511
512 for(uint i = nGatesA; i < (nGatesA + nGatesB); i++) {
513 // decode gate type, target, control mode
514 gate.type = genType->intValues[i] % QKD::nGateTypes;
515 gate.target = T + genTarget->intValues[i] % nWiresB;
516 gate.controlMode = bitstr->bits[i];
517 gate.control = T + genControl->intValues[i] % nWiresB;
518
519 if(gate.type == QKD::Rotation) {
520 gate.p = flpoint->realValue[i * 3 + 0];
521 gate.theta = flpoint->realValue[i * 3 + 1];
522 gate.psi = flpoint->realValue[i * 3 + 2];
523 }
524
525 B.push_back(gate);
526 }
527
528 fitness->setValue(ComputeFitness(A, B));
529
530 if(evaluateVerbose) {
531 stringstream ss;
532 ss << "Gates A:" << endl;
533 std::list<QKD::Gate>::iterator Iter;
534 for(Iter = A.begin(); Iter != A.end(); ++Iter) {
535 ss << "type " << Iter->type << " target " << Iter->target << " mode " << Iter->controlMode << " control: " << Iter->control;
536 if(Iter->type == QKD::Rotation)
537 ss << " p: " << Iter->p << " theta: " << Iter->theta << " psi: " << Iter->psi;
538 ss << endl;
539 }
540 ss << "Gates B:" << endl;
541 for(Iter = B.begin(); Iter != B.end(); ++Iter) {
542 ss << "type " << Iter->type << " target " << Iter->target << " mode " << Iter->controlMode << " control: " << Iter->control;
543 if(Iter->type == QKD::Rotation)
544 ss << " p: " << Iter->p << " theta: " << Iter->theta << " psi: " << Iter->psi;
545 ss << endl;
546 }
547 ECF_LOG(state_, 1, ss.str());
548 }
549
550 // return the smart pointer to new fitness
551 return fitness;
552}
BitString class - implements genotype as a series of bits.
Definition: BitString.h:24
Fitness for maximization problems.
Definition: FitnessMax.h:13
FloatingPoint class - implements genotype as a vector of floating point values.
Definition: FloatingPoint.h:39
void registerParameters(StateP)
Register evaluator parameters. Called before EvaluateOp::initialize method.
bool initialize(StateP)
Initialize the evaluator. Called before first evaluation occurs.
FitnessP evaluate(IndividualP individual)
Evaluate a single individual. Method must create and return a Fitness object.
std::vector< double > realValue
vector of floating point values