From: miha-q <> Date: Mon, 18 Mar 2024 22:14:19 +0000 (-0400) Subject: Mon Mar 18 06:14:19 PM EDT 2024 X-Git-Url: http://www.foleosoft.com/?a=commitdiff_plain;h=8feea5907c00d412eb6a9dc55a919113e9416265;p=QAnsel.git Mon Mar 18 06:14:19 PM EDT 2024 --- diff --git a/bin/QAnsel b/bin/QAnsel index df10cea..3476638 100755 Binary files a/bin/QAnsel and b/bin/QAnsel differ diff --git a/examples/hiddenvariable.txt b/examples/hiddenvariable.txt deleted file mode 100644 index 747d512..0000000 --- a/examples/hiddenvariable.txt +++ /dev/null @@ -1,24 +0,0 @@ -qreg q[1]; -creg c[4]; - -hvar 12.34; -h q[0]; measure q[0] -> c[0]; -h q[0]; measure q[0] -> c[1]; -h q[0]; measure q[0] -> c[2]; -h q[0]; measure q[0] -> c[3]; -print c; - -rand; -h q[0]; measure q[0] -> c[0]; -h q[0]; measure q[0] -> c[1]; -h q[0]; measure q[0] -> c[2]; -h q[0]; measure q[0] -> c[3]; -print c; - -hvar 43.21; -h q[0]; measure q[0] -> c[0]; -h q[0]; measure q[0] -> c[1]; -h q[0]; measure q[0] -> c[2]; -h q[0]; measure q[0] -> c[3]; -print c; - diff --git a/src/bytecode.c b/src/bytecode.c index ac53737..6db18a8 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -26,7 +26,6 @@ const char* qansel_instruction_to_string(unsigned char instr) case QANSEL_INSTRUCTION_CCX: return "QANSEL_INSTRUCTION_CCX"; case QANSEL_INSTRUCTION_CSWAP: return "QANSEL_INSTRUCTION_CSWAP"; case QANSEL_INSTRUCTION_MEASURE: return "QANSEL_INSTRUCTION_MEASURE"; - case QANSEL_INSTRUCTION_SAMPLE: return "QANSEL_INSTRUCTION_SAMPLE"; case QANSEL_INSTRUCTION_DENSITY: return "QANSEL_INSTRUCTION_DENSITY"; case QANSEL_INSTRUCTION_BORN: return "QANSEL_INSTRUCTION_BORN"; case QANSEL_INSTRUCTION_IF_E: return "QANSEL_INSTRUCTION_JUMP_E"; @@ -35,10 +34,8 @@ const char* qansel_instruction_to_string(unsigned char instr) case QANSEL_INSTRUCTION_IF_GE: return "QANSEL_INSTRUCTION_JUMP_GE"; case QANSEL_INSTRUCTION_IF_L: return "QANSEL_INSTRUCTION_JUMP_L"; case QANSEL_INSTRUCTION_IF_LE: return "QANSEL_INSTRUCTION_JUMP_LE"; - case QANSEL_INSTRUCTION_RAND: return "QANSEL_INSTRUCTION_RAND"; - case QANSEL_INSTRUCTION_HVAR: return "QANSEL_INSTRUCTION_HVAR"; - case QANSEL_INSTRUCTION_RESET: return "QANSEL_INSTRUCTION_RESET"; case QANSEL_INSTRUCTION_PRINT: return "QANSEL_INSTRUCTION_PRINT"; + case QANSEL_INSTRUCTION_RESET: return "QANSEL_INSTRUCTION_RESET"; case QANSEL_INSTRUCTION_BARRIER: return "QANSEL_INSTRUCTION_BARRIER"; case QANSEL_INSTRUCTION_EXIT: return "QANSEL_INSTRUCTION_EXIT"; } @@ -60,14 +57,20 @@ float qansel_rand_h() { return ((float)rand()) / ((float)RAND_MAX); } -float qansel_rand_t() +float qansel_rand_t(QAnselContext* ctx) { - if (QANSEL_RANDOM_FILE) + if (ctx->hardware_rng != QANSEL_HARDWARE_NONE) { unsigned int num = 0; for (unsigned char i = 0; i < 4; i++) { - num = (num << 8) | fgetc(QANSEL_RANDOM_FILE); + unsigned char r = 0; + switch (ctx->hardware_rng) + { + case QANSEL_HARDWARE_TRUERNG: r = fgetc(ctx->random_file); break; + case QANSEL_HARDWARE_RDSEED: r = qansel_hardware_rand(); break; + } + num = (num << 8) | r; } return ((float)num) / ((float)UINT32_MAX); } @@ -77,11 +80,6 @@ float qansel_rand_t() } } -float qansel_rand() -{ - return QANSEL_HIDDEN_VARIABLE ? qansel_rand_h() : qansel_rand_t(); -} - void qansel_cnot(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB) { if (bitA >= qubitCount || bitB >= qubitCount) return; @@ -264,6 +262,7 @@ void qansel_instruction_queue void qansel_instruction ( + QAnselContext* ctx, cpx_mtx_t* stateVector, int qubitCount, unsigned char instr, @@ -381,11 +380,11 @@ void qansel_instruction //us2 = get_time(); //printf("\tTranspose: %lu\n", us2 - us1); #else - if ((QANSEL_MODE & QANSEL_MODE_METAL) && !(QANSEL_MODE & QANSEL_MODE_THREADED) && tmp.cols >= 64) + if (((ctx->optimization_level) & QANSEL_MODE_METAL) && !((ctx->optimization_level) & QANSEL_MODE_THREADED) && tmp.cols >= 64) { cpx_mtx_knk_metal_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); } - else if ((QANSEL_MODE & QANSEL_MODE_THREADED) && tmp.cols >= 64) + else if (((ctx->optimization_level) & QANSEL_MODE_THREADED) && tmp.cols >= 64) { cpx_mtx_knk_threads_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); } @@ -419,11 +418,11 @@ void qansel_instruction us2 = get_time(); printf("\tBare: %lu\n", us2 - us1); #else - if ((QANSEL_MODE & QANSEL_MODE_METAL) && tmp.cols >= 64) + if (((ctx->optimization_level) & QANSEL_MODE_METAL) && tmp.cols >= 64) { cpx_mtx_dot_metal(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); } - else if ((QANSEL_MODE & QANSEL_MODE_THREADED) && tmp.cols >= 64) + else if (((ctx->optimization_level) & QANSEL_MODE_THREADED) && tmp.cols >= 64) { cpx_mtx_dot_threads(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); } @@ -438,7 +437,7 @@ void qansel_instruction if (needToFreeGate) free(gate_ptr); } -unsigned char qansel_measure(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char qubit) +unsigned char qansel_measure(QAnselContext* ctx, cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char qubit) { unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); cpx_t n; @@ -450,7 +449,7 @@ unsigned char qansel_measure(cpx_mtx_t* stateVector, unsigned char qubitCount, u if (bit == 0) prob0 += cpx_magsqr(&n); } - float r = qansel_rand(); + float r = (ctx->hidden_variable) ? qansel_rand_h() : qansel_rand_t(ctx); unsigned char newBit = r < prob0 ? 0 : 1; float probTot = 0; for (unsigned int i = 0; i < qubitCountPow2; i++) @@ -511,7 +510,6 @@ int qansel_get_instruction_bitmax(unsigned char* ptr, int offset, int* bitmax, i if (a0 > QANSEL_QBOUND_UPPER && a0 != QANSEL_ALL_QUANTUM) return 0; if (a0 != QANSEL_ALL_QUANTUM) *qbitmax = a0 + 1; return 1; - case QANSEL_INSTRUCTION_SAMPLE: case QANSEL_INSTRUCTION_IF_E: case QANSEL_INSTRUCTION_IF_NE: case QANSEL_INSTRUCTION_IF_G: @@ -563,23 +561,53 @@ int qansel_get_instruction_bitmax(unsigned char* ptr, int offset, int* bitmax, i *qbitmax = a0 + 1; *bitmax = (a1 - QANSEL_CBOUND_LOWER) + 1; return 1; - case QANSEL_INSTRUCTION_RAND: - case QANSEL_INSTRUCTION_HVAR: case QANSEL_INSTRUCTION_EXIT: return 1; } return 0; } -int qansel_get_barrier(int** q, int qubitCount, int bitCount, unsigned char* binary, int pos) +int qansel_get_instruction_size(unsigned char instr) { - - unsigned char instr = binary[pos]; switch (instr) { - case QANSEL_INSTRUCTION_SAMPLE: - case QANSEL_INSTRUCTION_RAND: - case QANSEL_INSTRUCTION_HVAR: + case QANSEL_INSTRUCTION_X: return 1 + 1; + case QANSEL_INSTRUCTION_Y: return 1 + 1; + case QANSEL_INSTRUCTION_Z: return 1 + 1; + case QANSEL_INSTRUCTION_H: return 1 + 1; + case QANSEL_INSTRUCTION_S: return 1 + 1; + case QANSEL_INSTRUCTION_T: return 1 + 1; + case QANSEL_INSTRUCTION_RX: return 1 + 1 + sizeof(float); + case QANSEL_INSTRUCTION_RY: return 1 + 1 + sizeof(float); + case QANSEL_INSTRUCTION_RZ: return 1 + 1 + sizeof(float); + case QANSEL_INSTRUCTION_U1: return 1 + 1 + sizeof(float); + case QANSEL_INSTRUCTION_U2: return 1 + 1 + sizeof(float) * 2; + case QANSEL_INSTRUCTION_U3: return 1 + 1 + sizeof(float) * 3; + case QANSEL_INSTRUCTION_CX: return 1 + 2; + case QANSEL_INSTRUCTION_SWAP: return 1 + 2; + case QANSEL_INSTRUCTION_CCX: return 1 + 3; + case QANSEL_INSTRUCTION_CSWAP: return 1 + 3; + case QANSEL_INSTRUCTION_MEASURE: return 1 + 2; + case QANSEL_INSTRUCTION_DENSITY: return 1 + 1; + case QANSEL_INSTRUCTION_BORN: return 1 + 1; + case QANSEL_INSTRUCTION_IF_E: return 1 + 1 + sizeof(unsigned short); + case QANSEL_INSTRUCTION_IF_NE: return 1 + 1 + sizeof(unsigned short); + case QANSEL_INSTRUCTION_IF_G: return 1 + 1 + sizeof(unsigned short); + case QANSEL_INSTRUCTION_IF_GE: return 1 + 1 + sizeof(unsigned short); + case QANSEL_INSTRUCTION_IF_L: return 1 + 1 + sizeof(unsigned short); + case QANSEL_INSTRUCTION_IF_LE: return 1 + 1 + sizeof(unsigned short); + case QANSEL_INSTRUCTION_RESET: return 1 + 1; + case QANSEL_INSTRUCTION_PRINT: return 1 + 1; + case QANSEL_INSTRUCTION_BARRIER: return 1 + 1; + case QANSEL_INSTRUCTION_EXIT: return 1; + } + return 0; +} + +void qansel_get_barrier(QBytecode** qbc, int idx) +{ + switch ((*qbc)[idx].op) + { case QANSEL_INSTRUCTION_EXIT: case QANSEL_INSTRUCTION_IF_E: case QANSEL_INSTRUCTION_IF_NE: @@ -587,8 +615,8 @@ int qansel_get_barrier(int** q, int qubitCount, int bitCount, unsigned char* bin case QANSEL_INSTRUCTION_IF_GE: case QANSEL_INSTRUCTION_IF_L: case QANSEL_INSTRUCTION_IF_LE: - *q = NULL; - return 0; + (*qbc)[idx].barrier_width = 0; + return; case QANSEL_INSTRUCTION_X: case QANSEL_INSTRUCTION_Y: case QANSEL_INSTRUCTION_Z: @@ -601,122 +629,55 @@ int qansel_get_barrier(int** q, int qubitCount, int bitCount, unsigned char* bin case QANSEL_INSTRUCTION_U1: case QANSEL_INSTRUCTION_U2: case QANSEL_INSTRUCTION_U3: - //only barrier single-qubit instructions if - // they are nexted in an if statement - if (pos >= (1 + sizeof(unsigned short))) - { - switch (binary[pos - (1 + sizeof(unsigned short))]) - { - case QANSEL_INSTRUCTION_IF_E: - case QANSEL_INSTRUCTION_IF_NE: - case QANSEL_INSTRUCTION_IF_G: - case QANSEL_INSTRUCTION_IF_GE: - case QANSEL_INSTRUCTION_IF_L: - case QANSEL_INSTRUCTION_IF_LE: - *q = malloc(1); - (*q)[0] = binary[pos + 1] + QANSEL_QBOUND_LOWER; - return 1; - } - } - *q = NULL; - return 0; + (*qbc)[idx].barrier_width = 1; + (*qbc)[idx].barrier[0] = (*qbc)[idx].bytes[1]; + return; case QANSEL_INSTRUCTION_MEASURE: case QANSEL_INSTRUCTION_DENSITY: - *q = malloc(2); - (*q)[0] = binary[pos + 1] + QANSEL_QBOUND_LOWER; - (*q)[1] = binary[pos + 2] + QANSEL_CBOUND_LOWER; - return 1; + (*qbc)[idx].barrier_width = 2; + (*qbc)[idx].barrier[0] = (*qbc)[idx].bytes[1]; + (*qbc)[idx].barrier[1] = (*qbc)[idx].bytes[2]; + return; case QANSEL_INSTRUCTION_BORN: case QANSEL_INSTRUCTION_BARRIER: case QANSEL_INSTRUCTION_PRINT: case QANSEL_INSTRUCTION_RESET: - switch (binary[pos + 1]) + switch ((*qbc)[idx].bytes[1]) { case QANSEL_ALL: - *q = malloc(sizeof(int) * (qubitCount + bitCount)); - for (int i = 0; i < qubitCount; i++) - { - (*q)[i] = i + QANSEL_QBOUND_LOWER; - } - for (int i = 0; i < bitCount; i++) - { - (*q)[i] = i + QANSEL_CBOUND_LOWER; - } - return qubitCount + bitCount; + (*qbc)[idx].barrier_width = QANSEL_QUBITS_MAX * 2; + for (int i = 0; i < QANSEL_QUBITS_MAX; i++) (*qbc)[idx].barrier[i] = i; + for (int i = 0; i < QANSEL_QUBITS_MAX; i++) (*qbc)[idx].barrier[i] = i + QANSEL_CBOUND_LOWER; + return; case QANSEL_ALL_QUANTUM: - *q = malloc(sizeof(int) * qubitCount); - for (int i = 0; i < qubitCount; i++) - { - (*q)[i] = i + QANSEL_QBOUND_LOWER; - } - return qubitCount; + (*qbc)[idx].barrier_width = QANSEL_QUBITS_MAX; + for (int i = 0; i < QANSEL_QUBITS_MAX; i++) (*qbc)[idx].barrier[i] = i; + return; case QANSEL_ALL_CLASSIC: - *q = malloc(sizeof(int) * bitCount); - for (int i = 0; i < bitCount; i++) - { - (*q)[i] = i + QANSEL_CBOUND_LOWER; - } - return bitCount; + (*qbc)[idx].barrier_width = QANSEL_QUBITS_MAX; + for (int i = 0; i < QANSEL_QUBITS_MAX; i++) (*qbc)[idx].barrier[i] = i + QANSEL_CBOUND_LOWER; + return; default: - *q = malloc(1); - (*q)[0] = binary[pos + 1]; - return 1; + (*qbc)[idx].barrier_width = 1; + (*qbc)[idx].barrier[0] = (*qbc)[idx].bytes[1]; + return; } case QANSEL_INSTRUCTION_CX: case QANSEL_INSTRUCTION_SWAP: - *q = malloc(2); - (*q)[0] = binary[pos + 1] + QANSEL_QBOUND_LOWER; - (*q)[1] = binary[pos + 2] + QANSEL_QBOUND_LOWER; - return 2; + (*qbc)[idx].barrier_width = 2; + (*qbc)[idx].barrier[0] = (*qbc)[idx].bytes[1]; + (*qbc)[idx].barrier[1] = (*qbc)[idx].bytes[2]; + return; case QANSEL_INSTRUCTION_CCX: case QANSEL_INSTRUCTION_CSWAP: - *q = malloc(3); - (*q)[0] = binary[pos + 1] + QANSEL_QBOUND_LOWER; - (*q)[1] = binary[pos + 2] + QANSEL_QBOUND_LOWER; - (*q)[2] = binary[pos + 3] + QANSEL_QBOUND_LOWER; - return 3; - } - fprintf(stderr, "QAnsel (%04X): Unknown error in barrier analysis.\n", pos); -} - -int qansel_get_instruction_size(unsigned char instr) -{ - switch (instr) - { - case QANSEL_INSTRUCTION_X: return 1 + 1; - case QANSEL_INSTRUCTION_Y: return 1 + 1; - case QANSEL_INSTRUCTION_Z: return 1 + 1; - case QANSEL_INSTRUCTION_H: return 1 + 1; - case QANSEL_INSTRUCTION_S: return 1 + 1; - case QANSEL_INSTRUCTION_T: return 1 + 1; - case QANSEL_INSTRUCTION_RX: return 1 + 1 + sizeof(float); - case QANSEL_INSTRUCTION_RY: return 1 + 1 + sizeof(float); - case QANSEL_INSTRUCTION_RZ: return 1 + 1 + sizeof(float); - case QANSEL_INSTRUCTION_U1: return 1 + 1 + sizeof(float); - case QANSEL_INSTRUCTION_U2: return 1 + 1 + sizeof(float) * 2; - case QANSEL_INSTRUCTION_U3: return 1 + 1 + sizeof(float) * 3; - case QANSEL_INSTRUCTION_CX: return 1 + 2; - case QANSEL_INSTRUCTION_SWAP: return 1 + 2; - case QANSEL_INSTRUCTION_CCX: return 1 + 3; - case QANSEL_INSTRUCTION_CSWAP: return 1 + 3; - case QANSEL_INSTRUCTION_MEASURE: return 1 + 2; - case QANSEL_INSTRUCTION_SAMPLE: return 1 + 1; - case QANSEL_INSTRUCTION_DENSITY: return 1 + 1; - case QANSEL_INSTRUCTION_BORN: return 1 + 1; - case QANSEL_INSTRUCTION_IF_E: return 1 + 1 + sizeof(unsigned short); - case QANSEL_INSTRUCTION_IF_NE: return 1 + 1 + sizeof(unsigned short); - case QANSEL_INSTRUCTION_IF_G: return 1 + 1 + sizeof(unsigned short); - case QANSEL_INSTRUCTION_IF_GE: return 1 + 1 + sizeof(unsigned short); - case QANSEL_INSTRUCTION_IF_L: return 1 + 1 + sizeof(unsigned short); - case QANSEL_INSTRUCTION_IF_LE: return 1 + 1 + sizeof(unsigned short); - case QANSEL_INSTRUCTION_RAND: return 1; - case QANSEL_INSTRUCTION_HVAR: return 1 + sizeof(float); - case QANSEL_INSTRUCTION_RESET: return 1 + 1; - case QANSEL_INSTRUCTION_PRINT: return 1 + 1; - case QANSEL_INSTRUCTION_BARRIER: return 1 + 1; - case QANSEL_INSTRUCTION_EXIT: return 1; + (*qbc)[idx].barrier_width = 3; + (*qbc)[idx].barrier[0] = (*qbc)[idx].bytes[1]; + (*qbc)[idx].barrier[1] = (*qbc)[idx].bytes[2]; + (*qbc)[idx].barrier[2] = (*qbc)[idx].bytes[3]; + return; } - return 0; + fprintf(stderr, "QAnsel (#%i): Unknown error in barrier analysis.\n", idx); + exit(1); } void qansel_born(cpx_mtx_t* stateVector, int PC, int qubitCount, unsigned char q0) @@ -870,7 +831,7 @@ int qansel_get_int(unsigned char* program, int offset) return ret; } -void qansel_reset(cpx_mtx_t* stateVector, unsigned char* bitVector, int qubitCount, int bitCount, unsigned char q0) +void qansel_reset(QAnselContext* ctx, cpx_mtx_t* stateVector, unsigned char* bitVector, int qubitCount, int bitCount, unsigned char q0) { unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); if (q0 == QANSEL_ALL) @@ -902,10 +863,10 @@ void qansel_reset(cpx_mtx_t* stateVector, unsigned char* bitVector, int qubitCou } else if (q0 <= QANSEL_QBOUND_UPPER) { - unsigned char bit = qansel_measure(stateVector, qubitCount, q0); + unsigned char bit = qansel_measure(ctx, stateVector, qubitCount, q0); if (bit) { - qansel_instruction(stateVector, qubitCount, QANSEL_INSTRUCTION_X, q0, 0, 0, 0, NULL); + qansel_instruction(ctx, stateVector, qubitCount, QANSEL_INSTRUCTION_X, q0, 0, 0, 0, NULL); } } else if (q0 >= QANSEL_CBOUND_LOWER && q0 <= QANSEL_CBOUND_UPPER) @@ -939,27 +900,62 @@ unsigned char qansel_compare(unsigned char* bitVector, int bitCount, int PC, uns return ret; } -int qansel_crawl(unsigned char* program, int programSize, int* qubitCount, int* bitCount, int* sample) +//computes program efficiency +// points are awarded for how long strings of single qubit +// instructions are +int qansel_efficiency(QBytecode* program, int programSize, int head) { - if (QANSEL_VERBOSE) printf("Crawling program . . .\n"); + int score = 0; + int tmpscore = 0; + int idx = head; + + for (int i = 0; i < programSize; i++) + { + switch (program[idx].op) + { + case QANSEL_INSTRUCTION_X: + case QANSEL_INSTRUCTION_Y: + case QANSEL_INSTRUCTION_Z: + case QANSEL_INSTRUCTION_H: + case QANSEL_INSTRUCTION_S: + case QANSEL_INSTRUCTION_T: + case QANSEL_INSTRUCTION_RX: + case QANSEL_INSTRUCTION_RY: + case QANSEL_INSTRUCTION_RZ: + case QANSEL_INSTRUCTION_U1: + case QANSEL_INSTRUCTION_U2: + case QANSEL_INSTRUCTION_U3: + switch (tmpscore) + { + case 0: tmpscore = 1; break; + default: tmpscore *= 2; + } + break; + case QANSEL_INSTRUCTION_IF_E: + case QANSEL_INSTRUCTION_IF_NE: + case QANSEL_INSTRUCTION_IF_G: + case QANSEL_INSTRUCTION_IF_GE: + case QANSEL_INSTRUCTION_IF_L: + case QANSEL_INSTRUCTION_IF_LE: + break; + default: + if (tmpscore > 1) score += tmpscore; + tmpscore = 0; + } + idx = program[idx].next; + } + return score; +} + +int qansel_crawl(QAnselContext* ctx, unsigned char* program, int programSize, int* qubitCount, int* bitCount) +{ + if (ctx->verbose) printf("Crawling program . . .\n"); int PC = 0; *qubitCount = 0; *bitCount = 0; - *sample = QANSEL_ALL; while (PC < programSize) { int next = qansel_get_instruction_size(program[PC]); - if (program[PC] == QANSEL_INSTRUCTION_SAMPLE) - { - if ((program[PC + 1] < QANSEL_CBOUND_LOWER || program[PC + 1] > QANSEL_CBOUND_UPPER) && program[PC + 1] != QANSEL_ALL_CLASSIC) - { - if (QANSEL_VERBOSE) fprintf(stderr, "QAnsel (%04X): Invalid index.\n", PC); - } - else - { - *sample = program[PC + 1] - QANSEL_CBOUND_LOWER; - } - } if (next == 0) { printf("QAnsel (%04X): Invalid instruction 0x%02x.\n", PC, program[PC]); @@ -976,14 +972,249 @@ int qansel_crawl(unsigned char* program, int programSize, int* qubitCount, int* if (qbitmax > *qubitCount) *qubitCount = qbitmax; PC += next; } - if (QANSEL_VERBOSE) printf("Quantum bits allocated: %i\n", *qubitCount); - if (QANSEL_VERBOSE) printf("Classical bits allocated: %i\n", *bitCount); + if (ctx->verbose) printf("Quantum bits allocated: %i\n", *qubitCount); + if (ctx->verbose) printf("Classical bits allocated: %i\n", *bitCount); + return 1; } -void qansel_run(unsigned char* program, int programSize, int qubitCount, int bitCount, unsigned char* outputBitVector) +void qansel_reorder(QAnselContext* ctx, unsigned char* program, int programSize) { - int useQueue = (QANSEL_MODE & QANSEL_MODE_QUEUE) ? 1 : 0; + if (ctx->verbose) printf("Reordering . . .\n"); + + //break out program for easier manipulation + QBytecode* ramInstr = malloc(0); + int ramInstrLen = 0; + int copyifop = 0; + unsigned char ifop[16]; + int PC = 0; + + while (PC < programSize) + { + int next = qansel_get_instruction_size(program[PC]); + switch (program[PC]) + { + case QANSEL_INSTRUCTION_IF_E: + case QANSEL_INSTRUCTION_IF_NE: + case QANSEL_INSTRUCTION_IF_G: + case QANSEL_INSTRUCTION_IF_GE: + case QANSEL_INSTRUCTION_IF_L: + case QANSEL_INSTRUCTION_IF_LE: + memcpy(ifop, program + PC, next); + copyifop = 1; + PC += next; + continue; + } + ramInstr = realloc(ramInstr, sizeof(QBytecode) * (ramInstrLen + 1)); + ramInstr[ramInstrLen].size = next; + memcpy(ramInstr[ramInstrLen].bytes, program + PC, next); + ramInstr[ramInstrLen].op = program[PC]; + ramInstr[ramInstrLen].use_ifop = copyifop; + if (copyifop) + { + memcpy(ramInstr[ramInstrLen].ifop, ifop, sizeof(ifop)); + copyifop = 0; + } + ramInstrLen++; + PC += next; + } + for (int i = 0; i < ramInstrLen; i++) + { + if (i == 0) + { + ramInstr[0].prev = -1; + ramInstr[0].next = ramInstrLen > 1 ? 1 : -1; + } + else if (i == ramInstrLen - 1) + { + ramInstr[ramInstrLen - 1].prev = i - 1; + ramInstr[ramInstrLen - 1].next = -1; + } + else + { + ramInstr[i].prev = i - 1; + ramInstr[i].next = i + 1; + } + //we can only rearrange single-qubit instructions + // so treat other instructions as pre-checked + switch (ramInstr[i].op) + { + case QANSEL_INSTRUCTION_X: + case QANSEL_INSTRUCTION_Y: + case QANSEL_INSTRUCTION_Z: + case QANSEL_INSTRUCTION_H: + case QANSEL_INSTRUCTION_S: + case QANSEL_INSTRUCTION_T: + case QANSEL_INSTRUCTION_RX: + case QANSEL_INSTRUCTION_RY: + case QANSEL_INSTRUCTION_RZ: + case QANSEL_INSTRUCTION_U1: + case QANSEL_INSTRUCTION_U2: + case QANSEL_INSTRUCTION_U3: + ramInstr[i].checked = 0; + break; + default: ramInstr[i].checked = 1; + } + } + + for (int i = 0; i < ramInstrLen; i++) + { + qansel_get_barrier(&ramInstr, i); + } + + QBytecode* reordered[2]; + reordered[0] = malloc(ramInstrLen * sizeof(QBytecode)); + reordered[1] = malloc(ramInstrLen * sizeof(QBytecode)); + memcpy(reordered[0], ramInstr, ramInstrLen * sizeof(QBytecode)); + memcpy(reordered[1], ramInstr, ramInstrLen * sizeof(QBytecode)); + + int efficiency = qansel_efficiency(ramInstr, ramInstrLen, 0); + int head[2]; + head[0] = 0; + head[1] = 0; + for (int reorid = 0; reorid < 2; reorid++) + { + while (1) + { + //find the next unchecked instruction + int found = -1; + int idx = head[reorid]; + for (int i = 0; i < ramInstrLen; i++) + { + if (reordered[reorid][idx].checked == 0) + { + found = idx; + break; + } + idx = reordered[reorid][idx].next; + } + if (found == -1) break; + //check if it can be moved up + reordered[reorid][found].checked = 1; + int blocked = 0; + idx = reordered[reorid][idx].prev; + while (idx != -1) + { + for (int i = 0; i < reordered[reorid][idx].barrier_width; i++) + { + //verify no classical bit barrier + if (reordered[reorid][found].use_ifop) + { + switch (reordered[reorid][found].ifop[1]) + { + case QANSEL_ALL_CLASSIC: + case QANSEL_ALL: + blocked = 1; + break; + default: + if (reordered[reorid][found].ifop[1] == reordered[reorid][idx].barrier[i]) + blocked = 1; + } + if (blocked) break; + } + //verify no quantum bit barrier + if (reordered[reorid][found].bytes[1] == reordered[reorid][idx].barrier[i]) + { + blocked = 1; + break; + } + } + if (blocked) break; + idx = reordered[reorid][idx].prev; + } + if (reordered[reorid][found].prev != idx) + { + QBytecode* tmpbc = malloc(ramInstrLen * sizeof(QBytecode)); + memcpy(tmpbc, reordered[reorid], ramInstrLen * sizeof(QBytecode)); + reordered[reorid][ reordered[reorid][found].prev ].next = reordered[reorid][found].next; + if (reordered[reorid][found].next != -1) + { + reordered[reorid][ reordered[reorid][found].next ].prev = reordered[reorid][found].prev; + } + + if (idx == -1) + { + reordered[reorid][head[reorid]].prev = found; + reordered[reorid][found].next = head[reorid]; + reordered[reorid][found].prev = -1; + head[reorid] = found; + } + else + { + reordered[reorid][ reordered[reorid][idx].next ].prev = found; + reordered[reorid][found].next = reordered[reorid][idx].next; + reordered[reorid][found].prev = idx; + reordered[reorid][idx].next = found; + } + if (reorid == 1) + { + int tmpeff = qansel_efficiency(reordered[reorid], ramInstrLen, head[reorid]); + if (tmpeff >= efficiency) + { + efficiency = tmpeff; + } + else + { + memcpy(reordered[reorid], tmpbc, ramInstrLen * sizeof(QBytecode)); + } + } + free(tmpbc); + } + } + } + + efficiency = qansel_efficiency(ramInstr, ramInstrLen, 0); + int best = -1; + int besti = -1; + for (int i = 0; i < 2; i++) + { + int tmpeff = qansel_efficiency(reordered[i], ramInstrLen, head[i]); + if (tmpeff > best) + { + besti = i; + best = tmpeff; + } + } + if (best > efficiency) + { + memcpy(ramInstr, reordered[besti], ramInstrLen * sizeof(QBytecode)); + } + for (int i = 0; i < 2; i++) + { + free(reordered[i]); + } + + int copyloc = 0; + for (int i = 0; i < ramInstrLen; i++) + { + int next; + if (ramInstr[i].use_ifop) + { + next = qansel_get_instruction_size(ramInstr[i].ifop[0]); + memcpy(program + copyloc, ramInstr[i].ifop, next); + copyloc += next; + } + next = qansel_get_instruction_size(ramInstr[i].op); + memcpy(program + copyloc, ramInstr[i].bytes, next); + copyloc += next; + } + + if (ctx->verbose) + { + if (best > efficiency) + { + printf("Efficiency score increased from %i to %i.\n", efficiency, best); + } + else + { + printf("Could not increase efficiency.\n"); + } + } +} + +void qansel_run(QAnselContext* ctx, unsigned char* program, int programSize, int qubitCount, int bitCount, unsigned char* outputBitVector) +{ + int useQueue = ((ctx->optimization_level) & QANSEL_MODE_QUEUE) ? 1 : 0; int PC = 0; unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); unsigned char bitVector[bitCount]; @@ -1003,7 +1234,7 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit queueVector[i].cols = 2; } } - if (QANSEL_USE_DISPLAY) { QANSEL_USE_DISPLAY = display(&stateVector, qubitCount, QANSEL_USE_DISPLAY); } + if (ctx->display_delay) { ctx->display_delay = display(&stateVector, qubitCount, ctx->display_delay); } unsigned char skip = 0, a0 = 0, a1 = 0, a2 = 0; unsigned char flags = 0; unsigned short tmp = 0; @@ -1051,12 +1282,9 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit case QANSEL_INSTRUCTION_IF_GE: case QANSEL_INSTRUCTION_IF_L: case QANSEL_INSTRUCTION_IF_LE: - case QANSEL_INSTRUCTION_SAMPLE: - case QANSEL_INSTRUCTION_HVAR: - case QANSEL_INSTRUCTION_RAND: break; default: - qansel_instruction(&stateVector, qubitCount, instr, 0, 0, 0, 0, &queueVector); + qansel_instruction(ctx, &stateVector, qubitCount, instr, 0, 0, 0, 0, &queueVector); for (int i = 0; i < qubitCount; i++) { memcpy(queueVector[i].ptr, Identity, sizeof(Identity)); @@ -1116,7 +1344,7 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit } a0 = program[PC + 1]; if (useQueue) qansel_instruction_queue(&queueVector, qubitCount, instr, a0, f0, f1, f2); - else qansel_instruction(&stateVector, qubitCount, instr, a0, f0, f1, f2, NULL); + else qansel_instruction(ctx, &stateVector, qubitCount, instr, a0, f0, f1, f2, NULL); break; case QANSEL_INSTRUCTION_CX: a0 = program[PC + 1]; @@ -1143,7 +1371,7 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit case QANSEL_INSTRUCTION_MEASURE: a0 = program[PC + 1]; a1 = program[PC + 2] - QANSEL_CBOUND_LOWER; - bitVector[a1] = qansel_measure(&stateVector, qubitCount, a0); + bitVector[a1] = qansel_measure(ctx, &stateVector, qubitCount, a0); break; case QANSEL_INSTRUCTION_BORN: a0 = program[PC + 1]; @@ -1162,17 +1390,7 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit break; case QANSEL_INSTRUCTION_RESET: a0 = program[PC + 1]; - qansel_reset(&stateVector, bitVector, qubitCount, bitCount, a0); - break; - case QANSEL_INSTRUCTION_HVAR: - QANSEL_HIDDEN_VARIABLE = 1; - float tmp1 = qansel_get_float(program, PC + 1); - unsigned int tmp2; - memcpy(&tmp2, &tmp1, sizeof(unsigned int)); - srand(tmp2); - break; - case QANSEL_INSTRUCTION_RAND: - QANSEL_HIDDEN_VARIABLE = 0; + qansel_reset(ctx, &stateVector, bitVector, qubitCount, bitCount, a0); break; case QANSEL_INSTRUCTION_IF_E: a0 = program[PC + 1]; @@ -1210,12 +1428,11 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); skip = 1; if ((flags & QANSEL_FLAGS_LESSER) && (flags & QANSEL_FLAGS_EQUAL)) skip = 0; break; - case QANSEL_INSTRUCTION_SAMPLE: break; } } PC += next; - if (QANSEL_USE_DISPLAY) { QANSEL_USE_DISPLAY = display(&stateVector, qubitCount, QANSEL_USE_DISPLAY); } + if (ctx->display_delay) { ctx->display_delay = display(&stateVector, qubitCount, ctx->display_delay); } } if (outputBitVector != NULL) { @@ -1233,28 +1450,36 @@ void qansel_run(unsigned char* program, int programSize, int qubitCount, int bit } free(queueVector); } - if (QANSEL_USE_DISPLAY) { display(NULL, 0, 0); } + if (ctx->display_delay) { display(NULL, 0, 0); } } -int qanselExecuteBytecode(unsigned char* buff, int sizeofbuff) +int qanselExecuteBytecode(unsigned char* buff, int sizeofbuff, QAnselContext* ctx) { + if (!qanselContextValidate(ctx)) return 0; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); float seed = (float)((unsigned long)ts.tv_sec * 1000000000LL + ts.tv_nsec); qansel_rand_s(seed); + if (ctx != NULL && ctx->hidden_variable != 0) + { + unsigned int tmp; + memcpy(&tmp, &(ctx->hidden_variable), sizeof(unsigned int)); + srand(tmp); + } + unsigned short vals; float valf; int pos = 0; - int qubitCount, bitCount, sample; - if (!qansel_crawl(buff, sizeofbuff, &qubitCount, &bitCount, &sample)) + int qubitCount, bitCount; + if (!qansel_crawl(ctx, buff, sizeofbuff, &qubitCount, &bitCount)) { return 0; } - if (sample != QANSEL_ALL) + if (ctx != NULL && ctx->sampling_shots > 0) { unsigned short stats[65536]; for (unsigned int i = 0; i < (1 << bitCount); i++) @@ -1264,10 +1489,10 @@ int qanselExecuteBytecode(unsigned char* buff, int sizeofbuff) unsigned char bitVect[bitCount]; memset(bitVect, 0, bitCount); for (int i = 0; i < bitCount; i++) bitVect[i] = 0; - unsigned int shots = QANSEL_SAMPLE_COUNT; + unsigned int shots = ctx->sampling_shots; for (unsigned int i = 0; i < shots; i++) { - qansel_run(buff, sizeofbuff, qubitCount, bitCount, bitVect); + qansel_run(ctx, buff, sizeofbuff, qubitCount, bitCount, bitVect); unsigned short stat = 0; for (signed char j = bitCount - 1; j >= 0; j--) { @@ -1282,22 +1507,22 @@ int qanselExecuteBytecode(unsigned char* buff, int sizeofbuff) for (unsigned char j = 0; j < bitCount; j++) { unsigned char bit = (tmp >> (bitCount - 1) & 1); - if (j == (bitCount - sample - 1) && bit) + if (j == (bitCount - (ctx->sampling_bit) - 1) && bit) { count += stats[i]; } - if (sample == QANSEL_ALL_QUANTUM) + if ((ctx->sampling_bit) == QANSEL_ALL) { putchar('0' + bit); } tmp <<= 1; } - if (sample == QANSEL_ALL_QUANTUM) + if ((ctx->sampling_bit) == QANSEL_ALL) { printf(": %.1f%%\n", ((float)stats[i] / (float)shots) * (float)100); } } - if (sample != QANSEL_ALL_QUANTUM) + if ((ctx->sampling_bit) != QANSEL_ALL) { float prob = ((float)count / (float)shots) * (float)100; printf("0: %.1f%%\n", ((float)100)-prob); @@ -1306,7 +1531,7 @@ int qanselExecuteBytecode(unsigned char* buff, int sizeofbuff) } else { - qansel_run(buff, sizeofbuff, qubitCount, bitCount, NULL); + qansel_run(ctx, buff, sizeofbuff, qubitCount, bitCount, NULL); } return 1; } diff --git a/src/complex.c b/src/complex.c index f9481e8..bc1d3d7 100644 --- a/src/complex.c +++ b/src/complex.c @@ -1,13 +1,5 @@ #ifndef __cpx__ #define __cpx__ -#include -#include -#include -#include -#include -#include "hardware.c" -#include "kernel_cpu.cl" -#include "kernel_gpu.cl" typedef struct { float real, imaginary; @@ -19,9 +11,9 @@ typedef struct int rows, cols; } cpx_mtx_t; -uint8_t* cpx_str(cpx_t* n) +unsigned char* cpx_str(cpx_t* n) { - uint8_t* r; + unsigned char* r; int z; float rl = n->real; @@ -35,7 +27,7 @@ uint8_t* cpx_str(cpx_t* n) } else { - uint8_t op = n->imaginary >= 0 ? '+' : '-'; + unsigned char op = n->imaginary >= 0 ? '+' : '-'; z = snprintf(NULL, 0, "%f %c %fi", rl, op, ig); r = malloc(z + 1); sprintf(r, "%f %c %fi", rl, op, ig); @@ -149,7 +141,7 @@ void cpx_mtx_print(cpx_mtx_t* m) { cpx_t n; cpx_mtx_get(m, r, c, &n); - uint8_t* s = cpx_str(&n); + unsigned char* s = cpx_str(&n); if (c > 0) printf(", "); printf("%s", s); free(s); @@ -218,7 +210,7 @@ void* cpx_mtx_knk_threads_run(void *context) void cpx_mtx_knk_threads(float* ptrR, float* ptrA, float* ptrB, int rowsA, int colsA, int rowsB, int colsB) { int delimeter = rowsA * rowsB; - int cores = get_core_count(); + int cores = qansel_get_core_count(); int threadCount = cores; if (threadCount > delimeter) threadCount = delimeter; int delimetersPerThread = delimeter / threadCount; @@ -245,7 +237,7 @@ void cpx_mtx_knk_threads(float* ptrR, float* ptrA, float* ptrB, int rowsA, int c exit(1); } } - for (uint32_t i = 0; i < threadCount; i++) + for (unsigned int i = 0; i < threadCount; i++) { if (pthread_join(threads[i], NULL)) { @@ -283,7 +275,7 @@ void* cpx_mtx_knk_threads_2x2_run(void *context) void cpx_mtx_knk_threads_2x2(float* ptrR, float* ptrA, float* ptrB, int rowsA, int colsA, int rowsB, int colsB) { int delimeter = (rowsA * rowsB) / 2; - int cores = get_core_count(); + int cores = qansel_get_core_count(); int threadCount = cores; if (threadCount > delimeter) threadCount = delimeter; int delimetersPerThread = delimeter / threadCount; @@ -310,7 +302,7 @@ void cpx_mtx_knk_threads_2x2(float* ptrR, float* ptrA, float* ptrB, int rowsA, i exit(1); } } - for (uint32_t i = 0; i < threadCount; i++) + for (unsigned int i = 0; i < threadCount; i++) { if (pthread_join(threads[i], NULL)) { @@ -334,7 +326,7 @@ void* cpx_mtx_dot_threads_run(void *context) void cpx_mtx_dot_threads(float* ptrR, float* ptrA, float* ptrB, int rowsA, int colsA, int rowsB, int colsB) { int delimeter = colsB; - int cores = get_core_count(); + int cores = qansel_get_core_count(); int threadCount = cores; if (threadCount > delimeter) threadCount = delimeter; int delimeterPerThread = delimeter / threadCount; @@ -360,7 +352,7 @@ void cpx_mtx_dot_threads(float* ptrR, float* ptrA, float* ptrB, int rowsA, int c exit(1); } } - for (uint32_t i = 0; i < threadCount; i++) + for (unsigned int i = 0; i < threadCount; i++) { if (pthread_join(threads[i], NULL)) { @@ -458,7 +450,7 @@ const char* clGetErrorString(cl_int err) } -uint8_t cpx_mtx_begin() +unsigned char cpx_mtx_begin(unsigned char verbose) { cl_uint count; cl_int err; @@ -467,9 +459,9 @@ uint8_t cpx_mtx_begin() if (err != CL_SUCCESS || count == 0) { if (err == 0) - fprintf(stderr, "GPU error: No supported platforms found.\n"); + fprintf(stderr, "QAnsel (GPU): No supported platforms found.\n"); else - fprintf(stderr, "GPU error: clGetPlatformIDs() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clGetPlatformIDs() failed.\n"); return 0; } @@ -477,32 +469,42 @@ uint8_t cpx_mtx_begin() if (err != CL_SUCCESS || count == 0) { if (count == 0) - fprintf(stderr, "GPU error: No supported GPUs found.\n"); + fprintf(stderr, "QAnsel (GPU): No supported GPUs found.\n"); else - fprintf(stderr, "GPU error: clGetDeviceIDs() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clGetDeviceIDs() failed.\n"); return 0; } - //size_t size; - //clGetDeviceInfo(cpx_mtx_device_id, CL_DEVICE_NAME, 0, NULL, &size); - //char str[size]; - //clGetDeviceInfo(cpx_mtx_device_id, CL_DEVICE_NAME, size, str, NULL); - //printf("%s\n", str); + size_t size; + err = clGetDeviceInfo(cpx_mtx_device_id, CL_DEVICE_NAME, 0, NULL, &size); + if (err != CL_SUCCESS) + { + fprintf(stderr, "QAnsel: Unknown GPU error.\n"); + return 0; + } + char str[size]; + err = clGetDeviceInfo(cpx_mtx_device_id, CL_DEVICE_NAME, size, str, NULL); + if (err != CL_SUCCESS) + { + fprintf(stderr, "QAnsel: Unknown GPU error.\n"); + return 0; + } + if (verbose) printf("QAnsel: Hardware `%s` selected.\n", str); cpx_mtx_context = clCreateContext(NULL, 1, &cpx_mtx_device_id, NULL, NULL, &err); if (err != CL_SUCCESS) { - fprintf(stderr, "GPU error: clCreateContext() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clCreateContext() failed.\n"); return 0; } cpx_mtx_command_queue = clCreateCommandQueue(cpx_mtx_context, cpx_mtx_device_id, 0, &err); if (err != CL_SUCCESS) { - fprintf(stderr, "GPU error: clCreateCommandQueue() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clCreateCommandQueue() failed.\n"); err = clReleaseContext(cpx_mtx_context); if (err != CL_SUCCESS) - fprintf(stderr, "GPU error: clReleaseContext() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clReleaseContext() failed.\n"); return 0; } return 1; @@ -514,12 +516,12 @@ void cpx_mtx_clean() err = clReleaseCommandQueue(cpx_mtx_command_queue); if (err != CL_SUCCESS) { - fprintf(stderr, "GPU error: clReleaseCommandQueue() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clReleaseCommandQueue() failed.\n"); } err = clReleaseContext(cpx_mtx_context); if (err != CL_SUCCESS) { - fprintf(stderr, "GPU error: clReleaseContext() failed.\n"); + fprintf(stderr, "QAnsel (GPU): clReleaseContext() failed.\n"); } free(cpx_mtx_cache); } @@ -650,7 +652,7 @@ void cpx_copy(float* ptr, cl_mem* buff, size_t* buff_size) exit(1); } } - for (uint32_t i = 0; i < threadCount; i++) + for (unsigned int i = 0; i < threadCount; i++) { if (pthread_join(threads[i], NULL)) { @@ -674,7 +676,7 @@ void cpx_mtx_knk_metal(float* ptrR, float* ptrA, float* ptrB, int rowsA, int col cl_mem memR = clCreateBuffer(cpx_mtx_context, CL_MEM_WRITE_ONLY, sizeR, NULL, &err); gpuerr(err); //Populate buffers - unsigned long long int q = get_time(); + unsigned long long int q = qansel_get_time(); err = clEnqueueWriteBuffer(cpx_mtx_command_queue, memA, CL_TRUE, 0, sizeA, ptrA, 0, NULL, NULL); gpuerr(err); err = clEnqueueWriteBuffer(cpx_mtx_command_queue, memB, CL_TRUE, 0, sizeB, ptrB, 0, NULL, NULL); diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..27528ce --- /dev/null +++ b/src/context.c @@ -0,0 +1,111 @@ +int qanselContextValidate(QAnselContext* ctx) +{ + if (ctx->memory_limit == 0) ctx->memory_limit = QANSEL_QUBITS_MAX; + if (ctx->memory_limit > QANSEL_QUBITS_MAX) + { + fprintf(stderr, "QAnsel: Invalid memory limit.\n", ctx->memory_limit); + return 0; + } + + if (ctx->sampling_shots < 0 || ctx->sampling_shots > 100000) + { + fprintf(stderr, "QAnsel: Invalid number of shots.\n"); + return 0; + } + if (ctx->display_delay < 0 || ctx->display_delay > 100) + { + fprintf(stderr, "QAnsel: Invalid display settings.\n"); + return 0; + } + if (ctx->optimization_level < QANSEL_MODE_BARE || ctx->optimization_level > (QANSEL_MODE_THREADED | QANSEL_MODE_METAL | QANSEL_MODE_QUEUE)) + { + fprintf(stderr, "QAnsel: Invalid optimization settings.\n"); + return 0; + } + + switch (ctx->hardware_rng) + { + case QANSEL_HARDWARE_NONE: + case QANSEL_HARDWARE_AUTO: + case QANSEL_HARDWARE_TRUERNG: + case QANSEL_HARDWARE_RDSEED: + break; + default: + fprintf(stderr, "QAnsel: Invalid hardware settings.\n"); + return 0; + } + + return 1; + +} + +int qanselContextBegin(QAnselContext* ctx) +{ + if (ctx->memory_limit == 0) ctx->memory_limit = QANSEL_QUBITS_MAX; + if (ctx->memory_limit > QANSEL_QUBITS_MAX) + { + fprintf(stderr, "QAnsel: Invalid memory limit.\n", ctx->memory_limit); + return 0; + } + + if (ctx->sampling_shots < 0 || ctx->sampling_shots > 100000) + { + fprintf(stderr, "QAnsel: Invalid number of shots.\n"); + return 0; + } + if (ctx->display_delay < 0 || ctx->display_delay > 100) + { + fprintf(stderr, "QAnsel: Invalid display settings.\n"); + return 0; + } + if (ctx->optimization_level < QANSEL_MODE_BARE || ctx->optimization_level > (QANSEL_MODE_THREADED | QANSEL_MODE_METAL | QANSEL_MODE_QUEUE)) + { + fprintf(stderr, "QAnsel: Invalid optimization settings.\n"); + return 0; + } + + if (ctx->hardware_rng == QANSEL_HARDWARE_AUTO) + { + ctx->random_file = fopen("/dev/TrueRNG0", "r"); + if (ctx->random_file == NULL) + { + if (qansel_hardware_rand_supported()) + { + if (ctx->verbose) printf("QAnsel: Hardware `Intel Secure Key Technology` selected.\n"); + ctx->hardware_rng = QANSEL_HARDWARE_RDSEED; + } + else + { + fprintf(stderr, "QAnsel: No supported hardware random number generator found.\n"); + return 0; + } + } + else + { + if (ctx->verbose) printf("QAnsel: Hardware `TrueRNG` selected.\n"); + ctx->hardware_rng = QANSEL_HARDWARE_TRUERNG; + } + } + if (ctx->optimization_level & QANSEL_MODE_METAL) + { + if (!cpx_mtx_begin(ctx->verbose)) + { + fprintf(stderr, "QAnsel: No supported hardware accelerator found.\n"); + return 0; + } + } + if (ctx->sampling_shots == 0) + { + ctx->sampling_shots = QANSEL_SHOTS_DEFAULT; + } + + return 1; + +} + +int qanselContextEnd(QAnselContext* ctx) +{ + if (ctx->random_file != NULL) fclose(ctx->random_file); + if (ctx->optimization_level & QANSEL_MODE_METAL) cpx_mtx_clean(); + return 1; +} \ No newline at end of file diff --git a/src/hardware.c b/src/hardware.c index 3b6d3b2..89c1d54 100644 --- a/src/hardware.c +++ b/src/hardware.c @@ -1,15 +1,4 @@ -#include -#include -#if defined(_WIN32) || defined(_WIN64) -#include -#elif defined(__linux__) -#include -#include -#elif defined(__APPLE__) -#include -#endif - -int ___get_core_count() +int qansel___get_core_count() { #if defined(_WIN32) || defined(_WIN64) SYSTEM_INFO sysinfo; @@ -39,12 +28,12 @@ int ___get_core_count() #endif } -int get_core_count() +int qansel_get_core_count() { static int coreCount = -1; if (coreCount == -1) { - coreCount = ___get_core_count(); + coreCount = qansel___get_core_count(); if (coreCount == -1) { coreCount = 1; @@ -53,7 +42,7 @@ int get_core_count() return coreCount; } -unsigned long int get_time() +unsigned long int qansel_get_time() { struct timeval tv; gettimeofday(&tv,NULL); @@ -66,7 +55,9 @@ int qansel_hardware_rand_supported() #if defined(__x86_64__) || defined(__i386__) int result = 0; - // Execute CPUID instruction with feature request + //Check for RDSEED + // https://en.wikipedia.org/wiki/CPUID#Calling_CPUID + // accessed 14-03-2024 __asm__ volatile ( "mov $7, %%eax;mov $0, %%ecx;cpuid;mov %%ebx, %0;" @@ -79,7 +70,10 @@ int qansel_hardware_rand_supported() return 0; #endif } -int qansel_hardware_rand() -{ +unsigned char qansel_hardware_rand() +{ + unsigned long long int r; + __asm__ volatile ("1:;rdseed %0;;jnc 1b;" : "=r" (r)); + return r & 0xFF; } diff --git a/src/main.c b/src/main.c index e7dd096..675640c 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,9 @@ void display_help() printf(" used to set an even lower limit.\n"); printf(" -sX Used for setting the number of shots\n"); printf(" when sampling to X.\n"); + printf(" -hX Use a hidden variable rather than\n"); + printf(" randomly generating measurement\n"); + printf(" results.\n"); printf(" -r Enables a supported hardware random\n"); printf(" number generator.\n"); printf(" -v Enables verbose mode.\n"); @@ -29,67 +32,25 @@ void display_help() void main(int argc, char** argv) { + QAnselContext ctx = {0}; - printf("%i\n", qansel_hardware_rand_supported()); - return; int opt; - int maximumQubitSettings = QANSEL_QUBITS_MAX; - int hardwarerngSetting = 0; - - while ((opt = getopt(argc, argv, "o:q:d:s:rvq?")) != -1) + while ((opt = getopt(argc, argv, "o:q:d:s:h:rvq?")) != -1) { switch (opt) { - case 'o': QANSEL_MODE = atoi(optarg); break; - case 'd': QANSEL_USE_DISPLAY = atoi(optarg); break; - case 'q': QANSEL_QUBIT_LIMIT = atoi(optarg); break; - case 's': QANSEL_SAMPLE_COUNT = atoi(optarg); break; - case 'r': hardwarerngSetting = 1; break; - case 'v': QANSEL_VERBOSE = 1; break; + case 'o': ctx.optimization_level = atoi(optarg); break; + case 'd': ctx.display_delay = atoi(optarg); break; + case 'q': ctx.memory_limit = atoi(optarg); break; + case 's': ctx.sampling_shots = atoi(optarg); break; + case 'r': ctx.hardware_rng = 1; break; + case 'h': ctx.hidden_variable = atof(optarg); break; + case 'v': ctx.verbose = 1; break; case '?': display_help(); break; default: exit(1); } } - if (QANSEL_SAMPLE_COUNT < 0 || QANSEL_SAMPLE_COUNT > 100000) - { - fprintf(stderr, "QAnsel: Invalid number of shots.\n"); - exit(1); - } - if (QANSEL_USE_DISPLAY < 0 || QANSEL_USE_DISPLAY > 100) - { - fprintf(stderr, "QAnsel: Invalid display settings.\n"); - exit(1); - } - if (QANSEL_MODE < QANSEL_MODE_BARE || QANSEL_MODE > (QANSEL_MODE_THREADED | QANSEL_MODE_METAL | QANSEL_MODE_QUEUE)) - { - fprintf(stderr, "QAnsel: Invalid optimization settings.\n"); - exit(1); - } - if (QANSEL_QUBIT_LIMIT <= 0 || QANSEL_QUBIT_LIMIT > QANSEL_QUBITS_MAX) - { - fprintf(stderr, "QAnsel: Invalid limit for quantum bits.\n"); - exit(1); - } - - if (hardwarerngSetting == 1) - { - QANSEL_RANDOM_FILE = fopen("/dev/TrueRNG0", "r"); - if (QANSEL_RANDOM_FILE == NULL) - { - fprintf(stderr, "QAnsel: No supported hardware random number generator found.\n"); - exit(1); - } - } - if (QANSEL_MODE & QANSEL_MODE_METAL) - { - if (!cpx_mtx_begin()) - { - fprintf(stderr, "QAnsel: No supported hardware accelerator found.\n"); - exit(1); - } - } - char* script = malloc(0); size_t scriptSize = 0; int c; @@ -103,14 +64,14 @@ void main(int argc, char** argv) unsigned char* bytecode; int bytecodeSize; - if (qanselBuildFromSource(script, &bytecode, &bytecodeSize)) + + if (!qanselContextBegin(&ctx)) exit(1); + if (qanselBuildFromSource(script, &bytecode, &bytecodeSize, &ctx)) { - qanselExecuteBytecode(bytecode, bytecodeSize); + qanselExecuteBytecode(bytecode, bytecodeSize, &ctx); + free(bytecode); } - free(bytecode); - - if (QANSEL_RANDOM_FILE != NULL) fclose(QANSEL_RANDOM_FILE); - if (QANSEL_MODE & QANSEL_MODE_METAL) cpx_mtx_clean(); + qanselContextEnd(&ctx); return; } \ No newline at end of file diff --git a/src/openqasm.c b/src/openqasm.c index 2a3fbaa..24b65bc 100644 --- a/src/openqasm.c +++ b/src/openqasm.c @@ -202,7 +202,7 @@ int qansel_parse_float(char* str, float* returnFloat) return 1; } -int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatches, int* qubitCount, int* bitCount, unsigned char** binary, int* binarySize) +int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatches, int* qubitCount, int* bitCount, unsigned char** binary, int* binarySize, QAnselContext* ctx, int samplingshots) { unsigned short s0; float d0, d1, d2; @@ -223,9 +223,9 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche memcpy(tmp, chunk + strbeg, strlen); tmp[strlen] = 0; int nump = atoi(tmp); - if (nump > QANSEL_QUBIT_LIMIT) + if (nump > ctx->memory_limit) { - fprintf(stderr, "QAnsel on line %i: Initialized qubits cannot exceed %i.\n", line, QANSEL_QUBIT_LIMIT); + fprintf(stderr, "QAnsel on line %i: Initialized qubits cannot exceed %i.\n", line, ctx->memory_limit); return 0; } *qubitCount = nump; @@ -243,9 +243,9 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche memcpy(tmp, chunk + strbeg, strlen); tmp[strlen] = 0; int nump = atoi(tmp); - if (nump > QANSEL_QUBIT_LIMIT) + if (nump > ctx->memory_limit) { - fprintf(stderr, "QAnsel on line %i: Initialized classical bits cannot exceed %i.\n", line, QANSEL_QUBIT_LIMIT); + fprintf(stderr, "QAnsel on line %i: Initialized classical bits cannot exceed %i.\n", line, ctx->memory_limit); return 0; } *bitCount = nump; @@ -445,7 +445,7 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche char tmp[strlen + 1]; memcpy(tmp, chunk + strbeg, strlen); tmp[strlen] = 0; - if (strcmp(tmp, "sample") == 0) instr = QANSEL_INSTRUCTION_SAMPLE; + if (strcmp(tmp, "sample") == 0) instr = 0x00; else if (strcmp(tmp, "reset") == 0) instr = QANSEL_INSTRUCTION_RESET; else if (strcmp(tmp, "print") == 0) instr = QANSEL_INSTRUCTION_PRINT; } @@ -474,10 +474,20 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche a0 = QANSEL_ALL_CLASSIC; } } - *binarySize += 2; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2] = instr; - (*binary)[(*binarySize) - 1] = a0; + if (instr == 0x00) //sample + { + if (a0 == QANSEL_ALL_QUANTUM) a0 = QANSEL_ALL; + else a0 = a0 - QANSEL_CBOUND_LOWER; + ctx->sampling_bit = a0; + ctx->sampling_shots = samplingshots; + } + else + { + *binarySize += 2; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2] = instr; + (*binary)[(*binarySize) - 1] = a0; + } } else if (index == 8 || index == 9) //double qubit instructions { @@ -634,7 +644,7 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche char tmp[strlen + 1]; memcpy(tmp, chunk + strbeg, strlen); tmp[strlen] = 0; - if (strcmp(tmp, "hvar") == 0) instr = QANSEL_INSTRUCTION_HVAR; + if (strcmp(tmp, "hvar") == 0) instr = 1; } { int strbeg = regmatches[rmp].rm_so; @@ -649,10 +659,10 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche return 0; } } - *binarySize += 1 + sizeof(float); - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 1 - sizeof(float)] = instr; - memcpy((*binary) + ((*binarySize) - sizeof(float)), &d0, sizeof(float)); + switch (instr) + { + case 1: ctx->hidden_variable = d0; break; + } } else if (index == 12) //lone instructions { @@ -664,7 +674,11 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche char tmp[strlen + 1]; memcpy(tmp, chunk + strbeg, strlen); tmp[strlen] = 0; - if (strcmp(tmp, "rand") == 0) instr = QANSEL_INSTRUCTION_RAND; + if (strcmp(tmp, "rand") == 0) + { + ctx->hidden_variable = 0; + return 1; + } else if (strcmp(tmp, "exit") == 0) instr = QANSEL_INSTRUCTION_EXIT; } *binarySize += 1; @@ -674,7 +688,7 @@ int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatche return 1; } -int qansel_process_chunks(char** chunks, int* associatedLines, int count, unsigned char** retBinary, int* retSize) +int qansel_process_chunks(char** chunks, int* associatedLines, int count, unsigned char** retBinary, int* retSize, QAnselContext* ctx, int samplingshots) { unsigned char* binary = malloc(0); int binarySize = 0; @@ -715,7 +729,7 @@ int qansel_process_chunks(char** chunks, int* associatedLines, int count, unsign if (!ret) { found = 1; - status = qansel_process_chunk(j, chunks[i], associatedLines[i], regmatches, &qubitCount, &bitCount, &binary, &binarySize); + status = qansel_process_chunk(j, chunks[i], associatedLines[i], regmatches, &qubitCount, &bitCount, &binary, &binarySize, ctx, samplingshots); break; } else if (ret == REG_NOMATCH) {} @@ -738,14 +752,17 @@ int qansel_process_chunks(char** chunks, int* associatedLines, int count, unsign return status; } -int qanselBuildFromSource(char* source, unsigned char** binary, int* binarySize) +int qanselBuildFromSource(char* source, unsigned char** binary, int* binarySize, QAnselContext* ctx) { + if (!qanselContextValidate(ctx)) return 0; char** chunks; int* chunksAssociatedLines; int chunksCount; int status = qansel_read_script(source, &chunks, &chunksAssociatedLines, &chunksCount); + int samplingshots = ctx->sampling_shots; + ctx->sampling_shots = 0; if (!status) return 0; - status = qansel_process_chunks(chunks, chunksAssociatedLines, chunksCount, binary, binarySize); + status = qansel_process_chunks(chunks, chunksAssociatedLines, chunksCount, binary, binarySize, ctx, samplingshots); for (int i = 0; i < chunksCount; i++) free(chunks[i]); free(chunks); free(chunksAssociatedLines); @@ -756,6 +773,8 @@ int qanselBuildFromSource(char* source, unsigned char** binary, int* binarySize) free(*binary); return 0; } + + //qansel_reorder(ctx, *binary, *binarySize); return 1; } diff --git a/src/qansel.h b/src/qansel.h index 60a932b..875e169 100644 --- a/src/qansel.h +++ b/src/qansel.h @@ -7,25 +7,30 @@ #include #include #include -#include "complex.c" -#include "gates.c" -#include "display.c" +#include +#include +#include +#if defined(_WIN32) || defined(_WIN64) +#include +#elif defined(__linux__) +#include +#include +#elif defined(__APPLE__) +#include +#endif + +#define QANSEL_SHOTS_DEFAULT 1000 #define QANSEL_QUBITS_MAX 16 -unsigned char QANSEL_QUBIT_LIMIT = QANSEL_QUBITS_MAX; -unsigned char QANSEL_HIDDEN_VARIABLE = 0; -unsigned char QANSEL_USE_DISPLAY = 0; -unsigned char QANSEL_VERBOSE = 0; -unsigned char QANSEL_USE_QUEUE = 0; -#define QANSEL_DEFAULT_SAMPLE_COUNT 1000 -int QANSEL_SAMPLE_COUNT = QANSEL_DEFAULT_SAMPLE_COUNT; -FILE* QANSEL_RANDOM_FILE = NULL; #define QANSEL_MODE_BARE 0 #define QANSEL_MODE_THREADED 1 #define QANSEL_MODE_METAL 2 #define QANSEL_MODE_QUEUE 4 -unsigned char QANSEL_MODE = QANSEL_MODE_BARE; //#define SPEED_TEST +#define QANSEL_HARDWARE_NONE 0 +#define QANSEL_HARDWARE_AUTO 1 +#define QANSEL_HARDWARE_TRUERNG 2 +#define QANSEL_HARDWARE_RDSEED 3 #define QANSEL_INSTRUCTION_X 0x10 #define QANSEL_INSTRUCTION_Y 0x11 #define QANSEL_INSTRUCTION_Z 0x12 @@ -43,21 +48,18 @@ unsigned char QANSEL_MODE = QANSEL_MODE_BARE; #define QANSEL_INSTRUCTION_CCX 0x40 #define QANSEL_INSTRUCTION_CSWAP 0x41 #define QANSEL_INSTRUCTION_MEASURE 0xD0 -#define QANSEL_INSTRUCTION_SAMPLE 0xD1 -#define QANSEL_INSTRUCTION_DENSITY 0xD2 -#define QANSEL_INSTRUCTION_BORN 0xD3 +#define QANSEL_INSTRUCTION_DENSITY 0xD1 +#define QANSEL_INSTRUCTION_BORN 0xD2 #define QANSEL_INSTRUCTION_IF_E 0xE1 #define QANSEL_INSTRUCTION_IF_NE 0xE2 #define QANSEL_INSTRUCTION_IF_G 0xE3 #define QANSEL_INSTRUCTION_IF_GE 0xE4 #define QANSEL_INSTRUCTION_IF_L 0xE5 #define QANSEL_INSTRUCTION_IF_LE 0xE6 -#define QANSEL_INSTRUCTION_RAND 0xF0 -#define QANSEL_INSTRUCTION_HVAR 0xF1 -#define QANSEL_INSTRUCTION_RESET 0xF2 -#define QANSEL_INSTRUCTION_PRINT 0xF3 -#define QANSEL_INSTRUCTION_BARRIER 0xF4 -#define QANSEL_INSTRUCTION_EXIT 0xF5 +#define QANSEL_INSTRUCTION_PRINT 0xF0 +#define QANSEL_INSTRUCTION_RESET 0xF1 +#define QANSEL_INSTRUCTION_BARRIER 0xF2 +#define QANSEL_INSTRUCTION_EXIT 0xF3 #define QANSEL_FLAGS_EQUAL 0b00001 #define QANSEL_FLAGS_GREATER 0b00010 @@ -72,6 +74,40 @@ unsigned char QANSEL_MODE = QANSEL_MODE_BARE; #define QANSEL_ALL_CLASSIC 0x3F #define QANSEL_ALL 0xFF +typedef struct +{ + unsigned char memory_limit; + unsigned char hardware_rng; + unsigned char verbose; + unsigned char optimization_level; + unsigned char sampling_bit; + float hidden_variable; + int display_delay; + int sampling_shots; + FILE* random_file; +} QAnselContext; + +typedef struct +{ + int size; + unsigned char bytes[16]; + int barrier_width; + unsigned char barrier[QANSEL_QUBITS_MAX * 2]; + int next; + int prev; + int checked; + int op; + unsigned char ifop[16]; + int use_ifop; +} QBytecode; + +#include "kernel_cpu.cl" +#include "kernel_gpu.cl" +#include "hardware.c" +#include "complex.c" +#include "context.c" +#include "gates.c" +#include "display.c" #include "bytecode.c" #include "openqasm.c" #endif \ No newline at end of file