Skip to content

Commit e3b525d

Browse files
committed
add support for register-sized boolean computation + fix bugs
1 parent 6601103 commit e3b525d

File tree

5 files changed

+149
-41
lines changed

5 files changed

+149
-41
lines changed

data/deutsch_jozsa.hodl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ function deutsch_josza(super inputs) {
2626
# main function, i.e., body of program
2727

2828
function main() {
29-
# initialize superposition to 5 qubits
29+
# initialize superposition to 2 qubits
3030
# this should serve as the input for our function
31-
super stuff = 4;
31+
super stuff = 16;
3232

3333
# apply deutsch-josza function
3434
# if the function is balanced, i.e, half of all inputs return 1 and the other half return 0,

src/compiler/comops.h

Lines changed: 119 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,7 @@ void compile_instructions(Circuit& qc, vector<INSTRUCTION> instructions, SymbolT
200200
else if (type == "-=") {
201201
subtract_append(qc, *qvar1, *qvar2, instruction.get_controls());
202202

203-
}
204-
205-
203+
}
206204

207205
// check if our operation is relational (comparison)
208206
if (isCompOp(type)) {
@@ -221,21 +219,6 @@ void compile_instructions(Circuit& qc, vector<INSTRUCTION> instructions, SymbolT
221219

222220
qc.add_qregister(*ancilla);
223221

224-
225-
/*
226-
// reuse garbage register
227-
QuantumVariable* ancilla = Garbage::get_garbage()->get_garbage_register(num_qubits_ancilla);
228-
229-
if(ancilla == nullptr) {
230-
// create ancillary register
231-
table->ADD_ANCILLA_REGISTER(num_qubits_ancilla);
232-
// get ancillary register
233-
QuantumVariable* ancilla = table->search_qtable(table->GET_ANCILLA_REGISTER());
234-
}
235-
236-
*/
237-
238-
// add ancillary register to circuit
239222

240223
// compile equality operator
241224
if (type == "==") {
@@ -276,57 +259,134 @@ void compile_instructions(Circuit& qc, vector<INSTRUCTION> instructions, SymbolT
276259
}
277260

278261
// compile AND operator
262+
279263
else if (type == "&") {
264+
if (qvar1->get_num_qubits() > 1 || qvar2->get_num_qubits() > 1) {
265+
// n qubit OR gate, loop through all qubit pairs, eval or on ancilla, then X all of them, multi-controlled gate
266+
QuantumVariable* max_reg_and = qvar1;
267+
QuantumVariable* min_reg_and = qvar2;
268+
// get min and max qubits
269+
unsigned int max_qubits_and = qvar1->get_num_qubits();
270+
unsigned int min_qubits_and = qvar2->get_num_qubits();
271+
if(max_qubits_and < min_qubits_and) {
272+
swap(max_qubits_and, min_qubits_and);
273+
swap(max_reg_and, min_reg_and);
274+
}
275+
276+
// check if single qubit OR required or register-wide or
277+
QuantumVariable* ancilla_nbit_and = result_reg;
278+
279+
if(result_reg->get_num_qubits() == 1) {
280+
ancilla_nbit_and = alloc_ancilla(qc, max_qubits_and, table);
281+
282+
}
283+
284+
unsigned int diff = max_qubits_and - min_qubits_and;
285+
// and all common qubits
286+
for(int qbit_pair = diff; qbit_pair < max_qubits_and; qbit_pair++) {
287+
qc.ccx(max_reg_and->get_qreg(), qbit_pair, min_reg_and->get_qreg(), qbit_pair-diff, ancilla_nbit_and->get_qreg(), qbit_pair-diff);
288+
}
289+
290+
291+
// continue if not in if statement
292+
if(result_reg->get_num_qubits() > 1) continue;
293+
294+
295+
// ELSE multi-controlled NOT onto single qubit
296+
297+
qc.x(ancilla_nbit_and->get_qreg());
298+
qc.x(result_reg->get_qreg());
299+
300+
301+
QuantumVariable* ancilla_mcgate = alloc_ancilla(qc, ancilla_nbit_and->get_num_qubits()-1, table);
302+
multi_ctrl_gate(qc, &Circuit::cx, ancilla_nbit_and, result_reg, ancilla_mcgate);
303+
304+
305+
// uncomputation
306+
qc.x(ancilla_nbit_and->get_qreg());
307+
308+
for(int qbit_pair = max_qubits_and - min_qubits_and; qbit_pair < max_qubits_and; qbit_pair++) {
309+
qc.ccx(qvar1->get_qreg(), qbit_pair, qvar2->get_qreg(), qbit_pair, ancilla_nbit_and->get_qreg(), qbit_pair);
310+
}
311+
312+
Garbage::get_garbage()->add_garbage(ancilla_mcgate);
313+
Garbage::get_garbage()->add_garbage(ancilla_nbit_and);
314+
continue;
315+
}
316+
317+
318+
280319
qc.ccx(qvar1->get_qreg(), 0, qvar2->get_qreg(), 0, result_reg->get_qreg(), 0);
281-
}
320+
}
282321

283322
// compile OR operator
284323
else if (type == "|") {
285324
if(qvar1->get_num_qubits() > 1 || qvar2->get_num_qubits() > 1) {
286325
// n qubit OR gate, loop through all qubit pairs, eval or on ancilla, then X all of them, multi-controlled gate
287326

288327
QuantumVariable* max_reg_or = qvar1;
328+
QuantumVariable* min_reg_or = qvar2;
289329
// get min and max qubits
290330
unsigned int max_qubits_or = qvar1->get_num_qubits();
291331
unsigned int min_qubits_or = qvar2->get_num_qubits();
292332
if(max_qubits_or < min_qubits_or) {
293333
swap(max_qubits_or, min_qubits_or);
294-
max_reg_or = qvar2;
334+
swap(max_reg_or, min_reg_or);
295335
}
296336

297-
QuantumVariable* ancilla_nbit_or = alloc_ancilla(qc, max_qubits_or, table);
337+
// check if single qubit OR required or register-wide or
338+
QuantumVariable* ancilla_nbit_or = result_reg;
339+
340+
if(result_reg->get_num_qubits() == 1) {
341+
ancilla_nbit_or = alloc_ancilla(qc, max_qubits_or, table);
298342

343+
}
344+
345+
unsigned int diff = max_qubits_or - min_qubits_or;
299346
// OR common bits
300-
for(int qbit_pair = max_qubits_or - min_qubits_or; qbit_pair < max_qubits_or; qbit_pair++) {
301-
bitwise_or(qc, qvar1, qbit_pair, qvar2, qbit_pair, ancilla_nbit_or, qbit_pair);
347+
for(int qbit_pair = max_qubits_or - 1; qbit_pair >= diff; qbit_pair--) {
348+
bitwise_or(qc, max_reg_or, qbit_pair, min_reg_or, qbit_pair-diff, ancilla_nbit_or, qbit_pair);
302349
}
303350

304351
// OR uncommon bits (case where one register is larger than the other, then OR with zero is simply copying the bit value
305-
for(int qbit_cutoff = 0; qbit_cutoff < max_qubits_or - min_qubits_or; qbit_cutoff++) {
352+
for(int qbit_cutoff = 0; qbit_cutoff < diff; qbit_cutoff++) {
306353
qc.cx(max_reg_or->get_qreg(), qbit_cutoff, ancilla_nbit_or->get_qreg(), qbit_cutoff);
307354
}
308355

356+
357+
// continue if not in if statement
358+
if(result_reg->get_num_qubits() > 1) continue;
359+
360+
361+
// Following block only for if statement bool
362+
309363
// NOT entire register
310364
qc.x(ancilla_nbit_or->get_qreg());
311365

366+
// NOT result register
367+
qc.x(result_reg->get_qreg());
368+
312369
QuantumVariable* ancilla_mcgate = alloc_ancilla(qc, ancilla_nbit_or->get_num_qubits()-1, table);
313370
multi_ctrl_gate(qc, &Circuit::cx, ancilla_nbit_or, result_reg, ancilla_mcgate);
314371

315372
// Uncompute NOT
316373
qc.x(ancilla_nbit_or->get_qreg());
317374

318-
// Uncompute OR operation on ancilla
319-
375+
// Uncompute OR operation on ancilla - START
320376
// OR common bits
321-
for(int qbit_pair = max_qubits_or - min_qubits_or; qbit_pair < max_qubits_or; qbit_pair++) {
322-
bitwise_or(qc, qvar1, qbit_pair, qvar2, qbit_pair, ancilla_nbit_or, qbit_pair);
377+
for(int qbit_pair = max_qubits_or - 1; qbit_pair >= diff; qbit_pair--) {
378+
bitwise_or(qc, max_reg_or, qbit_pair, min_reg_or, qbit_pair-diff, ancilla_nbit_or, qbit_pair);
323379
}
324380

325381
// OR uncommon bits (case where one register is larger than the other, then OR with zero is simply copying the bit value
326-
for(int qbit_cutoff = 0; qbit_cutoff < max_qubits_or - min_qubits_or; qbit_cutoff++) {
382+
for(int qbit_cutoff = 0; qbit_cutoff < diff; qbit_cutoff++) {
327383
qc.cx(max_reg_or->get_qreg(), qbit_cutoff, ancilla_nbit_or->get_qreg(), qbit_cutoff);
328384
}
385+
// END UNCOMPUTATION
329386

387+
// Garbage::get_garbage()->add_garbage(ancilla_mcgate);
388+
// Garbage::get_garbage()->add_garbage(ancilla_nbit_or);
389+
330390
continue;
331391

332392
}
@@ -342,7 +402,6 @@ void compile_instructions(Circuit& qc, vector<INSTRUCTION> instructions, SymbolT
342402

343403
}
344404

345-
346405
}
347406

348407
else {
@@ -459,7 +518,37 @@ void compile_instructions(Circuit& qc, vector<INSTRUCTION> instructions, SymbolT
459518

460519
}
461520

521+
// compile range operator
522+
else if (type == ":") {
523+
// get number or right operand
524+
long long number = stoll(reg1);
525+
526+
// initialize number of qubits to zero
527+
int num_qubits = 0;
528+
529+
// check if range is a power-of-two
530+
// in other words, check if log2(number) is an element of the set consisting natural numbers
531+
if (reg0 == "0" && ceil(log2(number)) == floor(log2(number))) {
532+
// set number of qubits
533+
// the reason for this is to only create a superposition of the range desired.
534+
// e.g., a register of 5 qubits but we want a superposition of 0:4
535+
// Therefore, we have to only put the last 2 qubits into superposition
536+
int num_qubits = floor(log2(number));
537+
538+
// Apply HADAMARD Gate to each qubit we want to be in superpositon
539+
for (int i = (result_reg->get_num_qubits() - num_qubits); i < result_reg->get_num_qubits(); i++) {
540+
qc.h(result_reg->get_qreg(), i);
541+
}
462542

543+
}
544+
545+
// this should be implemented in later versions
546+
// to allow programmer to specify custom range, e.g. (1:100)
547+
else {
548+
int num_qubits = floor(log2(number)) + 1;
549+
//apply operation to procure such a state
550+
}
551+
}
463552
}
464553
}
465554

src/compiler/compiler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ int compile(int num_args, char** args) {
6868
//lexical analysis -> stored in vector of token-values
6969
vector<Pair> TokenValues = execute_lex(program_file).get_lex().dict_output;
7070

71-
/*for(int i = 0; i < TokenValues.size(); i++) {
71+
/* for(int i = 0; i < TokenValues.size(); i++) {
7272
cout << TokenValues[i].getToken() << endl;
7373
7474
7575
}
76-
*/
76+
*/
7777

7878

7979
// get circuit object

src/compiler/estimation_funcs.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <map>
77

88

9-
unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumVariable* dependency = nullptr, Node* expr_node = nullptr, bool is_right_child = false, map<string, string> parameter_map = {});
9+
unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumVariable* dependency = nullptr, Node* expr_node = nullptr, bool is_right_child = false, map<string, string> parameter_map = {}, bool is_if_statement=false);
1010

1111
std::map<string, string> number_to_word() {
1212
std::map<std::string, std::string> numbers;
@@ -246,6 +246,16 @@ unsigned int long long eval_id_resources(Node* node, string left, string right,
246246
return 0;
247247
}
248248

249+
if(node->getTValue() == "|") {
250+
return max(qvar1.get_num_qubits(), qvar2.get_num_qubits());
251+
252+
}
253+
254+
if(node->getTValue() == "&") {
255+
return min(qvar1.get_num_qubits(), qvar2.get_num_qubits());
256+
257+
}
258+
249259

250260
return 0;
251261
}
@@ -281,7 +291,6 @@ unsigned long long eval_id_num_resources(Node* node, string left, string right,
281291
estimate_subtraction_append(qvar, number);
282292
}
283293

284-
285294
return 0;
286295
}
287296

@@ -290,7 +299,7 @@ unsigned long long eval_id_num_resources(Node* node, string left, string right,
290299

291300
void eval_operator_child(Node* node, SymbolTable* table, int& total_resources, Node* expr_node, QuantumVariable* dependency, map<string, string> parameter_map = {}) {
292301
int value;
293-
//dependency = nullptr;
302+
//dependency = nullptr;
294303

295304
SyntaxTree left_tree(node->getLeftChild());
296305
SyntaxTree right_tree(node->getRightChild());
@@ -310,13 +319,22 @@ void eval_operator_child(Node* node, SymbolTable* table, int& total_resources, N
310319
total_resources += value;
311320
}
312321

322+
else if (node->getTValue() == "|") {
323+
value = max(eval_resources(&left_tree, table, dependency, expr_node, false, parameter_map), eval_resources(&right_tree, table, dependency, expr_node, true, parameter_map));
324+
total_resources += value;
325+
}
313326

327+
else if (node->getTValue() == "&") {
328+
value = min(eval_resources(&left_tree, table, dependency, expr_node, false, parameter_map), eval_resources(&right_tree, table, dependency, expr_node, true, parameter_map));
329+
total_resources += value;
330+
}
314331

315332
else if (node->getTValue() == ":") {
316333
total_resources += estimate_range(eval_resources(&right_tree, table, dependency, expr_node, false, parameter_map));
317334

318335
}
319336

337+
320338
table->search_qtable(node->get_result_register())->set_num_qubits(value);
321339

322340

src/compiler/resources.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
// THIS FUNCTION COMPUTES SIZE OF EACH REGISTER REQUIRED AND CREATES THEM
88

99

10-
unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumVariable* dependency, Node* expr_node, bool is_right_child, map<string, string> parameter_map) {
10+
11+
unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumVariable* dependency, Node* expr_node, bool is_right_child, map<string, string> parameter_map, bool is_if_statement) {
1112
// Root node for expression parsing
1213
//cout << tree;
1314
Node* node = tree->getRoot();
@@ -162,7 +163,7 @@ unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumV
162163

163164

164165
//case for operators
165-
else if (node->getTToken() == "OPERATOR") {
166+
else if (node->getTToken() == "OPERATOR" || (node->getTToken() == "BOOL_EXPR" && !is_if_statement)) {
166167
// get left value
167168
string left = node->getLeftChild()->getTValue();
168169

@@ -350,7 +351,7 @@ unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumV
350351
SyntaxTree tree_left(node->getLeftChild());
351352

352353
// evaluate resources for condition
353-
eval_resources(&tree_left, table, nullptr, nullptr, false, parameter_map);
354+
eval_resources(&tree_left, table, nullptr, nullptr, false, parameter_map, true);
354355
// add CMP register
355356
table->ADD_CMP_REGISTER();
356357

@@ -370,7 +371,7 @@ unsigned long long eval_resources(SyntaxTree* tree, SymbolTable* table, QuantumV
370371
// evaluate resources for left and right child
371372
eval_resources(&tree_left, table, nullptr, nullptr, false, parameter_map);
372373
eval_resources(&tree_right, table, nullptr, nullptr, false, parameter_map);
373-
374+
374375
// create a CMP register to store boolean result
375376
table->ADD_CMP_REGISTER();
376377

0 commit comments

Comments
 (0)