From: miha-q <> Date: Sun, 10 Mar 2024 01:53:46 +0000 (-0500) Subject: Sat Mar 9 08:53:46 PM EST 2024 X-Git-Url: http://www.foleosoft.com/?a=commitdiff_plain;h=4c3956857bb4fbfe88ce39a4588a6326e618ace0;p=QAnsel.git Sat Mar 9 08:53:46 PM EST 2024 --- diff --git a/src/QAnsel.c b/src/QAnsel.c index cb11e3a..9722181 100644 --- a/src/QAnsel.c +++ b/src/QAnsel.c @@ -1,751 +1,67 @@ -#include -#include "core.c" +#include "qansel.h" +#include "bytecode.c" +#include "openqasm.c" -void qansel_read_script(char* script, char*** chunksReturn, int** chunkLinesReturn, int* countReturn) +void main(int argc, char** argv) { - size_t scriptSize = strlen(script); - char* line = malloc(0); - char** chunks = malloc(0); - int* chunksAssociatedLines = malloc(0); - int lineCount = 1; - int lineLen = 0; - int chunkCount = 0; - int inComment = 0; - for (int i = 0; i < scriptSize; i++) - { - int charactersLeft = scriptSize - i; - if (script[i] == '\n') - { - lineCount++; - inComment = 0; - } - else if (charactersLeft >= 2 && script[i] == '/' && script[i + 1] == '/') - { - inComment = 1; - } - else if (!inComment && script[i] != ';' && script[i] != '{' && script[i] != '}') - { - line = realloc(line, lineLen + 1); - line[lineLen++] = script[i] == '\t' ? ' ' : script[i]; - if (script[i] == ')' && lineLen > 2) - { - for (int j = 0; j < lineLen - 1; j++) - { - if ( (line[j] == 'i' || line[j] == 'I') && (line[j + 1] == 'f' || line[j + 1] == 'F') ) - { - line = realloc(line, lineLen + 1); - line[lineLen++] = 0; - chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); - chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); - chunks[chunkCount] = line; - chunksAssociatedLines[chunkCount++] = lineCount; - line = malloc(0); - lineLen = 0; - break; - } - } - } - } - else if (!inComment && (script[i] == '{' || script[i] == '}')) - { - if (lineLen > 0) - { - line = realloc(line, lineLen + 1); - line[lineLen++] = 0; - chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); - chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); - chunks[chunkCount] = line; - chunksAssociatedLines[chunkCount++] = lineCount; - line = malloc(2); - } - else - { - line = realloc(line, 2); - } - line[0] = script[i]; - line[1] = 0; - chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); - chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); - chunks[chunkCount] = line; - chunksAssociatedLines[chunkCount++] = lineCount; - line = malloc(0); - lineLen = 0; - } - else if (!inComment && script[i] == ';') - { - if (lineLen > 0) - { - line = realloc(line, lineLen + 1); - line[lineLen++] = 0; - chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); - chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); - chunks[chunkCount] = line; - chunksAssociatedLines[chunkCount++] = lineCount; - line = malloc(0); - lineLen = 0; - } - } - } - if (lineLen > 0) - { - line = realloc(line, lineLen + 1); - line[lineLen++] = 0; - chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); - chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); - chunks[chunkCount] = line; - chunksAssociatedLines[chunkCount++] = lineCount; - } - else - { - free(line); - } - for (int i = 0; i < chunkCount; i++) - { - int len = strlen(chunks[i]); - for (int j = 0; j < len; j++) - { - if (chunks[i][j] >= 'A' && chunks[i][j] <= 'Z') - { - chunks[i][j] += 'a' - 'A'; - } - } - } - *chunksReturn = chunks; - *chunkLinesReturn = chunksAssociatedLines; - *countReturn = chunkCount; -} + int opt; + int optimizationSettings = QANSEL_MODE_BARE; + int displaySettings = 0; + int maximumQubitSettings = QANSEL_QUBITS_MAX; + int hardwarerngSetting = 0; -float qansel_parse_float_part(char* neg, char* str) -{ - float ret; - int len = strlen(str); - if (len > 2) + while ((opt = getopt(argc, argv, "o:q:d:rv")) != -1) { - ret = atof(str); - if (str[len - 2] == 'p' && str[len - 1] == 'i') + switch (opt) { - ret *= M_PI; + case 'o': optimizationSettings = atoi(optarg); break; + case 'd': displaySettings = atoi(optarg); break; + case 'q': maximumQubitSettings = atoi(optarg); break; + case 'r': hardwarerngSetting = 1; break; + case 'v': QANSEL_VERBOSE = 1; break; + default: exit(1); } } - else if (strcmp(str, "pi") == 0) - { - ret = M_PI; - } - else - { - ret = atof(str); - } - if (strcmp(neg, "-") == 0) - { - ret *= -1; - } - return ret; -} - -int qansel_parse_float(char* str, float* returnFloat) -{ - *returnFloat = 0; - const char expr[] = "^(-|)([0-9][0-9]*\\.[0-9]*|[0-9][0-9]*|[0-9][0-9]*\\.[0-9]*pi|[0-9][0-9]*pi|pi)([/](-|)([0-9][0-9]*\\.[0-9]*|[0-9][0-9]*|[0-9][0-9]*\\.[0-9]*pi|[0-9][0-9]*pi|pi)|)$"; - regex_t regex; - regmatch_t regmatches[10]; - if (regcomp(®ex, expr, REG_EXTENDED | REG_ICASE)) return 0; - int ret = regexec(®ex, str, 10, regmatches, 0); - if (!ret) - { - int strbeg = regmatches[1].rm_so; - int strlen = regmatches[1].rm_eo - regmatches[1].rm_so; - char neg1[strlen + 1]; - memcpy(neg1, str + strbeg, strlen); - neg1[strlen] = 0; - strbeg = regmatches[2].rm_so; - strlen = regmatches[2].rm_eo - regmatches[2].rm_so; - char numer[strlen + 1]; - memcpy(numer, str + strbeg, strlen); - numer[strlen] = 0; - *returnFloat = qansel_parse_float_part(neg1, numer); - - if (regmatches[3].rm_eo > regmatches[3].rm_so) - { - strbeg = regmatches[4].rm_so; - strlen = regmatches[4].rm_eo - regmatches[4].rm_so; - char neg2[strlen + 1]; - memcpy(neg2, str + strbeg, strlen); - neg2[strlen] = 0; - - strbeg = regmatches[5].rm_so; - strlen = regmatches[5].rm_eo - regmatches[5].rm_so; - char denom[strlen + 1]; - memcpy(denom, str + strbeg, strlen); - denom[strlen] = 0; - - float fdenom = qansel_parse_float_part(neg2, denom); - *returnFloat /= fdenom; - } - } - else if (ret == REG_NOMATCH) - { - return 0; - } - else + if (displaySettings < 0 | displaySettings > 100) { - char errbuf[100]; - regerror(ret, ®ex, errbuf, sizeof(errbuf)); - fprintf(stderr, "QAnsel: %s.\n", errbuf); + fprintf(stderr, "QAnsel: Invalid display settings.\n"); exit(1); } - regfree(®ex); + QANSEL_USE_DISPLAY = displaySettings; - return 1; -} - -int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatches, int* qubitCount, int* bitCount, unsigned char** binary, int* binarySize) -{ - unsigned short s0; - float d0, d1, d2; - unsigned char instr = 0; - unsigned char a0 = 0; - unsigned char a1 = 0; - unsigned char a2 = 0; - if (index == 0) //qreg - { - if (*qubitCount > 0) - { - fprintf(stderr, "QAnsel on line %i: Qubits can only be initialized once.\n", line); - return 0; - } - int strbeg = regmatches[1].rm_so; - int strlen = regmatches[1].rm_eo - regmatches[1].rm_so; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - int nump = atoi(tmp); - if (nump > QUBITS_MAX) - { - fprintf(stderr, "QAnsel on line %i: Initialized qubits cannot exceed %i.\n", line, QUBITS_MAX); - return 0; - } - *qubitCount = nump; - } - else if (index == 1) //creg - { - if (*bitCount > 0) - { - fprintf(stderr, "QAnsel on line %i: Classical bits can only be initialized once.\n", line); - return 0; - } - int strbeg = regmatches[1].rm_so; - int strlen = regmatches[1].rm_eo - regmatches[1].rm_so; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - int nump = atoi(tmp); - if (nump > QUBITS_MAX) - { - fprintf(stderr, "QAnsel on line %i: Initialized classical bits cannot exceed %i.\n", line, QUBITS_MAX); - return 0; - } - *bitCount = nump; - } - else if (index == 2 || index == 3 || index == 4 || index == 5) //single qubit instructions - { - if (*qubitCount == 0) - { - fprintf(stderr, "QAnsel on line %i: Quantum bit instruction used prior to initialization.\n", line); - return 0; - } - int rmp = 1; - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strcmp(tmp, "rx") == 0) instr = QANSEL_INSTRUCTION_RX; - else if (strcmp(tmp, "ry") == 0) instr = QANSEL_INSTRUCTION_RY; - else if (strcmp(tmp, "rz") == 0) instr = QANSEL_INSTRUCTION_RZ; - else if (strcmp(tmp, "u1") == 0) instr = QANSEL_INSTRUCTION_U1; - else if (strcmp(tmp, "u2") == 0) instr = QANSEL_INSTRUCTION_U2; - else if (strcmp(tmp, "u3") == 0) instr = QANSEL_INSTRUCTION_U3; - else if (strcmp(tmp, "u") == 0) instr = QANSEL_INSTRUCTION_U3; - else if (strcmp(tmp, "reset") == 0) instr = QANSEL_INSTRUCTION_RESET; - else if (strcmp(tmp, "barrier") == 0) instr = QANSEL_INSTRUCTION_BARRIER; - else if (strcmp(tmp, "born") == 0) instr = QANSEL_INSTRUCTION_BORN; - else if (strcmp(tmp, "density") == 0) instr = QANSEL_INSTRUCTION_DENSITY; - else if (strcmp(tmp, "print") == 0) instr = QANSEL_INSTRUCTION_PRINT; - else if (strcmp(tmp, "not") == 0) instr = QANSEL_INSTRUCTION_X; - else if (strcmp(tmp, "x") == 0) instr = QANSEL_INSTRUCTION_X; - else if (strcmp(tmp, "y") == 0) instr = QANSEL_INSTRUCTION_Y; - else if (strcmp(tmp, "z") == 0) instr = QANSEL_INSTRUCTION_Z; - else if (strcmp(tmp, "h") == 0) instr = QANSEL_INSTRUCTION_H; - else if (strcmp(tmp, "s") == 0) instr = QANSEL_INSTRUCTION_S; - else if (strcmp(tmp, "t") == 0) instr = QANSEL_INSTRUCTION_T; - } - for (int i = 0; i < (index == 2 ? 0 : (index == 3 ? 1 : (index == 4 ? 2 : 3))); i++) - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (!qansel_parse_float(tmp, (i == 0 ? &d0 : (i == 1 ? &d1 : &d2)))) - { - fprintf(stderr, "QAnsel on line %i: Invalid rotation value.\n", line); - return 0; - } - } - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - if (strlen > 0) - { - strbeg = regmatches[rmp].rm_so; - strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - a0 = atoi(tmp); - if (a0 >= *qubitCount) - { - fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated quantum bits.\n", line, a0); - return 0; - } - } - else - { - a0 = 0x0F; - if (instr == QANSEL_INSTRUCTION_DENSITY) - { - fprintf(stderr, "QAnsel on line %i: Density matrices can only be produced for individual qubits.\n", line, a0); - return 0; - } - } - } - switch (index) - { - case 2: - *binarySize += 2; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2] = instr; - (*binary)[(*binarySize) - 1] = a0; - break; - case 3: - *binarySize += 2 + sizeof(float) * 1; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2 - sizeof(float) * 1] = instr; - (*binary)[(*binarySize) - 1 - sizeof(float) * 1] = a0; - memcpy((*binary) + ((*binarySize) - sizeof(float)), &d0, sizeof(float)); - break; - case 4: - *binarySize += 2 + sizeof(float) * 2; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2 - sizeof(float) * 2] = instr; - (*binary)[(*binarySize) - 1 - sizeof(float) * 2] = a0; - memcpy((*binary) + ((*binarySize) - sizeof(float) * 2), &d0, sizeof(float)); - memcpy((*binary) + ((*binarySize) - sizeof(float) * 1), &d1, sizeof(float)); - break; - case 5: - *binarySize += 2 + sizeof(float) * 3; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2 - sizeof(float) * 3] = instr; - (*binary)[(*binarySize) - 1 - sizeof(float) * 3] = a0; - memcpy((*binary) + ((*binarySize) - sizeof(float) * 3), &d0, sizeof(float)); - memcpy((*binary) + ((*binarySize) - sizeof(float) * 2), &d1, sizeof(float)); - memcpy((*binary) + ((*binarySize) - sizeof(float) * 1), &d2, sizeof(float)); - break; - } - } - else if (index == 6) //measure instruction - { - if (*qubitCount == 0) - { - fprintf(stderr, "QAnsel on line %i: Quantum bit instruction used prior to initialization.\n", line); - return 0; - } - if (*bitCount == 0) - { - fprintf(stderr, "QAnsel on line %i: Classical bit instruction used prior to initialization.\n", line); - return 0; - } - int rmp = 1; - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - if (strlen > 0) - { - strbeg = regmatches[rmp].rm_so; - strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - a0 = atoi(tmp); - if (a0 >= *qubitCount) - { - fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated quantum bits.\n", line, a0); - return 0; - } - } - else - { - a0 = 0x0F; - } - } - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - if (strlen > 0) - { - strbeg = regmatches[rmp].rm_so; - strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - a1 = atoi(tmp); - if (a1 >= *bitCount) - { - fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated classical bits.\n", line, a1); - return 0; - } - a1 += 0x10; - } - else - { - a1 = 0x1F; - } - } - *binarySize += 3; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 3] = QANSEL_INSTRUCTION_MEASURE; - (*binary)[(*binarySize) - 2] = a0; - (*binary)[(*binarySize) - 1] = a1; - } - else if (index == 7) //classical bit instructions - { - if (*bitCount == 0) - { - fprintf(stderr, "QAnsel on line %i: Classical bit instruction used prior to initialization.\n", line); - return 0; - } - int rmp = 1; - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strcmp(tmp, "sample") == 0) instr = QANSEL_INSTRUCTION_SAMPLE; - else if (strcmp(tmp, "reset") == 0) instr = QANSEL_INSTRUCTION_RESET; - else if (strcmp(tmp, "print") == 0) instr = QANSEL_INSTRUCTION_PRINT; - } - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - if (strlen > 0) - { - strbeg = regmatches[rmp].rm_so; - strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - a0 = atoi(tmp); - if (a0 >= *bitCount) - { - fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated classical bits.\n", line, a0); - return 0; - } - a0 += 0x10; - } - else - { - a0 = 0x1F; - } - } - *binarySize += 2; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2] = instr; - (*binary)[(*binarySize) - 1] = a0; - } - else if (index == 8 || index == 9) //double qubit instructions - { - if (*qubitCount == 0) - { - fprintf(stderr, "QAnsel on line %i: Quantum bit instruction used prior to initialization.\n", line); - return 0; - } - int rmp = 1; - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strcmp(tmp, "cx") == 0) instr = QANSEL_INSTRUCTION_CX; - if (strcmp(tmp, "cnot") == 0) instr = QANSEL_INSTRUCTION_CX; - if (strcmp(tmp, "ccnot") == 0) instr = QANSEL_INSTRUCTION_CCX; - if (strcmp(tmp, "ccx") == 0) instr = QANSEL_INSTRUCTION_CCX; - else if (strcmp(tmp, "toffoli") == 0) instr = QANSEL_INSTRUCTION_CCX; - else if (strcmp(tmp, "cswap") == 0) instr = QANSEL_INSTRUCTION_CSWAP; - else if (strcmp(tmp, "fredkin") == 0) instr = QANSEL_INSTRUCTION_CSWAP; - } - for (int i = 0; i < (index == 8 ? 2 : 3); i++) - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - int tmpi = atoi(tmp); - if (tmpi >= *qubitCount) - { - fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated quantum bits.\n", line, tmpi); - return 0; - } - switch (i) - { - case 0: a0 = tmpi; break; - case 1: a1 = tmpi; break; - case 2: a2 = tmpi; break; - } - } - if (index == 8) - { - *binarySize += 3; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 3] = instr; - (*binary)[(*binarySize) - 2] = a0; - (*binary)[(*binarySize) - 1] = a1; - } - else - { - *binarySize += 4; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 4] = instr; - (*binary)[(*binarySize) - 3] = a0; - (*binary)[(*binarySize) - 2] = a1; - (*binary)[(*binarySize) - 1] = a2; - } - } - else if (index == 10) //if instructions + if (optimizationSettings < QANSEL_MODE_BARE || optimizationSettings > QANSEL_MODE_METAL_THREADED) { - if (*bitCount == 0) - { - fprintf(stderr, "QAnsel on line %i: Classical bit instruction used prior to initialization.\n", line); - return 0; - } - int rmp = 1; - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - if (strlen > 0) - { - strbeg = regmatches[rmp].rm_so; - strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - a0 = atoi(tmp); - if (a0 >= *bitCount) - { - fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated classical bits.\n", line, a0); - return 0; - } - a0 += 0x10; - } - else - { - a0 = 0x1F; - } - } - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strlen == 0) - { - strbeg = regmatches[rmp].rm_so; - strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strcmp(tmp, "==") == 0) instr = QANSEL_INSTRUCTION_IF_E; - else if (strcmp(tmp, "!=") == 0) instr = QANSEL_INSTRUCTION_IF_NE; - else if (strcmp(tmp, "<>") == 0) instr = QANSEL_INSTRUCTION_IF_NE; - else if (strcmp(tmp, ">=") == 0) instr = QANSEL_INSTRUCTION_IF_GE; - else if (strcmp(tmp, "<=") == 0) instr = QANSEL_INSTRUCTION_IF_LE; - else if (strcmp(tmp, ">") == 0) instr = QANSEL_INSTRUCTION_IF_G; - else if (strcmp(tmp, "<") == 0) instr = QANSEL_INSTRUCTION_IF_L; - } - else - { - if (strcmp(tmp, "==") == 0) instr = QANSEL_INSTRUCTION_IF_E; - else if (strcmp(tmp, "!=") == 0) instr = QANSEL_INSTRUCTION_IF_NE; - else if (strcmp(tmp, "<>") == 0) instr = QANSEL_INSTRUCTION_IF_NE; - else if (strcmp(tmp, ">=") == 0) instr = QANSEL_INSTRUCTION_IF_GE; - else if (strcmp(tmp, "<=") == 0) instr = QANSEL_INSTRUCTION_IF_LE; - else if (strcmp(tmp, ">") == 0) instr = QANSEL_INSTRUCTION_IF_G; - else if (strcmp(tmp, "<") == 0) instr = QANSEL_INSTRUCTION_IF_L; - } - } - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - s0 = (unsigned short)atoi(tmp); - } - //printf("%s(%02x,%i)\n", qansel_instruction_to_string(instr), a0, s0); - *binarySize += 2 + sizeof(unsigned short); - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 2 - sizeof(unsigned short)] = instr; - (*binary)[(*binarySize) - 1 - sizeof(unsigned short)] = a0; - memcpy((*binary) + ((*binarySize) - sizeof(unsigned short)), &s0, sizeof(unsigned short)); + fprintf(stderr, "QAnsel: Invalid optimization settings.\n"); + exit(1); } - else if (index == 11) //floating point settings + QANSEL_MODE = optimizationSettings; + + if (maximumQubitSettings <= 0 || maximumQubitSettings > QANSEL_QUBITS_MAX) { - int rmp = 1; - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strcmp(tmp, "hvar") == 0) instr = QANSEL_INSTRUCTION_HVAR; - } - { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (!qansel_parse_float(tmp, &d0)) - { - fprintf(stderr, "QAnsel on line %i: Syntax error.\n", line); - return 0; - } - } - *binarySize += 1 + sizeof(float); - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 1 - sizeof(float)] = instr; - memcpy((*binary) + ((*binarySize) - sizeof(float)), &d0, sizeof(float)); + fprintf(stderr, "QAnsel: Invalid limit for quantum bits.\n"); + exit(1); } - else if (index == 12) //lone instructions + QANSEL_QUBIT_LIMIT = maximumQubitSettings; + + if (hardwarerngSetting == 1) { - int rmp = 1; + QANSEL_RANDOM_FILE = fopen("/dev/TrueRNG0", "r"); + if (QANSEL_RANDOM_FILE == NULL) { - int strbeg = regmatches[rmp].rm_so; - int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; - rmp++; - char tmp[strlen + 1]; - memcpy(tmp, chunk + strbeg, strlen); - tmp[strlen] = 0; - if (strcmp(tmp, "rand") == 0) instr = QANSEL_INSTRUCTION_RAND; - else if (strcmp(tmp, "exit") == 0) instr = QANSEL_INSTRUCTION_EXIT; + fprintf(stderr, "QAnsel: No supported hardware random number generator found.\n"); + exit(1); } - *binarySize += 1; - *binary = realloc(*binary, (*binarySize)); - (*binary)[(*binarySize) - 1] = instr; } - return 1; -} - -int qansel_process_chunks(char** chunks, int* associatedLines, int count) -{ - unsigned char* binary = malloc(0); - int binarySize = 0; - int qubitCount = 0; - int bitCount = 0; - char errbuf[100]; - regex_t regex; - regmatch_t regmatches[10]; - const char regexes[][1024] = + + if (QANSEL_MODE == QANSEL_MODE_METAL || QANSEL_MODE == QANSEL_MODE_METAL_THREADED) { - "^\\s*qreg\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*$", - "^\\s*creg\\s*c\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*$", - "^\\s*(x|y|z|h|s|t|reset|barrier|born|density|print)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", - "^\\s*(rx|ry|rz|u1)\\(\\s*([-/0-9PI.]*)\\s*\\)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", - "^\\s*(u2)\\(\\s*([-/0-9PI.]*)\\s*,\\s*([-/0-9PI.]*)\\s*\\)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", - "^\\s*(u|u3)\\(\\s*([-/0-9PI.]*)\\s*,\\s*([-/0-9PI.]*)\\s*,\\s*([-/0-9PI.]*)\\s*\\)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", - "^\\s*measure\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*)\\s*->\\s*c\\c*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*)$", - //"^\\s*measure\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)\\s*->\\s*c\\c*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", - "^\\s*(sample|reset|print)\\s*c\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", - "^\\s*(cx|cnot|swap)\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*,\\s*q\\s*\\[\\s*([0-9]*)\\s*\\]\\s*$", - "^\\s*(ccx|toffoli|cswap|fredkin)\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*,\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*,\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*$", - "^\\s*if\\s*\\(\\s*c\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]|)\\s*(==|!=|<>|>=|<=|>|<)\\s*([0-9][0-9]*)\\s*\\).*\\s*$", - "^\\s*(hvar)\\s*([-/0-9PI.]*)\\s*$", - "^\\s*(rand|exit)\\s*$", - }; - int ret, status = 0, found; - for (int i = 0; i < count; i++) - { - found = 0; - for (int j = 0; j < sizeof(regexes) / sizeof(regexes[0]); j++) + if (!cpx_mtx_begin()) { - if (regcomp(®ex, regexes[j], REG_EXTENDED | REG_ICASE)) - { - printf("QAnsel: Regex fatal error.\n"); - exit(1); - } - ret = regexec(®ex, chunks[i], 10, regmatches, 0); - regfree(®ex); - if (!ret) - { - found = 1; - status = qansel_process_chunk(j, chunks[i], associatedLines[i], regmatches, &qubitCount, &bitCount, &binary, &binarySize); - break; - } - else if (ret == REG_NOMATCH) {} - else - { - regerror(ret, ®ex, errbuf, sizeof(errbuf)); - fprintf(stderr, "QAnsel: %s.\n", errbuf); - exit(1); - } - } - if (!status) break; - if (!found) - { - fprintf(stderr, "QAnsel on line %i: Invalid syntax.\n", associatedLines[i]); - return 0; + fprintf(stderr, "QAnsel: No supported hardware accelerator found.\n"); + exit(1); } } - qansel_execute(binary, binarySize); - free(binary); -} - -void main(int argc, char** argv) -{ - MODE = MODE_METAL_THREADED; - unsigned char err = cpx_mtx_begin(); - if (err == 0 && (MODE == MODE_METAL_THREADED || MODE == MODE_METAL)) - { - MODE = MODE == MODE_METAL_THREADED ? MODE_THREADED : MODE_BARE; - } - RANDOM_FILE = fopen("/dev/TrueRNG0", "r"); - if (!RANDOM_FILE) RANDOM_FILE = fopen("/dev/random", "r"); - char* script = malloc(0); size_t scriptSize = 0; int c; @@ -757,19 +73,16 @@ void main(int argc, char** argv) script = realloc(script, scriptSize + 1); script[scriptSize++] = 0; - char** chunks; - int* chunksAssociatedLines; - int chunksCount; - qansel_read_script(script, &chunks, &chunksAssociatedLines, &chunksCount); - qansel_process_chunks(chunks, chunksAssociatedLines, chunksCount); - for (int i = 0; i < chunksCount; i++) free(chunks[i]); - free(chunks); - free(chunksAssociatedLines); - free(script); - - fclose(RANDOM_FILE); + unsigned char* bytecode; + int bytecodeSize; + if (qanselBuildFromSource(script, &bytecode, &bytecodeSize)) + { + qanselExecuteBytecode(bytecode, bytecodeSize); + } + free(bytecode); - if (MODE_METAL || MODE_METAL_THREADED) cpx_mtx_clean(); + if (QANSEL_RANDOM_FILE != NULL) fclose(QANSEL_RANDOM_FILE); + if (QANSEL_MODE == QANSEL_MODE_METAL || QANSEL_MODE == QANSEL_MODE_METAL_THREADED) cpx_mtx_clean(); return; } \ No newline at end of file diff --git a/src/bytecode.c b/src/bytecode.c new file mode 100644 index 0000000..63cf248 --- /dev/null +++ b/src/bytecode.c @@ -0,0 +1,1064 @@ +typedef struct +{ + char n[128]; + unsigned char q0, q1, q2; + float arg0, arg1, arg2; +} QInstr; + +const char* qansel_instruction_to_string(unsigned char instr) +{ + switch (instr) + { + case QANSEL_INSTRUCTION_X: return "QANSEL_INSTRUCTION_X"; + case QANSEL_INSTRUCTION_Y: return "QANSEL_INSTRUCTION_Y"; + case QANSEL_INSTRUCTION_Z: return "QANSEL_INSTRUCTION_Z"; + case QANSEL_INSTRUCTION_H: return "QANSEL_INSTRUCTION_H"; + case QANSEL_INSTRUCTION_S: return "QANSEL_INSTRUCTION_S"; + case QANSEL_INSTRUCTION_T: return "QANSEL_INSTRUCTION_T"; + case QANSEL_INSTRUCTION_RX: return "QANSEL_INSTRUCTION_RX"; + case QANSEL_INSTRUCTION_RY: return "QANSEL_INSTRUCTION_RY"; + case QANSEL_INSTRUCTION_RZ: return "QANSEL_INSTRUCTION_RZ"; + case QANSEL_INSTRUCTION_U1: return "QANSEL_INSTRUCTION_U1"; + case QANSEL_INSTRUCTION_U2: return "QANSEL_INSTRUCTION_U2"; + case QANSEL_INSTRUCTION_U3: return "QANSEL_INSTRUCTION_U3"; + case QANSEL_INSTRUCTION_CX: return "QANSEL_INSTRUCTION_CX"; + case QANSEL_INSTRUCTION_SWAP: return "QANSEL_INSTRUCTION_SWAP"; + 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"; + case QANSEL_INSTRUCTION_IF_NE: return "QANSEL_INSTRUCTION_JUMP_NE"; + case QANSEL_INSTRUCTION_IF_G: return "QANSEL_INSTRUCTION_JUMP_G"; + 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_BARRIER: return "QANSEL_INSTRUCTION_BARRIER"; + case QANSEL_INSTRUCTION_EXIT: return "QANSEL_INSTRUCTION_EXIT"; + } + return "Unknown"; +} + +void qansel_rand_init() +{ + srand(time(NULL)); +} + +float qansel_rand_s(float s) +{ + unsigned int tmp; + memcpy(&tmp, &s, sizeof(unsigned int)); + srand(tmp); +} +float qansel_rand_h() +{ + return ((float)rand()) / ((float)RAND_MAX); +} +float qansel_rand_t() +{ + if (QANSEL_RANDOM_FILE) + { + unsigned int num = 0; + for (unsigned char i = 0; i < 4; i++) + { + num = (num << 8) | fgetc(QANSEL_RANDOM_FILE); + } + return ((float)num) / ((float)UINT32_MAX); + } + else + { + return qansel_rand_h(); + } +} + +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; + unsigned int retLen = (unsigned int)pow(2, qubitCount); + cpx_mtx_t ret; + cpx_mtx_init(&ret, 1, retLen); + cpx_t n; + for (unsigned int i = 0; i < retLen; i++) + { + unsigned char bitAVal = (i >> bitA) & 1; + unsigned char bitBVal = (i >> bitB) & 1; + unsigned char bitBNew = bitAVal ? !bitBVal : bitBVal; + unsigned int j = (i & ~(1 << bitB)) | (bitBNew << bitB); + cpx_mtx_get(stateVector, 0, i, &n); + cpx_mtx_set(&ret, 0, j, &n); + } + cpx_mtx_free(stateVector); + stateVector->ptr = ret.ptr; + stateVector->rows = ret.rows; + stateVector->cols = ret.cols; +} + +void qansel_swap(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB) +{ + if (bitA >= qubitCount || bitB >= qubitCount) return; + unsigned int retLen = (unsigned int)pow(2, qubitCount); + cpx_mtx_t ret; + cpx_mtx_init(&ret, 1, retLen); + cpx_t n; + for (unsigned int i = 0; i < retLen; i++) + { + unsigned char bitAVal = (i >> bitA) & 1; + unsigned char bitBVal = (i >> bitB) & 1; + unsigned char bitANew = bitBVal; + unsigned char bitBNew = bitAVal; + unsigned int j = (i & ~((1 << bitA) | (1 << bitB))) | ((bitANew << bitA) | (bitBNew << bitB)); + cpx_mtx_get(stateVector, 0, i, &n); + cpx_mtx_set(&ret, 0, j, &n); + } + cpx_mtx_free(stateVector); + stateVector->ptr = ret.ptr; + stateVector->rows = ret.rows; + stateVector->cols = ret.cols; +} + +void qansel_fredkin(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB, unsigned char bitC) +{ + if (bitA >= qubitCount || bitB >= qubitCount) return; + unsigned int retLen = (unsigned int)pow(2, qubitCount); + cpx_mtx_t ret; + cpx_mtx_init(&ret, 1, retLen); + cpx_t n; + for (unsigned int i = 0; i < retLen; i++) + { + unsigned char bitAVal = (i >> bitA) & 1; + unsigned char bitBVal = (i >> bitB) & 1; + unsigned char bitCVal = (i >> bitC) & 1; + unsigned char bitBNew = bitAVal ? bitCVal : bitBVal; + unsigned char bitCNew = bitAVal ? bitBVal : bitCVal; + unsigned int j = (i & ~((1 << bitB) | (1 << bitC))) | ((bitBNew << bitB) | (bitCNew << bitC)); + cpx_mtx_get(stateVector, 0, i, &n); + cpx_mtx_set(&ret, 0, j, &n); + } + cpx_mtx_free(stateVector); + stateVector->ptr = ret.ptr; + stateVector->rows = ret.rows; + stateVector->cols = ret.cols; +} + + +void qansel_toffoli(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB, unsigned char bitC) +{ + if (bitA >= qubitCount || bitB >= qubitCount) return; + unsigned int retLen = (unsigned int)pow(2, qubitCount); + cpx_mtx_t ret; + cpx_mtx_init(&ret, 1, retLen); + cpx_t n; + for (unsigned int i = 0; i < retLen; i++) + { + unsigned char bitAVal = (i >> bitA) & 1; + unsigned char bitBVal = (i >> bitB) & 1; + unsigned char bitCVal = (i >> bitC) & 1; + unsigned char bitCNew = (bitAVal && bitBVal) ? !bitCVal : bitCVal; + unsigned int j = (i & ~(1 << bitC)) | (bitCNew << bitC); + cpx_mtx_get(stateVector, 0, i, &n); + cpx_mtx_set(&ret, 0, j, &n); + } + cpx_mtx_free(stateVector); + stateVector->ptr = ret.ptr; + stateVector->rows = ret.rows; + stateVector->cols = ret.cols; +} + +float* qansel_unitary(float theta, float phi, float lambda) +{ + cpx_mtx_t m; + cpx_t a, b, c, d; + a.real = cos(theta/2.0); + a.imaginary = 0; + b.real = -cos(lambda) * sin(theta/2.0); + b.imaginary = sin(lambda) * sin(theta/2.0); + c.real = cos(phi) * sin(theta/2.0); + c.imaginary = sin(phi) * sin(theta/2.0); + d.real = cos(phi + lambda) * cos(theta/2.0); + d.imaginary = sin(phi + lambda) * cos(theta/2.0); + cpx_mtx_init(&m, 2, 2); + cpx_mtx_set(&m, 0, 0, &a); + cpx_mtx_set(&m, 0, 1, &b); + cpx_mtx_set(&m, 1, 0, &c); + cpx_mtx_set(&m, 1, 1, &d); + return m.ptr; +} + +void qansel_instruction +( + cpx_mtx_t* stateVector, + int qubitCount, + unsigned char instr, + unsigned char index, + float arg0, + float arg1, + float arg2 +) +{ + cpx_mtx_t tmp; + cpx_mtx_t gate; + gate.rows = 2; + gate.cols = 2; + float* gate_ptr; + switch (instr) + { + case QANSEL_INSTRUCTION_H: gate_ptr = Hadamard; break; + case QANSEL_INSTRUCTION_X: gate_ptr = PauliX; break; + case QANSEL_INSTRUCTION_Y: gate_ptr = PauliY; break; + case QANSEL_INSTRUCTION_Z: gate_ptr = PauliZ; break; + case QANSEL_INSTRUCTION_S: gate_ptr = PhaseS; break; + case QANSEL_INSTRUCTION_T: gate_ptr = PhaseT; break; + case QANSEL_INSTRUCTION_RX: + case QANSEL_INSTRUCTION_RY: + case QANSEL_INSTRUCTION_RZ: + case QANSEL_INSTRUCTION_U1: + case QANSEL_INSTRUCTION_U2: + case QANSEL_INSTRUCTION_U3: + gate_ptr = qansel_unitary(arg0, arg1, arg2); + break; + default: gate_ptr = Identity; break; + } + + cpx_t n; + cpx_mtx_t filter; + cpx_mtx_init(&filter, 2, 2); + unsigned char qubit = qubitCount - (index) - 1; + if (qubit == 0) + { + memcpy(filter.ptr, gate_ptr, 8 * sizeof(float)); + } + else + { + memcpy(filter.ptr, Identity, 8 * sizeof(float)); + } + + for (unsigned char i = 1; i < qubitCount; i++) + { + if (index != 0x0F) + { + if (qubit == i) + { + gate.ptr = gate_ptr; + } + else + { + gate.ptr = Identity; + } + } + else + { + gate.ptr = gate_ptr; + } + + tmp.rows = filter.rows * gate.rows; + tmp.cols = filter.cols * gate.cols; + tmp.ptr = malloc(tmp.rows * (tmp.cols * 2) * sizeof(float)); + + #ifdef SPEED_TEST + printf("(%ix%i);(%ix%i) (knk)\n", tmp.rows, tmp.cols, gate.rows, gate.cols); + unsigned long int us1, us2; + us1 = get_time(); + cpx_mtx_knk_metal(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + us2 = get_time(); + printf("\tMetal: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_knk_metal_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + us2 = get_time(); + printf("\tMetal2x2: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_knk_threads(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + us2 = get_time(); + printf("\tThreads: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_knk_threads_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + us2 = get_time(); + printf("\tThreads2x2: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_knk(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + us2 = get_time(); + printf("\tBare: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_knk_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + us2 = get_time(); + printf("\tBare2x2: %lu\n", us2 - us1); + + //us1 = get_time(); + //cpx_mtx_knk(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + //us2 = get_time(); + //printf("\tTranspose: %lu\n", us2 - us1); + #else + if (QANSEL_MODE == QANSEL_MODE_METAL && 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 || QANSEL_MODE == QANSEL_MODE_METAL_THREADED) && tmp.cols >= 64) + { + cpx_mtx_knk_threads_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + } + else + { + cpx_mtx_knk_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); + } + #endif + + free(filter.ptr); + filter.ptr = tmp.ptr; + filter.rows = tmp.rows; + filter.cols = tmp.cols; + } + + cpx_mtx_init(&tmp, stateVector->rows, stateVector->cols); + + #ifdef SPEED_TEST + printf("%ix%i (dot)\n", tmp.rows, tmp.cols); + unsigned long int us1, us2; + us1 = get_time(); + cpx_mtx_dot_metal(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); + us2 = get_time(); + printf("\tMetal: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_dot_threads(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); + us2 = get_time(); + printf("\tThreads: %lu\n", us2 - us1); + us1 = get_time(); + cpx_mtx_dot(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); + us2 = get_time(); + printf("\tBare: %lu\n", us2 - us1); + #else + if ((QANSEL_MODE == QANSEL_MODE_METAL || QANSEL_MODE == QANSEL_MODE_METAL_THREADED) && 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) + { + cpx_mtx_dot_threads(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); + } + else + { + cpx_mtx_dot(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); + } + #endif + free(stateVector->ptr); + stateVector->ptr = tmp.ptr; + free(filter.ptr); + if (instr == QANSEL_INSTRUCTION_U1 || instr == QANSEL_INSTRUCTION_U2 || instr == QANSEL_INSTRUCTION_U3) + { + free(gate_ptr); + } +} + +unsigned char qansel_measure(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char qubit) +{ + unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); + cpx_t n; + float prob0 = 0; + for (unsigned int i = 0; i < qubitCountPow2; i++) + { + unsigned char bit = (i >> qubit) & 1; + cpx_mtx_get(stateVector, 0, i, &n); + if (bit == 0) prob0 += cpx_magsqr(&n); + } + + float r = qansel_rand(); + unsigned char newBit = r < prob0 ? 0 : 1; + float probTot = 0; + for (unsigned int i = 0; i < qubitCountPow2; i++) + { + unsigned char bit = (i >> qubit) & 1; + cpx_mtx_get(stateVector, 0, i, &n); + if (bit != newBit) + { + n.real = 0; + n.imaginary = 0; + } + else + { + probTot += cpx_magsqr(&n); + } + cpx_mtx_set(stateVector, 0, i, &n); + } + + float multiplier = sqrt(1 / probTot); + for (unsigned int i = 0; i < qubitCountPow2; i++) + { + unsigned char bit = (i >> qubit) & 1; + cpx_mtx_get(stateVector, 0, i, &n); + if (bit == newBit) + { + n.real *= multiplier; + n.imaginary *= multiplier; + } + cpx_mtx_set(stateVector, 0, i, &n); + } + + return newBit; +} + +int qansel_get_instruction_bitmax(unsigned char* ptr, int offset, int* bitmax, int* qbitmax) +{ + unsigned char a0, a1, a2; + *bitmax = 0; + *qbitmax = 0; + switch (ptr[offset]) + { + 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: + case QANSEL_INSTRUCTION_BARRIER: + case QANSEL_INSTRUCTION_DENSITY: + case QANSEL_INSTRUCTION_BORN: + a0 = ptr[offset + 1]; + if (a0 > 0x0D && a0 != 0x0F) return 0; + if (a0 != 0x0F) *qbitmax = a0 + 1; + return 1; + case QANSEL_INSTRUCTION_SAMPLE: + 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: + a0 = ptr[offset + 1]; + if ((a0 > 0x1D || a0 < 0x10) && a0 != 0x1F) return 0; + if (a0 != 0x1F) *bitmax = (a0 - 0x10) + 1; + return 1; + case QANSEL_INSTRUCTION_RESET: + case QANSEL_INSTRUCTION_PRINT: + a0 = ptr[offset + 1]; + if (a0 == 0xFF) return 1; + if (a0 < 0x10) + { + if (a0 > 0x0D && a0 != 0x0F) return 0; + if (a0 != 0x0F) *qbitmax = a0 + 1; + return 1; + } + else + { + if ((a0 > 0x1D || a0 < 0x10) && a0 != 0x1F) return 0; + if (a0 != 0x1F) *bitmax = (a0 - 0x10) + 1; + return 1; + } + return 0; + case QANSEL_INSTRUCTION_CX: + case QANSEL_INSTRUCTION_SWAP: + a0 = ptr[offset + 1]; + a1 = ptr[offset + 2]; + if (a0 > 0x0D) return 0; + if (a1 > 0x0D) return 0; + *qbitmax = (a0 > a1 ? a0 : a1) + 1; + return 1; + case QANSEL_INSTRUCTION_CCX: + case QANSEL_INSTRUCTION_CSWAP: + a0 = ptr[offset + 1]; + a1 = ptr[offset + 2]; + a2 = ptr[offset + 3]; + if (a0 > 0x0D || a1 > 0x0D || a2 > 0x0D) return 0; + *qbitmax = ((a0 > a1) && (a0 > a2) ? a0 : ((a1 > a0) && (a1 > a2) ? a1 : a2)) + 1; + return 1; + case QANSEL_INSTRUCTION_MEASURE: + a0 = ptr[offset + 1]; + a1 = ptr[offset + 2]; + if (a0 > 0x0D) return 0; + if (a1 > 0x1D || a1 < 0x10) return 0; + *qbitmax = a0 + 1; + *bitmax = (a1 - 0x10) + 1; + return 1; + case QANSEL_INSTRUCTION_RAND: + case QANSEL_INSTRUCTION_HVAR: + case QANSEL_INSTRUCTION_EXIT: + return 1; + } + return 0; +} + +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; + } + return 0; +} + +void qansel_born(cpx_mtx_t* stateVector, int PC, int qubitCount, unsigned char q0) +{ + unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); + if (q0 == 0x0F) + { + for (unsigned int j = 0; j < qubitCountPow2; j++) + { + unsigned int tmp = j; + for (unsigned char k = 0; k < qubitCount; k++) + { + putchar('0' + (tmp >> (qubitCount - 1) & 1)); + tmp <<= 1; + } + cpx_t n; + cpx_mtx_get(stateVector, 0, j, &n); + printf(": %.1f%%\n", cpx_magsqr(&n) * 100); + } + } + else if (q0 <= 0x0D) + { + float prob = 0; + for (unsigned int j = 0; j < qubitCountPow2; j++) + { + cpx_t n; + cpx_mtx_get(stateVector, 0, j, &n); + if ((j >> q0) & 1) + { + prob += cpx_magsqr(&n); + } + } + printf("0: %.1f%%\n", (1 - prob) * 100.0); + printf("1: %.1f%%\n", prob * 100.0); + } +} + +void qansel_density_or_print(cpx_mtx_t* stateVector, unsigned char* bitVector, unsigned char density, int bitCount, int qubitCount, unsigned char a0) +{ + unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); + if (a0 == 0x0F || a0 == 0x1F || a0 == 0xFF) + { + if (a0 == 0x0F || a0 == 0xFF) + { + printf("[ "); cpx_mtx_print(stateVector); printf(" ]\n"); + } + if (a0 == 0x1F || a0 == 0xFF) + { + for (int32_t j = bitCount - 1; j >= 0; j--) + { + putchar('0' + bitVector[j]); + } + putchar('\n'); + } + } + else if (a0 >= 0x10 && a0 <= 0x1D) + { + putchar('0' + bitVector[a0 - 0x10]); + putchar('\n'); + } + else + { + cpx_mtx_t tmp; + cpx_mtx_init(&tmp, 1, 2); + for (unsigned int j = 0; j < qubitCountPow2; j++) + { + if ((j >> a0) & 1) + { + cpx_t a, b; + cpx_mtx_get(&tmp, 0, 1, &a); + cpx_mtx_get(stateVector, 0, j, &b); + a.real += b.real; + a.imaginary += b.imaginary; + cpx_mtx_set(&tmp, 0, 1, &a); + } + else + { + cpx_t a, b; + cpx_mtx_get(&tmp, 0, 0, &a); + cpx_mtx_get(stateVector, 0, j, &b); + a.real += b.real; + a.imaginary += b.imaginary; + cpx_mtx_set(&tmp, 0, 0, &a); + } + } + float multiplier = 0; + cpx_t n; + cpx_mtx_get(&tmp, 0, 0, &n); + multiplier += cpx_magsqr(&n); + cpx_mtx_get(&tmp, 0, 1, &n); + multiplier += cpx_magsqr(&n); + multiplier = sqrt(1 / multiplier); + n.real *= multiplier; + n.imaginary *= multiplier; + cpx_mtx_set(&tmp, 0, 1, &n); + cpx_mtx_get(&tmp, 0, 0, &n); + n.real *= multiplier; + n.imaginary *= multiplier; + cpx_mtx_set(&tmp, 0, 0, &n); + + if (density) + { + cpx_t a, b, c, d, x, y, z, w; + cpx_mtx_get(&tmp, 0, 0, &a); + cpx_mtx_get(&tmp, 0, 1, &b); + cpx_mtx_get(&tmp, 0, 0, &c); + cpx_mtx_get(&tmp, 0, 1, &d); + c.imaginary *= -1; + d.imaginary *= -1; + cpx_mul(&x, &a, &c); + cpx_mul(&y, &a, &d); + cpx_mul(&z, &b, &c); + cpx_mul(&w, &b, &d); + char* sx = cpx_str(&x); + char* sy = cpx_str(&y); + char* sz = cpx_str(&z); + char* sw = cpx_str(&w); + printf("[ %s, %s ]\n", sx, sy); + printf("[ %s, %s ]\n", sz, sw); + free(sx); + free(sy); + free(sz); + free(sw); + } + else + { + printf("[ "); cpx_mtx_print(&tmp); printf(" ]\n"); + } + cpx_mtx_free(&tmp); + } +} + +float qansel_get_float(unsigned char* program, int offset) +{ + float ret; + memcpy(&ret, program + offset, sizeof(float)); + return ret; +} + +short qansel_get_short(unsigned char* program, int offset) +{ + short ret; + memcpy(&ret, program + offset, sizeof(short)); + return ret; +} + +int qansel_get_int(unsigned char* program, int offset) +{ + int ret; + memcpy(&ret, program + offset, sizeof(int)); + return ret; +} + +void qansel_reset(cpx_mtx_t* stateVector, unsigned char* bitVector, int qubitCount, int bitCount, unsigned char q0) +{ + unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); + if (q0 == 0xFF) + { + cpx_mtx_set2(stateVector, 0, 0, 1, 0); + for (unsigned int j = 1; j < qubitCountPow2; j++) + { + cpx_mtx_set2(stateVector, 0, j, 0, 0); + } + for (unsigned char j = 0; j < bitCount; j++) + { + bitVector[j] = 0; + } + } + else if (q0 == 0x0F) + { + cpx_mtx_set2(stateVector, 0, 0, 1, 0); + for (unsigned int j = 1; j < qubitCountPow2; j++) + { + cpx_mtx_set2(stateVector, 0, j, 0, 0); + } + } + else if (q0 == 0x1F) + { + for (unsigned char j = 0; j < bitCount; j++) + { + bitVector[j] = 0; + } + } + else if (q0 <= 0x0D) + { + unsigned char bit = qansel_measure(stateVector, qubitCount, q0); + if (bit) + { + qansel_instruction(stateVector, qubitCount, QANSEL_INSTRUCTION_X, q0, 0, 0, 0); + } + } + else if (q0 >= 0x10 && q0 <= 0x1D) + { + bitVector[q0 - 0x10] = 0; + } +} + +unsigned char qansel_compare(unsigned char* bitVector, int bitCount, int PC, unsigned char a0, short op) +{ + unsigned char ret = 0; + short val; + if (a0 == 0x1F) + { + val = 0; + for (int32_t j = bitCount - 1; j >= 0; j--) + { + val = (val << 1) | bitVector[j]; + } + if (val == op) ret |= QANSEL_FLAGS_EQUAL; + if (val > op) ret |= QANSEL_FLAGS_GREATER; + if (val < op) ret |= QANSEL_FLAGS_LESSER; + } + else if (a0 >= 0x10 && a0 <= 0x1D) + { + val = bitVector[a0 - 0x10]; + if (val == op) ret |= QANSEL_FLAGS_EQUAL; + if (val > op) ret |= QANSEL_FLAGS_GREATER; + if (val < op) ret |= QANSEL_FLAGS_LESSER; + } + return ret; +} + +int qansel_crawl(unsigned char* program, int programSize, int* qubitCount, int* bitCount, int* sample) +{ + if (QANSEL_VERBOSE) printf("Crawling program . . .\n"); + int PC = 0; + *qubitCount = 0; + *bitCount = 0; + *sample = 0xFF; + while (PC < programSize) + { + int next = qansel_get_instruction_size(program[PC]); + if (program[PC] == QANSEL_INSTRUCTION_SAMPLE) + { + if ((program[PC + 1] < 0x10 || program[PC + 1] > 0x1D) && program[PC + 1] != 0x1F) + { + if (QANSEL_VERBOSE) fprintf(stderr, "QAnsel (%04X): Invalid index.\n", PC); + } + else + { + *sample = program[PC + 1] - 0x10; + } + } + if (next == 0) + { + printf("QAnsel (%04X): Invalid instruction 0x%02x.\n", PC, program[PC]); + return 0; + } + int bitmax, qbitmax; + int success = qansel_get_instruction_bitmax(program, PC, &bitmax, &qbitmax); + if (!success) + { + fprintf(stderr, "QAnsel (%04X): Invalid index.\n", PC); + return 0; + } + if (bitmax > *bitCount) *bitCount = bitmax; + 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); + return 1; +} + +void qansel_run(unsigned char* program, int programSize, int qubitCount, int bitCount, unsigned char* outputBitVector) +{ + int PC = 0; + unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); + unsigned char bitVector[bitCount]; + memset(bitVector, 0, bitCount); + cpx_mtx_t stateVector; + cpx_mtx_init(&stateVector, 1, qubitCountPow2); + cpx_mtx_set2(&stateVector, 0, 0, 1, 0); + if (QANSEL_USE_DISPLAY) { QANSEL_USE_DISPLAY = display(&stateVector, qubitCount, QANSEL_USE_DISPLAY); } + unsigned char skip = 0, a0 = 0, a1 = 0, a2 = 0; + unsigned char flags = 0; + unsigned short tmp = 0; + + while (PC < programSize) + { + //printf("%i;%i\n", PC, programSize); + int next = qansel_get_instruction_size(program[PC]); + if (skip) + { + skip = 0; + } + else + { + unsigned char instr = program[PC]; + //printf("-----------------------------------\n"); + //qansel_density_or_print(&stateVector, bitVector, 0, bitCount, qubitCount, 0x0F); + //qansel_density_or_print(&stateVector, bitVector, 0, bitCount, qubitCount, 0x1F); + //printf("%s(%i, %i, %i)(%f, %f, %f)\n", qansel_instruction_to_string(instr), program[PC+1], program[PC+2], program[PC], qansel_get_float(program, PC + 2), qansel_get_float(program, PC + 2 + sizeof(float)), qansel_get_float(program, PC + 2) + sizeof(float) * 2); + switch (instr) + { + case QANSEL_INSTRUCTION_X: + case QANSEL_INSTRUCTION_Y: + case QANSEL_INSTRUCTION_Z: + case QANSEL_INSTRUCTION_H: + case QANSEL_INSTRUCTION_S: + case QANSEL_INSTRUCTION_T: + a0 = program[PC + 1]; + qansel_instruction(&stateVector, qubitCount, instr, program[PC + 1], 0, 0, 0); + break; + case QANSEL_INSTRUCTION_RX: + a0 = program[PC + 1]; + qansel_instruction + ( + &stateVector, qubitCount, instr, a0, + M_PI / 2, -M_PI / 2, qansel_get_float(program, PC + 2) - (M_PI / 2) + ); + break; + case QANSEL_INSTRUCTION_RY: + case QANSEL_INSTRUCTION_U1: + a0 = program[PC + 1]; + qansel_instruction + ( + &stateVector, qubitCount, instr, a0, + qansel_get_float(program, PC + 2), 0, 0 + ); + break; + case QANSEL_INSTRUCTION_RZ: + a0 = program[PC + 1]; + qansel_instruction + ( + &stateVector, qubitCount, instr, a0, + 0, 0, qansel_get_float(program, PC + 2) + ); + break; + case QANSEL_INSTRUCTION_U2: + a0 = program[PC + 1]; + qansel_instruction + ( + &stateVector, qubitCount, instr, a0, + qansel_get_float(program, PC + 2), + qansel_get_float(program, PC + 2 + sizeof(float)), + 0 + ); + break; + case QANSEL_INSTRUCTION_U3: + a0 = program[PC + 1]; + qansel_instruction + ( + &stateVector, qubitCount, instr, a0, + qansel_get_float(program, PC + 2), + qansel_get_float(program, PC + 2 + sizeof(float)), + qansel_get_float(program, PC + 2 + sizeof(float) * 2) + ); + break; + case QANSEL_INSTRUCTION_CX: + a0 = program[PC + 1]; + a1 = program[PC + 2]; + qansel_cnot(&stateVector, qubitCount, a0, a1); + break; + case QANSEL_INSTRUCTION_SWAP: + a0 = program[PC + 1]; + a1 = program[PC + 2]; + qansel_swap(&stateVector, qubitCount, a0, a1); + break; + case QANSEL_INSTRUCTION_CCX: + a0 = program[PC + 1]; + a1 = program[PC + 2]; + a2 = program[PC + 3]; + qansel_toffoli(&stateVector, qubitCount, a0, a1, a2); + break; + case QANSEL_INSTRUCTION_CSWAP: + a0 = program[PC + 1]; + a1 = program[PC + 2]; + a2 = program[PC + 3]; + qansel_fredkin(&stateVector, qubitCount, a0, a1, a2); + break; + case QANSEL_INSTRUCTION_MEASURE: + a0 = program[PC + 1]; + a1 = program[PC + 2] - 0x10; + bitVector[a1] = qansel_measure(&stateVector, qubitCount, a0); + break; + case QANSEL_INSTRUCTION_BORN: + a0 = program[PC + 1]; + qansel_born(&stateVector, PC, qubitCount, a0); + break; + case QANSEL_INSTRUCTION_DENSITY: + a0 = program[PC + 1]; + qansel_density_or_print(&stateVector, bitVector, 1, bitCount, qubitCount, a0); + break; + case QANSEL_INSTRUCTION_PRINT: + a0 = program[PC + 1]; + qansel_density_or_print(&stateVector, bitVector, 0, bitCount, qubitCount, a0); + break; + case QANSEL_INSTRUCTION_BARRIER: + a0 = program[PC + 1]; + 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; + break; + case QANSEL_INSTRUCTION_IF_E: + a0 = program[PC + 1]; + tmp = qansel_get_short(program, PC + 2); + flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); + skip = 1; if (flags & QANSEL_FLAGS_EQUAL) skip = 0; + break; + case QANSEL_INSTRUCTION_IF_NE: + a0 = program[PC + 1]; + tmp = qansel_get_short(program, PC + 2); + flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); + skip = 1; if (!(flags & QANSEL_FLAGS_EQUAL)) skip = 0; + break; + case QANSEL_INSTRUCTION_IF_G: + a0 = program[PC + 1]; + tmp = qansel_get_short(program, PC + 2); + flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); + skip = 1; if (flags & QANSEL_FLAGS_GREATER) skip = 0; + break; + case QANSEL_INSTRUCTION_IF_GE: + a0 = program[PC + 1]; + tmp = qansel_get_short(program, PC + 2); + flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); + skip = 1; if ((flags & QANSEL_FLAGS_GREATER) && (flags & QANSEL_FLAGS_EQUAL)) skip = 0; + break; + case QANSEL_INSTRUCTION_IF_L: + a0 = program[PC + 1]; + tmp = qansel_get_short(program, PC + 2); + flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); + skip = 1; if (flags & QANSEL_FLAGS_LESSER) skip = 0; + break; + case QANSEL_INSTRUCTION_IF_LE: + a0 = program[PC + 1]; + tmp = qansel_get_short(program, PC + 2); + 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 (outputBitVector != NULL) + { + for (int i = 0; i < bitCount; i++) + { + outputBitVector[i] = bitVector[i]; + } + } + cpx_mtx_free(&stateVector); + if (QANSEL_USE_DISPLAY) { display(NULL, 0, 0); } + +} + +int qanselExecuteBytecode(unsigned char* buff, int sizeofbuff) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + float seed = (float)((unsigned long)ts.tv_sec * 1000000000LL + ts.tv_nsec); + qansel_rand_s(seed); + + unsigned short vals; + float valf; + int pos = 0; + + int qubitCount, bitCount, sample; + if (!qansel_crawl(buff, sizeofbuff, &qubitCount, &bitCount, &sample)) + { + return 0; + } + + if (sample != 0xFF) + { + unsigned short stats[65536]; + for (unsigned int i = 0; i < (1 << bitCount); i++) + { + stats[i] = 0; + } + unsigned char bitVect[bitCount]; + memset(bitVect, 0, bitCount); + for (int i = 0; i < bitCount; i++) bitVect[i] = 0; + unsigned int shots = 1000; + for (unsigned int i = 0; i < shots; i++) + { + qansel_run(buff, sizeofbuff, qubitCount, bitCount, bitVect); + unsigned short stat = 0; + for (signed char j = bitCount - 1; j >= 0; j--) + { + stat = (stat << 1) | bitVect[j]; + } + stats[stat]++; + } + unsigned int count = 0; + for (unsigned int i = 0; i < (1 << bitCount); i++) + { + unsigned int tmp = i; + for (unsigned char j = 0; j < bitCount; j++) + { + unsigned char bit = (tmp >> (bitCount - 1) & 1); + if (j == (bitCount - sample - 1) && bit) + { + count += stats[i]; + } + if (sample == 0x0F) + { + putchar('0' + bit); + } + tmp <<= 1; + } + if (sample == 0x0F) + { + printf(": %.1f%%\n", ((float)stats[i] / (float)shots) * (float)100); + } + } + if (sample != 0x0F) + { + float prob = ((float)count / (float)shots) * (float)100; + printf("0: %.1f%%\n", ((float)100)-prob); + printf("1: %.1f%%\n", prob); + } + } + else + { + qansel_run(buff, sizeofbuff, qubitCount, bitCount, NULL); + } + return 1; +} diff --git a/src/complex.c b/src/complex.c index f9a57b7..c1ab4e6 100644 --- a/src/complex.c +++ b/src/complex.c @@ -90,6 +90,40 @@ void cpx_mtx_get(cpx_mtx_t* m, int row, int col, cpx_t* n) n->imaginary = m->ptr[row * ((m->cols) * 2) + (col * 2) + 1]; } +void cpx_mtx_copy(cpx_mtx_t* m, cpx_mtx_t* n) +{ + for (int i = 0; i < n->rows; i++) + { + for (int j = 0; j < n->cols; j++) + { + cpx_t tmp; + cpx_mtx_get(n, i, j, &tmp); + cpx_mtx_set(m, i, j, &tmp); + } + } +} + +int cpx_mtx_cmp(cpx_mtx_t* m, cpx_mtx_t* n) +{ + if (m->rows != n->rows) return -1; + if (m->cols != n->cols) return -2; + for (int i = 0; i < n->rows; i++) + { + for (int j = 0; j < n->cols; j++) + { + cpx_t tmp1; + cpx_t tmp2; + cpx_mtx_get(n, i, j, &tmp1); + cpx_mtx_get(m, i, j, &tmp2); + if (tmp1.real != tmp2.real || tmp1.imaginary != tmp2.imaginary) + { + return j + i * n->cols + 1; + } + } + } + return 0; +} + void cpx_mtx_init(cpx_mtx_t* m, int rows, int cols) { int z = rows * (cols * 2) * sizeof(float); @@ -733,8 +767,7 @@ void cpx_mtx_knk_metal_2x2(float* ptrR, float* ptrA, float* ptrB, int rowsA, int cl_mem memR = clCreateBuffer(cpx_mtx_context, CL_MEM_READ_ONLY, sizeR, NULL, &err); gpuerr(err); //Populate buffers - err = clEnqueueWriteBuffer(cpx_mtx_command_queue, memA, CL_TRUE, 0, sizeA, ptrA, 0, NULL, NULL); - gpuerr(err); + err = clEnqueueWriteBuffer(cpx_mtx_command_queue, memA, CL_TRUE, 0, sizeA, ptrA, 0, NULL, NULL); gpuerr(err); //Load and compile program cl_program program; diff --git a/src/core.c b/src/core.c deleted file mode 100644 index dc32ab2..0000000 --- a/src/core.c +++ /dev/null @@ -1,1107 +0,0 @@ -#include -#include -#include -#include -#include "complex.c" -#include "gates.c" -#include "display.c" -#include "chacha20.c" -#define QUBITS_MAX 14 -unsigned char HIDDEN_VARIABLE = 0; -FILE* RANDOM_FILE; -#define GPU_ENABLED -unsigned char USE_THREADS = 1; -#define MODE_BARE 1 -#define MODE_THREADED 2 -#define MODE_METAL 3 -#define MODE_METAL_THREADED 4 -unsigned char MODE = MODE_BARE; -//#define SPEED_TEST - -#define QANSEL_INSTRUCTION_X 0x10 -#define QANSEL_INSTRUCTION_Y 0x11 -#define QANSEL_INSTRUCTION_Z 0x12 -#define QANSEL_INSTRUCTION_H 0x13 -#define QANSEL_INSTRUCTION_S 0x14 -#define QANSEL_INSTRUCTION_T 0x15 -#define QANSEL_INSTRUCTION_RX 0x20 -#define QANSEL_INSTRUCTION_RY 0x21 -#define QANSEL_INSTRUCTION_RZ 0x22 -#define QANSEL_INSTRUCTION_U1 0x23 -#define QANSEL_INSTRUCTION_U2 0x24 -#define QANSEL_INSTRUCTION_U3 0x25 -#define QANSEL_INSTRUCTION_CX 0x30 -#define QANSEL_INSTRUCTION_SWAP 0x31 -#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_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_FLAGS_EQUAL 0b00001 -#define QANSEL_FLAGS_GREATER 0b00010 -#define QANSEL_FLAGS_LESSER 0b00100 -#define QANSEL_FLAGS_JUMPED 0b01000 -typedef struct -{ - char n[128]; - unsigned char q0, q1, q2; - float arg0, arg1, arg2; -} QInstr; - -const char* qansel_instruction_to_string(unsigned char instr) -{ - switch (instr) - { - case QANSEL_INSTRUCTION_X: return "QANSEL_INSTRUCTION_X"; - case QANSEL_INSTRUCTION_Y: return "QANSEL_INSTRUCTION_Y"; - case QANSEL_INSTRUCTION_Z: return "QANSEL_INSTRUCTION_Z"; - case QANSEL_INSTRUCTION_H: return "QANSEL_INSTRUCTION_H"; - case QANSEL_INSTRUCTION_S: return "QANSEL_INSTRUCTION_S"; - case QANSEL_INSTRUCTION_T: return "QANSEL_INSTRUCTION_T"; - case QANSEL_INSTRUCTION_RX: return "QANSEL_INSTRUCTION_RX"; - case QANSEL_INSTRUCTION_RY: return "QANSEL_INSTRUCTION_RY"; - case QANSEL_INSTRUCTION_RZ: return "QANSEL_INSTRUCTION_RZ"; - case QANSEL_INSTRUCTION_U1: return "QANSEL_INSTRUCTION_U1"; - case QANSEL_INSTRUCTION_U2: return "QANSEL_INSTRUCTION_U2"; - case QANSEL_INSTRUCTION_U3: return "QANSEL_INSTRUCTION_U3"; - case QANSEL_INSTRUCTION_CX: return "QANSEL_INSTRUCTION_CX"; - case QANSEL_INSTRUCTION_SWAP: return "QANSEL_INSTRUCTION_SWAP"; - 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"; - case QANSEL_INSTRUCTION_IF_NE: return "QANSEL_INSTRUCTION_JUMP_NE"; - case QANSEL_INSTRUCTION_IF_G: return "QANSEL_INSTRUCTION_JUMP_G"; - 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_BARRIER: return "QANSEL_INSTRUCTION_BARRIER"; - case QANSEL_INSTRUCTION_EXIT: return "QANSEL_INSTRUCTION_EXIT"; - } - return "Unknown"; -} -float qansel_rand_s(float s) -{ - unsigned int tmp; - memcpy(&tmp, &s, sizeof(unsigned int)); - srand(tmp); -} -float qansel_rand_h() -{ - return ((float)rand()) / ((float)RAND_MAX); -} -float qansel_rand_t() -{ - if (RANDOM_FILE) - { - unsigned int num = 0; - for (unsigned char i = 0; i < 4; i++) - { - num = (num << 8) | fgetc(RANDOM_FILE); - } - return ((float)num) / ((float)UINT32_MAX); - } - else - { - HIDDEN_VARIABLE = 1; - return qansel_rand_h(); - } -} - -float qansel_rand() -{ - return 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; - unsigned int retLen = (unsigned int)pow(2, qubitCount); - cpx_mtx_t ret; - cpx_mtx_init(&ret, 1, retLen); - cpx_t n; - for (unsigned int i = 0; i < retLen; i++) - { - unsigned char bitAVal = (i >> bitA) & 1; - unsigned char bitBVal = (i >> bitB) & 1; - unsigned char bitBNew = bitAVal ? !bitBVal : bitBVal; - unsigned int j = (i & ~(1 << bitB)) | (bitBNew << bitB); - cpx_mtx_get(stateVector, 0, i, &n); - cpx_mtx_set(&ret, 0, j, &n); - } - cpx_mtx_free(stateVector); - stateVector->ptr = ret.ptr; - stateVector->rows = ret.rows; - stateVector->cols = ret.cols; -} - -void qansel_swap(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB) -{ - if (bitA >= qubitCount || bitB >= qubitCount) return; - unsigned int retLen = (unsigned int)pow(2, qubitCount); - cpx_mtx_t ret; - cpx_mtx_init(&ret, 1, retLen); - cpx_t n; - for (unsigned int i = 0; i < retLen; i++) - { - unsigned char bitAVal = (i >> bitA) & 1; - unsigned char bitBVal = (i >> bitB) & 1; - unsigned char bitANew = bitBVal; - unsigned char bitBNew = bitAVal; - unsigned int j = (i & ~((1 << bitA) | (1 << bitB))) | ((bitANew << bitA) | (bitBNew << bitB)); - cpx_mtx_get(stateVector, 0, i, &n); - cpx_mtx_set(&ret, 0, j, &n); - } - cpx_mtx_free(stateVector); - stateVector->ptr = ret.ptr; - stateVector->rows = ret.rows; - stateVector->cols = ret.cols; -} - -void qansel_fredkin(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB, unsigned char bitC) -{ - if (bitA >= qubitCount || bitB >= qubitCount) return; - unsigned int retLen = (unsigned int)pow(2, qubitCount); - cpx_mtx_t ret; - cpx_mtx_init(&ret, 1, retLen); - cpx_t n; - for (unsigned int i = 0; i < retLen; i++) - { - unsigned char bitAVal = (i >> bitA) & 1; - unsigned char bitBVal = (i >> bitB) & 1; - unsigned char bitCVal = (i >> bitC) & 1; - unsigned char bitBNew = bitAVal ? bitCVal : bitBVal; - unsigned char bitCNew = bitAVal ? bitBVal : bitCVal; - unsigned int j = (i & ~((1 << bitB) | (1 << bitC))) | ((bitBNew << bitB) | (bitCNew << bitC)); - cpx_mtx_get(stateVector, 0, i, &n); - cpx_mtx_set(&ret, 0, j, &n); - } - cpx_mtx_free(stateVector); - stateVector->ptr = ret.ptr; - stateVector->rows = ret.rows; - stateVector->cols = ret.cols; -} - - -void qansel_toffoli(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char bitA, unsigned char bitB, unsigned char bitC) -{ - if (bitA >= qubitCount || bitB >= qubitCount) return; - unsigned int retLen = (unsigned int)pow(2, qubitCount); - cpx_mtx_t ret; - cpx_mtx_init(&ret, 1, retLen); - cpx_t n; - for (unsigned int i = 0; i < retLen; i++) - { - unsigned char bitAVal = (i >> bitA) & 1; - unsigned char bitBVal = (i >> bitB) & 1; - unsigned char bitCVal = (i >> bitC) & 1; - unsigned char bitCNew = (bitAVal && bitBVal) ? !bitCVal : bitCVal; - unsigned int j = (i & ~(1 << bitC)) | (bitCNew << bitC); - cpx_mtx_get(stateVector, 0, i, &n); - cpx_mtx_set(&ret, 0, j, &n); - } - cpx_mtx_free(stateVector); - stateVector->ptr = ret.ptr; - stateVector->rows = ret.rows; - stateVector->cols = ret.cols; -} - -float* qansel_unitary(float theta, float phi, float lambda) -{ - cpx_mtx_t m; - cpx_t a, b, c, d; - a.real = cos(theta/2.0); - a.imaginary = 0; - b.real = -cos(lambda) * sin(theta/2.0); - b.imaginary = sin(lambda) * sin(theta/2.0); - c.real = cos(phi) * sin(theta/2.0); - c.imaginary = sin(phi) * sin(theta/2.0); - d.real = cos(phi + lambda) * cos(theta/2.0); - d.imaginary = sin(phi + lambda) * cos(theta/2.0); - cpx_mtx_init(&m, 2, 2); - cpx_mtx_set(&m, 0, 0, &a); - cpx_mtx_set(&m, 0, 1, &b); - cpx_mtx_set(&m, 1, 0, &c); - cpx_mtx_set(&m, 1, 1, &d); - return m.ptr; -} - -void qansel_instruction -( - cpx_mtx_t* stateVector, - int qubitCount, - unsigned char instr, - unsigned char index, - float arg0, - float arg1, - float arg2 -) -{ - cpx_mtx_t tmp; - cpx_mtx_t gate; - gate.rows = 2; - gate.cols = 2; - float* gate_ptr; - switch (instr) - { - case QANSEL_INSTRUCTION_H: gate_ptr = Hadamard; break; - case QANSEL_INSTRUCTION_X: gate_ptr = PauliX; break; - case QANSEL_INSTRUCTION_Y: gate_ptr = PauliY; break; - case QANSEL_INSTRUCTION_Z: gate_ptr = PauliZ; break; - case QANSEL_INSTRUCTION_S: gate_ptr = PhaseS; break; - case QANSEL_INSTRUCTION_T: gate_ptr = PhaseT; break; - case QANSEL_INSTRUCTION_RX: - case QANSEL_INSTRUCTION_RY: - case QANSEL_INSTRUCTION_RZ: - case QANSEL_INSTRUCTION_U1: - case QANSEL_INSTRUCTION_U2: - case QANSEL_INSTRUCTION_U3: - gate_ptr = qansel_unitary(arg0, arg1, arg2); - break; - default: gate_ptr = Identity; break; - } - - cpx_t n; - cpx_mtx_t filter; - cpx_mtx_init(&filter, 2, 2); - unsigned char qubit = qubitCount - (index) - 1; - if (qubit == 0) - { - memcpy(filter.ptr, gate_ptr, 8 * sizeof(float)); - } - else - { - memcpy(filter.ptr, Identity, 8 * sizeof(float)); - } - - for (unsigned char i = 1; i < qubitCount; i++) - { - if (index != 0x0F) - { - if (qubit == i) - { - gate.ptr = gate_ptr; - } - else - { - gate.ptr = Identity; - } - } - else - { - gate.ptr = gate_ptr; - } - - tmp.rows = filter.rows * gate.rows; - tmp.cols = filter.cols * gate.cols; - tmp.ptr = malloc(tmp.rows * (tmp.cols * 2) * sizeof(float)); - - #ifdef SPEED_TEST - printf("(%ix%i);(%ix%i) (knk)\n", tmp.rows, tmp.cols, gate.rows, gate.cols); - unsigned long int us1, us2; - us1 = get_time(); - cpx_mtx_knk_metal(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - us2 = get_time(); - printf("\tMetal: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_knk_metal_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - us2 = get_time(); - printf("\tMetal2x2: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_knk_threads(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - us2 = get_time(); - printf("\tThreads: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_knk_threads_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - us2 = get_time(); - printf("\tThreads2x2: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_knk(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - us2 = get_time(); - printf("\tBare: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_knk_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - us2 = get_time(); - printf("\tBare2x2: %lu\n", us2 - us1); - - //us1 = get_time(); - //cpx_mtx_knk(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - //us2 = get_time(); - //printf("\tTranspose: %lu\n", us2 - us1); - #else - if (MODE == MODE_METAL && tmp.cols >= 64) - { - cpx_mtx_knk_metal_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - } - else if ((MODE == MODE_THREADED || MODE == MODE_METAL_THREADED) && tmp.cols >= 64) - { - cpx_mtx_knk_threads_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - } - else - { - cpx_mtx_knk_2x2(tmp.ptr, filter.ptr, gate.ptr, filter.rows, filter.cols, gate.rows, gate.cols); - } - #endif - - free(filter.ptr); - filter.ptr = tmp.ptr; - filter.rows = tmp.rows; - filter.cols = tmp.cols; - } - - cpx_mtx_init(&tmp, stateVector->rows, stateVector->cols); - - #ifdef SPEED_TEST - printf("%ix%i (dot)\n", tmp.rows, tmp.cols); - unsigned long int us1, us2; - us1 = get_time(); - cpx_mtx_dot_metal(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); - us2 = get_time(); - printf("\tMetal: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_dot_threads(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); - us2 = get_time(); - printf("\tThreads: %lu\n", us2 - us1); - us1 = get_time(); - cpx_mtx_dot(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); - us2 = get_time(); - printf("\tBare: %lu\n", us2 - us1); - #else - if ((MODE == MODE_METAL || MODE == MODE_METAL_THREADED) && tmp.cols >= 64) - { - cpx_mtx_dot_metal(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); - } - else if (MODE == MODE_THREADED && tmp.cols >= 64) - { - cpx_mtx_dot_threads(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); - } - else - { - cpx_mtx_dot(tmp.ptr, stateVector->ptr, filter.ptr, stateVector->rows, stateVector->cols, filter.rows, filter.cols); - } - #endif - free(stateVector->ptr); - stateVector->ptr = tmp.ptr; - free(filter.ptr); - if (instr == QANSEL_INSTRUCTION_U1 || instr == QANSEL_INSTRUCTION_U2 || instr == QANSEL_INSTRUCTION_U3) - { - free(gate_ptr); - } -} - -unsigned char qansel_measure(cpx_mtx_t* stateVector, unsigned char qubitCount, unsigned char qubit) -{ - unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); - cpx_t n; - float prob0 = 0; - for (unsigned int i = 0; i < qubitCountPow2; i++) - { - unsigned char bit = (i >> qubit) & 1; - cpx_mtx_get(stateVector, 0, i, &n); - if (bit == 0) prob0 += cpx_magsqr(&n); - } - - float r = qansel_rand(); - unsigned char newBit = r < prob0 ? 0 : 1; - float probTot = 0; - for (unsigned int i = 0; i < qubitCountPow2; i++) - { - unsigned char bit = (i >> qubit) & 1; - cpx_mtx_get(stateVector, 0, i, &n); - if (bit != newBit) - { - n.real = 0; - n.imaginary = 0; - } - else - { - probTot += cpx_magsqr(&n); - } - cpx_mtx_set(stateVector, 0, i, &n); - } - - float multiplier = sqrt(1 / probTot); - for (unsigned int i = 0; i < qubitCountPow2; i++) - { - unsigned char bit = (i >> qubit) & 1; - cpx_mtx_get(stateVector, 0, i, &n); - if (bit == newBit) - { - n.real *= multiplier; - n.imaginary *= multiplier; - } - cpx_mtx_set(stateVector, 0, i, &n); - } - - return newBit; -} - -int qansel_get_instruction_bitmax(unsigned char* ptr, int offset, int* bitmax, int* qbitmax) -{ - unsigned char a0, a1, a2; - *bitmax = 0; - *qbitmax = 0; - switch (ptr[offset]) - { - 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: - case QANSEL_INSTRUCTION_BARRIER: - case QANSEL_INSTRUCTION_DENSITY: - case QANSEL_INSTRUCTION_BORN: - a0 = ptr[offset + 1]; - if (a0 > 0x0D && a0 != 0x0F) return 0; - if (a0 != 0x0F) *qbitmax = a0 + 1; - return 1; - case QANSEL_INSTRUCTION_SAMPLE: - 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: - a0 = ptr[offset + 1]; - if ((a0 > 0x1D || a0 < 0x10) && a0 != 0x1F) return 0; - if (a0 != 0x1F) *bitmax = (a0 - 0x10) + 1; - return 1; - case QANSEL_INSTRUCTION_RESET: - case QANSEL_INSTRUCTION_PRINT: - a0 = ptr[offset + 1]; - if (a0 == 0xFF) return 1; - if (a0 < 0x10) - { - if (a0 > 0x0D && a0 != 0x0F) return 0; - if (a0 != 0x0F) *qbitmax = a0 + 1; - return 1; - } - else - { - if ((a0 > 0x1D || a0 < 0x10) && a0 != 0x1F) return 0; - if (a0 != 0x1F) *bitmax = (a0 - 0x10) + 1; - return 1; - } - return 0; - case QANSEL_INSTRUCTION_CX: - case QANSEL_INSTRUCTION_SWAP: - a0 = ptr[offset + 1]; - a1 = ptr[offset + 2]; - if (a0 > 0x0D) return 0; - if (a1 > 0x0D) return 0; - *qbitmax = (a0 > a1 ? a0 : a1) + 1; - return 1; - case QANSEL_INSTRUCTION_CCX: - case QANSEL_INSTRUCTION_CSWAP: - a0 = ptr[offset + 1]; - a1 = ptr[offset + 2]; - a2 = ptr[offset + 3]; - if (a0 > 0x0D || a1 > 0x0D || a2 > 0x0D) return 0; - *qbitmax = ((a0 > a1) && (a0 > a2) ? a0 : ((a1 > a0) && (a1 > a2) ? a1 : a2)) + 1; - return 1; - case QANSEL_INSTRUCTION_MEASURE: - a0 = ptr[offset + 1]; - a1 = ptr[offset + 2]; - if (a0 > 0x0D) return 0; - if (a1 > 0x1D || a1 < 0x10) return 0; - *qbitmax = a0 + 1; - *bitmax = (a1 - 0x10) + 1; - return 1; - case QANSEL_INSTRUCTION_RAND: - case QANSEL_INSTRUCTION_HVAR: - case QANSEL_INSTRUCTION_EXIT: - return 1; - } - return 0; -} - -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; - } - return 0; -} - -void qansel_born(cpx_mtx_t* stateVector, int PC, int qubitCount, unsigned char q0) -{ - unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); - if (q0 == 0x0F) - { - for (unsigned int j = 0; j < qubitCountPow2; j++) - { - unsigned int tmp = j; - for (unsigned char k = 0; k < qubitCount; k++) - { - putchar('0' + (tmp >> (qubitCount - 1) & 1)); - tmp <<= 1; - } - cpx_t n; - cpx_mtx_get(stateVector, 0, j, &n); - printf(": %.1f%%\n", cpx_magsqr(&n) * 100); - } - } - else if (q0 <= 0x0D) - { - float prob = 0; - for (unsigned int j = 0; j < qubitCountPow2; j++) - { - cpx_t n; - cpx_mtx_get(stateVector, 0, j, &n); - if ((j >> q0) & 1) - { - prob += cpx_magsqr(&n); - } - } - printf("0: %.1f%%\n", (1 - prob) * 100.0); - printf("1: %.1f%%\n", prob * 100.0); - } -} - -void qansel_density_or_print(cpx_mtx_t* stateVector, unsigned char* bitVector, unsigned char density, int bitCount, int qubitCount, unsigned char a0) -{ - unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); - if (a0 == 0x0F || a0 == 0x1F || a0 == 0xFF) - { - if (a0 == 0x0F || a0 == 0xFF) - { - printf("[ "); cpx_mtx_print(stateVector); printf(" ]\n"); - } - if (a0 == 0x1F || a0 == 0xFF) - { - for (int32_t j = bitCount - 1; j >= 0; j--) - { - putchar('0' + bitVector[j]); - } - putchar('\n'); - } - } - else if (a0 >= 0x10 && a0 <= 0x1D) - { - putchar('0' + bitVector[a0 - 0x10]); - putchar('\n'); - } - else - { - cpx_mtx_t tmp; - cpx_mtx_init(&tmp, 1, 2); - for (unsigned int j = 0; j < qubitCountPow2; j++) - { - if ((j >> a0) & 1) - { - cpx_t a, b; - cpx_mtx_get(&tmp, 0, 1, &a); - cpx_mtx_get(stateVector, 0, j, &b); - a.real += b.real; - a.imaginary += b.imaginary; - cpx_mtx_set(&tmp, 0, 1, &a); - } - else - { - cpx_t a, b; - cpx_mtx_get(&tmp, 0, 0, &a); - cpx_mtx_get(stateVector, 0, j, &b); - a.real += b.real; - a.imaginary += b.imaginary; - cpx_mtx_set(&tmp, 0, 0, &a); - } - } - float multiplier = 0; - cpx_t n; - cpx_mtx_get(&tmp, 0, 0, &n); - multiplier += cpx_magsqr(&n); - cpx_mtx_get(&tmp, 0, 1, &n); - multiplier += cpx_magsqr(&n); - multiplier = sqrt(1 / multiplier); - n.real *= multiplier; - n.imaginary *= multiplier; - cpx_mtx_set(&tmp, 0, 1, &n); - cpx_mtx_get(&tmp, 0, 0, &n); - n.real *= multiplier; - n.imaginary *= multiplier; - cpx_mtx_set(&tmp, 0, 0, &n); - - if (density) - { - cpx_t a, b, c, d, x, y, z, w; - cpx_mtx_get(&tmp, 0, 0, &a); - cpx_mtx_get(&tmp, 0, 1, &b); - cpx_mtx_get(&tmp, 0, 0, &c); - cpx_mtx_get(&tmp, 0, 1, &d); - c.imaginary *= -1; - d.imaginary *= -1; - cpx_mul(&x, &a, &c); - cpx_mul(&y, &a, &d); - cpx_mul(&z, &b, &c); - cpx_mul(&w, &b, &d); - char* sx = cpx_str(&x); - char* sy = cpx_str(&y); - char* sz = cpx_str(&z); - char* sw = cpx_str(&w); - printf("[ %s, %s ]\n", sx, sy); - printf("[ %s, %s ]\n", sz, sw); - free(sx); - free(sy); - free(sz); - free(sw); - } - else - { - printf("[ "); cpx_mtx_print(&tmp); printf(" ]\n"); - } - cpx_mtx_free(&tmp); - } -} - -float qansel_get_float(unsigned char* program, int offset) -{ - float ret; - memcpy(&ret, program + offset, sizeof(float)); - return ret; -} - -short qansel_get_short(unsigned char* program, int offset) -{ - short ret; - memcpy(&ret, program + offset, sizeof(short)); - return ret; -} - -int qansel_get_int(unsigned char* program, int offset) -{ - int ret; - memcpy(&ret, program + offset, sizeof(int)); - return ret; -} - -void qansel_reset(cpx_mtx_t* stateVector, unsigned char* bitVector, int qubitCount, int bitCount, unsigned char q0) -{ - unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); - if (q0 == 0xFF) - { - cpx_mtx_set2(stateVector, 0, 0, 1, 0); - for (unsigned int j = 1; j < qubitCountPow2; j++) - { - cpx_mtx_set2(stateVector, 0, j, 0, 0); - } - for (unsigned char j = 0; j < bitCount; j++) - { - bitVector[j] = 0; - } - } - else if (q0 == 0x0F) - { - cpx_mtx_set2(stateVector, 0, 0, 1, 0); - for (unsigned int j = 1; j < qubitCountPow2; j++) - { - cpx_mtx_set2(stateVector, 0, j, 0, 0); - } - } - else if (q0 == 0x1F) - { - for (unsigned char j = 0; j < bitCount; j++) - { - bitVector[j] = 0; - } - } - else if (q0 <= 0x0D) - { - unsigned char bit = qansel_measure(stateVector, qubitCount, q0); - if (bit) - { - qansel_instruction(stateVector, qubitCount, QANSEL_INSTRUCTION_X, q0, 0, 0, 0); - } - } - else if (q0 >= 0x10 && q0 <= 0x1D) - { - bitVector[q0 - 0x10] = 0; - } -} - -unsigned char qansel_compare(unsigned char* bitVector, int bitCount, int PC, unsigned char a0, short op) -{ - unsigned char ret = 0; - short val; - if (a0 == 0x1F) - { - val = 0; - for (int32_t j = bitCount - 1; j >= 0; j--) - { - val = (val << 1) | bitVector[j]; - } - if (val == op) ret |= QANSEL_FLAGS_EQUAL; - if (val > op) ret |= QANSEL_FLAGS_GREATER; - if (val < op) ret |= QANSEL_FLAGS_LESSER; - } - else if (a0 >= 0x10 && a0 <= 0x1D) - { - val = bitVector[a0 - 0x10]; - if (val == op) ret |= QANSEL_FLAGS_EQUAL; - if (val > op) ret |= QANSEL_FLAGS_GREATER; - if (val < op) ret |= QANSEL_FLAGS_LESSER; - } - return ret; -} - -void qansel_crawl(unsigned char* program, int programSize, int* qubitCount, int* bitCount, int* sample) -{ - printf("Crawling program . . .\n"); - int PC = 0; - *qubitCount = 0; - *bitCount = 0; - *sample = 0xFF; - while (PC < programSize) - { - int next = qansel_get_instruction_size(program[PC]); - if (program[PC] == QANSEL_INSTRUCTION_SAMPLE) - { - if ((program[PC + 1] < 0x10 || program[PC + 1] > 0x1D) && program[PC + 1] != 0x1F) - { - fprintf(stderr, "QAnsel (%04X): Invalid index.\n", PC); - } - else - { - *sample = program[PC + 1] - 0x10; - } - } - if (next == 0) - { - printf("QAnsel (%04X): Invalid instruction 0x%02x.\n", PC, program[PC]); - exit(1); - } - int bitmax, qbitmax; - int success = qansel_get_instruction_bitmax(program, PC, &bitmax, &qbitmax); - if (!success) - { - fprintf(stderr, "QAnsel (%04X): Invalid index.\n", PC); - exit(1); - } - if (bitmax > *bitCount) *bitCount = bitmax; - if (qbitmax > *qubitCount) *qubitCount = qbitmax; - PC += next; - } - printf("Quantum bits allocated: %i\n", *qubitCount); - printf("Classical bits allocated: %i\n", *bitCount); -} - -void qansel_run(unsigned char* program, int programSize, int qubitCount, int bitCount, unsigned char* outputBitVector) -{ - int PC = 0; - unsigned int qubitCountPow2 = (unsigned int)pow(2, qubitCount); - unsigned char bitVector[bitCount]; - memset(bitVector, 0, bitCount); - cpx_mtx_t stateVector; - cpx_mtx_init(&stateVector, 1, qubitCountPow2); - cpx_mtx_set2(&stateVector, 0, 0, 1, 0); - //if (gfx) display(&stateVector, qubitCount); - unsigned char skip = 0, a0 = 0, a1 = 0, a2 = 0; - unsigned char flags = 0; - unsigned short tmp = 0; - - while (PC < programSize) - { - //printf("%i;%i\n", PC, programSize); - int next = qansel_get_instruction_size(program[PC]); - if (skip) - { - skip = 0; - } - else - { - unsigned char instr = program[PC]; - //printf("-----------------------------------\n"); - //qansel_density_or_print(&stateVector, bitVector, 0, bitCount, qubitCount, 0x0F); - //qansel_density_or_print(&stateVector, bitVector, 0, bitCount, qubitCount, 0x1F); - //printf("%s(%i, %i, %i)(%f, %f, %f)\n", qansel_instruction_to_string(instr), program[PC+1], program[PC+2], program[PC], qansel_get_float(program, PC + 2), qansel_get_float(program, PC + 2 + sizeof(float)), qansel_get_float(program, PC + 2) + sizeof(float) * 2); - switch (instr) - { - case QANSEL_INSTRUCTION_X: - case QANSEL_INSTRUCTION_Y: - case QANSEL_INSTRUCTION_Z: - case QANSEL_INSTRUCTION_H: - case QANSEL_INSTRUCTION_S: - case QANSEL_INSTRUCTION_T: - a0 = program[PC + 1]; - qansel_instruction(&stateVector, qubitCount, instr, program[PC + 1], 0, 0, 0); - break; - case QANSEL_INSTRUCTION_RX: - a0 = program[PC + 1]; - qansel_instruction - ( - &stateVector, qubitCount, instr, a0, - M_PI / 2, -M_PI / 2, qansel_get_float(program, PC + 2) - (M_PI / 2) - ); - break; - case QANSEL_INSTRUCTION_RY: - case QANSEL_INSTRUCTION_U1: - a0 = program[PC + 1]; - qansel_instruction - ( - &stateVector, qubitCount, instr, a0, - qansel_get_float(program, PC + 2), 0, 0 - ); - break; - case QANSEL_INSTRUCTION_RZ: - a0 = program[PC + 1]; - qansel_instruction - ( - &stateVector, qubitCount, instr, a0, - 0, 0, qansel_get_float(program, PC + 2) - ); - break; - case QANSEL_INSTRUCTION_U2: - a0 = program[PC + 1]; - qansel_instruction - ( - &stateVector, qubitCount, instr, a0, - qansel_get_float(program, PC + 2), - qansel_get_float(program, PC + 2 + sizeof(float)), - 0 - ); - break; - case QANSEL_INSTRUCTION_U3: - a0 = program[PC + 1]; - qansel_instruction - ( - &stateVector, qubitCount, instr, a0, - qansel_get_float(program, PC + 2), - qansel_get_float(program, PC + 2 + sizeof(float)), - qansel_get_float(program, PC + 2 + sizeof(float) * 2) - ); - break; - case QANSEL_INSTRUCTION_CX: - a0 = program[PC + 1]; - a1 = program[PC + 2]; - qansel_cnot(&stateVector, qubitCount, a0, a1); - break; - case QANSEL_INSTRUCTION_SWAP: - a0 = program[PC + 1]; - a1 = program[PC + 2]; - qansel_swap(&stateVector, qubitCount, a0, a1); - break; - case QANSEL_INSTRUCTION_CCX: - a0 = program[PC + 1]; - a1 = program[PC + 2]; - a2 = program[PC + 3]; - qansel_toffoli(&stateVector, qubitCount, a0, a1, a2); - break; - case QANSEL_INSTRUCTION_CSWAP: - a0 = program[PC + 1]; - a1 = program[PC + 2]; - a2 = program[PC + 3]; - qansel_fredkin(&stateVector, qubitCount, a0, a1, a2); - break; - case QANSEL_INSTRUCTION_MEASURE: - a0 = program[PC + 1]; - a1 = program[PC + 2] - 0x10; - bitVector[a1] = qansel_measure(&stateVector, qubitCount, a0); - break; - case QANSEL_INSTRUCTION_BORN: - a0 = program[PC + 1]; - qansel_born(&stateVector, PC, qubitCount, a0); - break; - case QANSEL_INSTRUCTION_DENSITY: - a0 = program[PC + 1]; - qansel_density_or_print(&stateVector, bitVector, 1, bitCount, qubitCount, a0); - break; - case QANSEL_INSTRUCTION_PRINT: - a0 = program[PC + 1]; - qansel_density_or_print(&stateVector, bitVector, 0, bitCount, qubitCount, a0); - break; - case QANSEL_INSTRUCTION_BARRIER: - a0 = program[PC + 1]; - break; - case QANSEL_INSTRUCTION_RESET: - a0 = program[PC + 1]; - qansel_reset(&stateVector, bitVector, qubitCount, bitCount, a0); - break; - case QANSEL_INSTRUCTION_HVAR: - 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: - HIDDEN_VARIABLE = 0; - break; - case QANSEL_INSTRUCTION_IF_E: - a0 = program[PC + 1]; - tmp = qansel_get_short(program, PC + 2); - flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); - skip = 1; if (flags & QANSEL_FLAGS_EQUAL) skip = 0; - break; - case QANSEL_INSTRUCTION_IF_NE: - a0 = program[PC + 1]; - tmp = qansel_get_short(program, PC + 2); - flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); - skip = 1; if (!(flags & QANSEL_FLAGS_EQUAL)) skip = 0; - break; - case QANSEL_INSTRUCTION_IF_G: - a0 = program[PC + 1]; - tmp = qansel_get_short(program, PC + 2); - flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); - skip = 1; if (flags & QANSEL_FLAGS_GREATER) skip = 0; - break; - case QANSEL_INSTRUCTION_IF_GE: - a0 = program[PC + 1]; - tmp = qansel_get_short(program, PC + 2); - flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); - skip = 1; if ((flags & QANSEL_FLAGS_GREATER) && (flags & QANSEL_FLAGS_EQUAL)) skip = 0; - break; - case QANSEL_INSTRUCTION_IF_L: - a0 = program[PC + 1]; - tmp = qansel_get_short(program, PC + 2); - flags = qansel_compare(bitVector, bitCount, PC, a0, tmp); - skip = 1; if (flags & QANSEL_FLAGS_LESSER) skip = 0; - break; - case QANSEL_INSTRUCTION_IF_LE: - a0 = program[PC + 1]; - tmp = qansel_get_short(program, PC + 2); - 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 (outputBitVector != NULL) - { - for (int i = 0; i < bitCount; i++) - { - outputBitVector[i] = bitVector[i]; - } - } - cpx_mtx_free(&stateVector); -} - -void qansel_execute(unsigned char* buff, int sizeofbuff) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - float seed = (float)((unsigned long)ts.tv_sec * 1000000000LL + ts.tv_nsec); - qansel_rand_s(seed); - - unsigned short vals; - float valf; - int pos = 0; - - int qubitCount, bitCount, sample; - qansel_crawl(buff, sizeofbuff, &qubitCount, &bitCount, &sample); - if (sample != 0xFF) - { - unsigned short stats[65536]; - for (unsigned int i = 0; i < (1 << bitCount); i++) - { - stats[i] = 0; - } - unsigned char bitVect[bitCount]; - memset(bitVect, 0, bitCount); - for (int i = 0; i < bitCount; i++) bitVect[i] = 0; - unsigned int shots = 1000; - for (unsigned int i = 0; i < shots; i++) - { - qansel_run(buff, sizeofbuff, qubitCount, bitCount, bitVect); - unsigned short stat = 0; - for (signed char j = bitCount - 1; j >= 0; j--) - { - stat = (stat << 1) | bitVect[j]; - } - stats[stat]++; - } - unsigned int count = 0; - for (unsigned int i = 0; i < (1 << bitCount); i++) - { - unsigned int tmp = i; - for (unsigned char j = 0; j < bitCount; j++) - { - unsigned char bit = (tmp >> (bitCount - 1) & 1); - if (j == (bitCount - sample - 1) && bit) - { - count += stats[i]; - } - if (sample == 0x0F) - { - putchar('0' + bit); - } - tmp <<= 1; - } - if (sample == 0x0F) - { - printf(": %.1f%%\n", ((float)stats[i] / (float)shots) * (float)100); - } - } - if (sample != 0x0F) - { - float prob = ((float)count / (float)shots) * (float)100; - printf("0: %.1f%%\n", ((float)100)-prob); - printf("1: %.1f%%\n", prob); - } - } - else - { - qansel_run(buff, sizeofbuff, qubitCount, bitCount, NULL); - } -} diff --git a/src/display.c b/src/display.c index 1862610..5b5ff66 100644 --- a/src/display.c +++ b/src/display.c @@ -20,18 +20,18 @@ void DrawThickLine(SDL_Renderer* renderer, int x1, int y1, int x2, int y2, int t } } -void display_wait(uint32_t i) -{ - SDL_Delay(i); -} - -void display(cpx_mtx_t* stateVector, uint8_t qubitCount) +int display(cpx_mtx_t* stateVector, uint8_t qubitCount, int delay) { + if (qubitCount > 8) + { + fprintf(stderr, "QAnsel warning: Too many quantum bits to be displayed.\n"); + return 0; + } uint32_t qubitCountPow2 = (uint32_t)pow(2, qubitCount); static uint8_t displayInitialized = 0; static SDL_Window* window = NULL; - static SDL_Surface* surface = NULL; static SDL_Renderer* renderer = NULL; + static cpx_mtx_t oldStateVector; int SCREEN_WIDTH = 640 * 2; int SCREEN_HEIGHT = 480; int SCREEN_HALF = SCREEN_HEIGHT / 2; @@ -41,14 +41,16 @@ void display(cpx_mtx_t* stateVector, uint8_t qubitCount) SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); - return; + cpx_mtx_free(&oldStateVector); + displayInitialized = 0; + return delay; } if (displayInitialized == 0) { if (SDL_Init(SDL_INIT_VIDEO)) { - fprintf(stderr, "Failed to open graphical window.\n"); + fprintf(stderr, "QAnsel: Failed to open graphical window.\n"); exit(1); } window = SDL_CreateWindow @@ -62,17 +64,25 @@ void display(cpx_mtx_t* stateVector, uint8_t qubitCount) ); if (window == NULL) { - fprintf(stderr, "Failed to open graphical window.\n"); + fprintf(stderr, "QAnsel: Failed to open graphical window.\n"); exit(1); } - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == NULL) { - fprintf(stderr, "Failed to open graphical window.\n"); + fprintf(stderr, "QAnsel: Failed to open graphical window.\n"); exit(1); } + cpx_mtx_init(&oldStateVector, stateVector->rows, stateVector->cols); + cpx_mtx_copy(&oldStateVector, stateVector); displayInitialized = 1; } + else if (cpx_mtx_cmp(&oldStateVector, stateVector) == 0) + { + return delay; + } + cpx_mtx_copy(&oldStateVector, stateVector); + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); SDL_RenderClear(renderer); SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00); @@ -124,7 +134,20 @@ void display(cpx_mtx_t* stateVector, uint8_t qubitCount) i0 = i1; } + SDL_Event windowEvent; + if (SDL_PollEvent(&windowEvent)) + { + if (SDL_QUIT == windowEvent.type) + { + delay = 0; + } + } + SDL_RenderPresent(renderer); // Update screen. - SDL_Delay(500); // Wait for two seconds. + if (delay != 255) + { + SDL_Delay(100 * delay); + } + return delay; } \ No newline at end of file diff --git a/src/openqasm.c b/src/openqasm.c new file mode 100644 index 0000000..f451fa5 --- /dev/null +++ b/src/openqasm.c @@ -0,0 +1,762 @@ +int qansel_read_script(char* script, char*** chunksReturn, int** chunkLinesReturn, int* countReturn) +{ + int scriptSize = strlen(script); + if (scriptSize > QANSEL_MAX_SIZE) + { + fprintf(stderr, "QAnsel: The source is too large.\n"); + return 0; + } + char* line = malloc(0); + char** chunks = malloc(0); + int* chunksAssociatedLines = malloc(0); + int lineCount = 1; + int lineLen = 0; + int chunkCount = 0; + int inComment = 0; + for (int i = 0; i < scriptSize; i++) + { + int charactersLeft = scriptSize - i; + if (script[i] == '\n') + { + lineCount++; + inComment = 0; + } + else if (charactersLeft >= 2 && script[i] == '/' && script[i + 1] == '/') + { + inComment = 1; + } + else if (!inComment && script[i] != ';' && script[i] != '{' && script[i] != '}') + { + line = realloc(line, lineLen + 1); + line[lineLen++] = script[i] == '\t' ? ' ' : script[i]; + if (script[i] == ')' && lineLen > 2) + { + for (int j = 0; j < lineLen - 1; j++) + { + if ( (line[j] == 'i' || line[j] == 'I') && (line[j + 1] == 'f' || line[j + 1] == 'F') ) + { + line = realloc(line, lineLen + 1); + line[lineLen++] = 0; + chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); + chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); + chunks[chunkCount] = line; + chunksAssociatedLines[chunkCount++] = lineCount; + line = malloc(0); + lineLen = 0; + break; + } + } + } + } + else if (!inComment && (script[i] == '{' || script[i] == '}')) + { + if (lineLen > 0) + { + line = realloc(line, lineLen + 1); + line[lineLen++] = 0; + chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); + chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); + chunks[chunkCount] = line; + chunksAssociatedLines[chunkCount++] = lineCount; + line = malloc(2); + } + else + { + line = realloc(line, 2); + } + line[0] = script[i]; + line[1] = 0; + chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); + chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); + chunks[chunkCount] = line; + chunksAssociatedLines[chunkCount++] = lineCount; + line = malloc(0); + lineLen = 0; + } + else if (!inComment && script[i] == ';') + { + if (lineLen > 0) + { + line = realloc(line, lineLen + 1); + line[lineLen++] = 0; + chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); + chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); + chunks[chunkCount] = line; + chunksAssociatedLines[chunkCount++] = lineCount; + line = malloc(0); + lineLen = 0; + } + } + } + if (lineLen > 0) + { + line = realloc(line, lineLen + 1); + line[lineLen++] = 0; + chunks = realloc(chunks, (chunkCount + 1) * sizeof(char*)); + chunksAssociatedLines = realloc(chunksAssociatedLines, (chunkCount + 1) * sizeof(int)); + chunks[chunkCount] = line; + chunksAssociatedLines[chunkCount++] = lineCount; + } + else + { + free(line); + } + for (int i = 0; i < chunkCount; i++) + { + int len = strlen(chunks[i]); + for (int j = 0; j < len; j++) + { + if (chunks[i][j] >= 'A' && chunks[i][j] <= 'Z') + { + chunks[i][j] += 'a' - 'A'; + } + } + } + *chunksReturn = chunks; + *chunkLinesReturn = chunksAssociatedLines; + *countReturn = chunkCount; + return 1; +} + +float qansel_parse_float_part(char* neg, char* str) +{ + float ret; + int len = strlen(str); + if (len > 2) + { + ret = atof(str); + if (str[len - 2] == 'p' && str[len - 1] == 'i') + { + ret *= M_PI; + } + } + else if (strcmp(str, "pi") == 0) + { + ret = M_PI; + } + else + { + ret = atof(str); + } + if (strcmp(neg, "-") == 0) + { + ret *= -1; + } + return ret; +} + +int qansel_parse_float(char* str, float* returnFloat) +{ + *returnFloat = 0; + const char expr[] = "^(-|)([0-9][0-9]*\\.[0-9]*|[0-9][0-9]*|[0-9][0-9]*\\.[0-9]*pi|[0-9][0-9]*pi|pi)([/](-|)([0-9][0-9]*\\.[0-9]*|[0-9][0-9]*|[0-9][0-9]*\\.[0-9]*pi|[0-9][0-9]*pi|pi)|)$"; + regex_t regex; + regmatch_t regmatches[10]; + if (regcomp(®ex, expr, REG_EXTENDED | REG_ICASE)) return 0; + int ret = regexec(®ex, str, 10, regmatches, 0); + if (!ret) + { + int strbeg = regmatches[1].rm_so; + int strlen = regmatches[1].rm_eo - regmatches[1].rm_so; + char neg1[strlen + 1]; + memcpy(neg1, str + strbeg, strlen); + neg1[strlen] = 0; + + strbeg = regmatches[2].rm_so; + strlen = regmatches[2].rm_eo - regmatches[2].rm_so; + char numer[strlen + 1]; + memcpy(numer, str + strbeg, strlen); + numer[strlen] = 0; + *returnFloat = qansel_parse_float_part(neg1, numer); + + if (regmatches[3].rm_eo > regmatches[3].rm_so) + { + strbeg = regmatches[4].rm_so; + strlen = regmatches[4].rm_eo - regmatches[4].rm_so; + char neg2[strlen + 1]; + memcpy(neg2, str + strbeg, strlen); + neg2[strlen] = 0; + + strbeg = regmatches[5].rm_so; + strlen = regmatches[5].rm_eo - regmatches[5].rm_so; + char denom[strlen + 1]; + memcpy(denom, str + strbeg, strlen); + denom[strlen] = 0; + + float fdenom = qansel_parse_float_part(neg2, denom); + *returnFloat /= fdenom; + } + } + else if (ret == REG_NOMATCH) + { + return 0; + } + else + { + char errbuf[100]; + regerror(ret, ®ex, errbuf, sizeof(errbuf)); + fprintf(stderr, "QAnsel: %s.\n", errbuf); + exit(1); + } + regfree(®ex); + + return 1; +} + +int qansel_process_chunk(int index, char* chunk, int line, regmatch_t* regmatches, int* qubitCount, int* bitCount, unsigned char** binary, int* binarySize) +{ + unsigned short s0; + float d0, d1, d2; + unsigned char instr = 0; + unsigned char a0 = 0; + unsigned char a1 = 0; + unsigned char a2 = 0; + if (index == 0) //qreg + { + if (*qubitCount > 0) + { + fprintf(stderr, "QAnsel on line %i: Qubits can only be initialized once.\n", line); + return 0; + } + int strbeg = regmatches[1].rm_so; + int strlen = regmatches[1].rm_eo - regmatches[1].rm_so; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + int nump = atoi(tmp); + if (nump > QANSEL_QUBIT_LIMIT) + { + fprintf(stderr, "QAnsel on line %i: Initialized qubits cannot exceed %i.\n", line, QANSEL_QUBIT_LIMIT); + return 0; + } + *qubitCount = nump; + } + else if (index == 1) //creg + { + if (*bitCount > 0) + { + fprintf(stderr, "QAnsel on line %i: Classical bits can only be initialized once.\n", line); + return 0; + } + int strbeg = regmatches[1].rm_so; + int strlen = regmatches[1].rm_eo - regmatches[1].rm_so; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + int nump = atoi(tmp); + if (nump > QANSEL_QUBIT_LIMIT) + { + fprintf(stderr, "QAnsel on line %i: Initialized classical bits cannot exceed %i.\n", line, QANSEL_QUBIT_LIMIT); + return 0; + } + *bitCount = nump; + } + else if (index == 2 || index == 3 || index == 4 || index == 5) //single qubit instructions + { + if (*qubitCount == 0) + { + fprintf(stderr, "QAnsel on line %i: Quantum bit instruction used prior to initialization.\n", line); + return 0; + } + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strcmp(tmp, "rx") == 0) instr = QANSEL_INSTRUCTION_RX; + else if (strcmp(tmp, "ry") == 0) instr = QANSEL_INSTRUCTION_RY; + else if (strcmp(tmp, "rz") == 0) instr = QANSEL_INSTRUCTION_RZ; + else if (strcmp(tmp, "u1") == 0) instr = QANSEL_INSTRUCTION_U1; + else if (strcmp(tmp, "u2") == 0) instr = QANSEL_INSTRUCTION_U2; + else if (strcmp(tmp, "u3") == 0) instr = QANSEL_INSTRUCTION_U3; + else if (strcmp(tmp, "u") == 0) instr = QANSEL_INSTRUCTION_U3; + else if (strcmp(tmp, "reset") == 0) instr = QANSEL_INSTRUCTION_RESET; + else if (strcmp(tmp, "barrier") == 0) instr = QANSEL_INSTRUCTION_BARRIER; + else if (strcmp(tmp, "born") == 0) instr = QANSEL_INSTRUCTION_BORN; + else if (strcmp(tmp, "density") == 0) instr = QANSEL_INSTRUCTION_DENSITY; + else if (strcmp(tmp, "print") == 0) instr = QANSEL_INSTRUCTION_PRINT; + else if (strcmp(tmp, "not") == 0) instr = QANSEL_INSTRUCTION_X; + else if (strcmp(tmp, "x") == 0) instr = QANSEL_INSTRUCTION_X; + else if (strcmp(tmp, "y") == 0) instr = QANSEL_INSTRUCTION_Y; + else if (strcmp(tmp, "z") == 0) instr = QANSEL_INSTRUCTION_Z; + else if (strcmp(tmp, "h") == 0) instr = QANSEL_INSTRUCTION_H; + else if (strcmp(tmp, "s") == 0) instr = QANSEL_INSTRUCTION_S; + else if (strcmp(tmp, "t") == 0) instr = QANSEL_INSTRUCTION_T; + } + for (int i = 0; i < (index == 2 ? 0 : (index == 3 ? 1 : (index == 4 ? 2 : 3))); i++) + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (!qansel_parse_float(tmp, (i == 0 ? &d0 : (i == 1 ? &d1 : &d2)))) + { + fprintf(stderr, "QAnsel on line %i: Invalid rotation value.\n", line); + return 0; + } + } + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + if (strlen > 0) + { + strbeg = regmatches[rmp].rm_so; + strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + a0 = atoi(tmp); + if (a0 >= *qubitCount) + { + fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated quantum bits.\n", line, a0); + return 0; + } + } + else + { + a0 = 0x0F; + if (instr == QANSEL_INSTRUCTION_DENSITY) + { + fprintf(stderr, "QAnsel on line %i: Density matrices can only be produced for individual qubits.\n", line, a0); + return 0; + } + } + } + switch (index) + { + case 2: + *binarySize += 2; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2] = instr; + (*binary)[(*binarySize) - 1] = a0; + break; + case 3: + *binarySize += 2 + sizeof(float) * 1; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2 - sizeof(float) * 1] = instr; + (*binary)[(*binarySize) - 1 - sizeof(float) * 1] = a0; + memcpy((*binary) + ((*binarySize) - sizeof(float)), &d0, sizeof(float)); + break; + case 4: + *binarySize += 2 + sizeof(float) * 2; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2 - sizeof(float) * 2] = instr; + (*binary)[(*binarySize) - 1 - sizeof(float) * 2] = a0; + memcpy((*binary) + ((*binarySize) - sizeof(float) * 2), &d0, sizeof(float)); + memcpy((*binary) + ((*binarySize) - sizeof(float) * 1), &d1, sizeof(float)); + break; + case 5: + *binarySize += 2 + sizeof(float) * 3; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2 - sizeof(float) * 3] = instr; + (*binary)[(*binarySize) - 1 - sizeof(float) * 3] = a0; + memcpy((*binary) + ((*binarySize) - sizeof(float) * 3), &d0, sizeof(float)); + memcpy((*binary) + ((*binarySize) - sizeof(float) * 2), &d1, sizeof(float)); + memcpy((*binary) + ((*binarySize) - sizeof(float) * 1), &d2, sizeof(float)); + break; + } + } + else if (index == 6) //measure instruction + { + if (*qubitCount == 0) + { + fprintf(stderr, "QAnsel on line %i: Quantum bit instruction used prior to initialization.\n", line); + return 0; + } + if (*bitCount == 0) + { + fprintf(stderr, "QAnsel on line %i: Classical bit instruction used prior to initialization.\n", line); + return 0; + } + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + if (strlen > 0) + { + strbeg = regmatches[rmp].rm_so; + strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + a0 = atoi(tmp); + if (a0 >= *qubitCount) + { + fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated quantum bits.\n", line, a0); + return 0; + } + } + else + { + a0 = 0x0F; + } + } + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + if (strlen > 0) + { + strbeg = regmatches[rmp].rm_so; + strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + a1 = atoi(tmp); + if (a1 >= *bitCount) + { + fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated classical bits.\n", line, a1); + return 0; + } + a1 += 0x10; + } + else + { + a1 = 0x1F; + } + } + *binarySize += 3; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 3] = QANSEL_INSTRUCTION_MEASURE; + (*binary)[(*binarySize) - 2] = a0; + (*binary)[(*binarySize) - 1] = a1; + } + else if (index == 7) //classical bit instructions + { + if (*bitCount == 0) + { + fprintf(stderr, "QAnsel on line %i: Classical bit instruction used prior to initialization.\n", line); + return 0; + } + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strcmp(tmp, "sample") == 0) instr = QANSEL_INSTRUCTION_SAMPLE; + else if (strcmp(tmp, "reset") == 0) instr = QANSEL_INSTRUCTION_RESET; + else if (strcmp(tmp, "print") == 0) instr = QANSEL_INSTRUCTION_PRINT; + } + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + if (strlen > 0) + { + strbeg = regmatches[rmp].rm_so; + strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + a0 = atoi(tmp); + if (a0 >= *bitCount) + { + fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated classical bits.\n", line, a0); + return 0; + } + a0 += 0x10; + } + else + { + a0 = 0x1F; + } + } + *binarySize += 2; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2] = instr; + (*binary)[(*binarySize) - 1] = a0; + } + else if (index == 8 || index == 9) //double qubit instructions + { + if (*qubitCount == 0) + { + fprintf(stderr, "QAnsel on line %i: Quantum bit instruction used prior to initialization.\n", line); + return 0; + } + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strcmp(tmp, "cx") == 0) instr = QANSEL_INSTRUCTION_CX; + if (strcmp(tmp, "cnot") == 0) instr = QANSEL_INSTRUCTION_CX; + if (strcmp(tmp, "ccnot") == 0) instr = QANSEL_INSTRUCTION_CCX; + if (strcmp(tmp, "ccx") == 0) instr = QANSEL_INSTRUCTION_CCX; + else if (strcmp(tmp, "toffoli") == 0) instr = QANSEL_INSTRUCTION_CCX; + else if (strcmp(tmp, "cswap") == 0) instr = QANSEL_INSTRUCTION_CSWAP; + else if (strcmp(tmp, "fredkin") == 0) instr = QANSEL_INSTRUCTION_CSWAP; + } + for (int i = 0; i < (index == 8 ? 2 : 3); i++) + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + int tmpi = atoi(tmp); + if (tmpi >= *qubitCount) + { + fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated quantum bits.\n", line, tmpi); + return 0; + } + switch (i) + { + case 0: a0 = tmpi; break; + case 1: a1 = tmpi; break; + case 2: a2 = tmpi; break; + } + } + if (index == 8) + { + *binarySize += 3; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 3] = instr; + (*binary)[(*binarySize) - 2] = a0; + (*binary)[(*binarySize) - 1] = a1; + } + else + { + *binarySize += 4; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 4] = instr; + (*binary)[(*binarySize) - 3] = a0; + (*binary)[(*binarySize) - 2] = a1; + (*binary)[(*binarySize) - 1] = a2; + } + } + else if (index == 10) //if instructions + { + if (*bitCount == 0) + { + fprintf(stderr, "QAnsel on line %i: Classical bit instruction used prior to initialization.\n", line); + return 0; + } + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + if (strlen > 0) + { + strbeg = regmatches[rmp].rm_so; + strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + a0 = atoi(tmp); + if (a0 >= *bitCount) + { + fprintf(stderr, "QAnsel on line %i: Index `%i` exceeds allocated classical bits.\n", line, a0); + return 0; + } + a0 += 0x10; + } + else + { + a0 = 0x1F; + } + } + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strlen == 0) + { + strbeg = regmatches[rmp].rm_so; + strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strcmp(tmp, "==") == 0) instr = QANSEL_INSTRUCTION_IF_E; + else if (strcmp(tmp, "!=") == 0) instr = QANSEL_INSTRUCTION_IF_NE; + else if (strcmp(tmp, "<>") == 0) instr = QANSEL_INSTRUCTION_IF_NE; + else if (strcmp(tmp, ">=") == 0) instr = QANSEL_INSTRUCTION_IF_GE; + else if (strcmp(tmp, "<=") == 0) instr = QANSEL_INSTRUCTION_IF_LE; + else if (strcmp(tmp, ">") == 0) instr = QANSEL_INSTRUCTION_IF_G; + else if (strcmp(tmp, "<") == 0) instr = QANSEL_INSTRUCTION_IF_L; + } + else + { + if (strcmp(tmp, "==") == 0) instr = QANSEL_INSTRUCTION_IF_E; + else if (strcmp(tmp, "!=") == 0) instr = QANSEL_INSTRUCTION_IF_NE; + else if (strcmp(tmp, "<>") == 0) instr = QANSEL_INSTRUCTION_IF_NE; + else if (strcmp(tmp, ">=") == 0) instr = QANSEL_INSTRUCTION_IF_GE; + else if (strcmp(tmp, "<=") == 0) instr = QANSEL_INSTRUCTION_IF_LE; + else if (strcmp(tmp, ">") == 0) instr = QANSEL_INSTRUCTION_IF_G; + else if (strcmp(tmp, "<") == 0) instr = QANSEL_INSTRUCTION_IF_L; + } + } + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + s0 = (unsigned short)atoi(tmp); + } + //printf("%s(%02x,%i)\n", qansel_instruction_to_string(instr), a0, s0); + *binarySize += 2 + sizeof(unsigned short); + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 2 - sizeof(unsigned short)] = instr; + (*binary)[(*binarySize) - 1 - sizeof(unsigned short)] = a0; + memcpy((*binary) + ((*binarySize) - sizeof(unsigned short)), &s0, sizeof(unsigned short)); + } + else if (index == 11) //floating point settings + { + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strcmp(tmp, "hvar") == 0) instr = QANSEL_INSTRUCTION_HVAR; + } + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (!qansel_parse_float(tmp, &d0)) + { + fprintf(stderr, "QAnsel on line %i: Syntax error.\n", line); + return 0; + } + } + *binarySize += 1 + sizeof(float); + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 1 - sizeof(float)] = instr; + memcpy((*binary) + ((*binarySize) - sizeof(float)), &d0, sizeof(float)); + } + else if (index == 12) //lone instructions + { + int rmp = 1; + { + int strbeg = regmatches[rmp].rm_so; + int strlen = regmatches[rmp].rm_eo - regmatches[rmp].rm_so; + rmp++; + char tmp[strlen + 1]; + memcpy(tmp, chunk + strbeg, strlen); + tmp[strlen] = 0; + if (strcmp(tmp, "rand") == 0) instr = QANSEL_INSTRUCTION_RAND; + else if (strcmp(tmp, "exit") == 0) instr = QANSEL_INSTRUCTION_EXIT; + } + *binarySize += 1; + *binary = realloc(*binary, (*binarySize)); + (*binary)[(*binarySize) - 1] = instr; + } + return 1; +} + +int qansel_process_chunks(char** chunks, int* associatedLines, int count, unsigned char** retBinary, int* retSize) +{ + unsigned char* binary = malloc(0); + int binarySize = 0; + int qubitCount = 0; + int bitCount = 0; + char errbuf[100]; + regex_t regex; + regmatch_t regmatches[10]; + const char regexes[][1024] = + { + "^\\s*qreg\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*$", + "^\\s*creg\\s*c\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*$", + "^\\s*(x|y|z|h|s|t|reset|barrier|born|density|print)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", + "^\\s*(rx|ry|rz|u1)\\(\\s*([-/0-9PI.]*)\\s*\\)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", + "^\\s*(u2)\\(\\s*([-/0-9PI.]*)\\s*,\\s*([-/0-9PI.]*)\\s*\\)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", + "^\\s*(u|u3)\\(\\s*([-/0-9PI.]*)\\s*,\\s*([-/0-9PI.]*)\\s*,\\s*([-/0-9PI.]*)\\s*\\)\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", + "^\\s*measure\\s*q\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*)\\s*->\\s*c\\c*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*)$", + "^\\s*(sample|reset|print)\\s*c\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]\\s*|)$", + "^\\s*(cx|cnot|swap)\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*,\\s*q\\s*\\[\\s*([0-9]*)\\s*\\]\\s*$", + "^\\s*(ccx|toffoli|cswap|fredkin)\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*,\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*,\\s*q\\s*\\[\\s*([0-9][0-9]*)\\s*\\]\\s*$", + "^\\s*if\\s*\\(\\s*c\\s*(\\[\\s*([0-9][0-9]*)\\s*\\]|)\\s*(==|!=|<>|>=|<=|>|<)\\s*([0-9][0-9]*)\\s*\\).*\\s*$", + "^\\s*(hvar)\\s*([-/0-9PI.]*)\\s*$", + "^\\s*(rand|exit)\\s*$", + }; + int ret, status = 0, found; + for (int i = 0; i < count; i++) + { + found = 0; + for (int j = 0; j < sizeof(regexes) / sizeof(regexes[0]); j++) + { + if (regcomp(®ex, regexes[j], REG_EXTENDED | REG_ICASE)) + { + printf("QAnsel: Regex fatal error.\n"); + return 0; + } + ret = regexec(®ex, chunks[i], 10, regmatches, 0); + regfree(®ex); + if (!ret) + { + found = 1; + status = qansel_process_chunk(j, chunks[i], associatedLines[i], regmatches, &qubitCount, &bitCount, &binary, &binarySize); + break; + } + else if (ret == REG_NOMATCH) {} + else + { + regerror(ret, ®ex, errbuf, sizeof(errbuf)); + fprintf(stderr, "QAnsel: %s.\n", errbuf); + return 0; + } + } + if (!status) break; + if (!found) + { + fprintf(stderr, "QAnsel on line %i: Invalid syntax.\n", associatedLines[i]); + return 0; + } + } + *retBinary = binary; + *retSize = binarySize; + return status; +} + +int qanselBuildFromSource(char* source, unsigned char** binary, int* binarySize) +{ + char** chunks; + int* chunksAssociatedLines; + int chunksCount; + int status = qansel_read_script(source, &chunks, &chunksAssociatedLines, &chunksCount); + if (!status) return 0; + status = qansel_process_chunks(chunks, chunksAssociatedLines, chunksCount, binary, binarySize); + for (int i = 0; i < chunksCount; i++) free(chunks[i]); + free(chunks); + free(chunksAssociatedLines); + free(source); + if (!status) + { + *binarySize = 0; + free(*binary); + return 0; + } + return 1; + +} + diff --git a/src/qansel.h b/src/qansel.h new file mode 100644 index 0000000..ef55269 --- /dev/null +++ b/src/qansel.h @@ -0,0 +1,64 @@ +#ifndef __QANSEL_H__ +#define __QANSEL_H__ + +#define QANSEL_MAX_SIZE 1073741824 +#include +#include +#include +#include +#include +#include "complex.c" +#include "gates.c" +#include "display.c" +#include "chacha20.c" +#define QANSEL_QUBITS_MAX 14 +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; +FILE* QANSEL_RANDOM_FILE = NULL; +#define QANSEL_MODE_BARE 0 +#define QANSEL_MODE_THREADED 1 +#define QANSEL_MODE_METAL 2 +#define QANSEL_MODE_METAL_THREADED 3 +unsigned char QANSEL_MODE = QANSEL_MODE_BARE; +//#define SPEED_TEST + +#define QANSEL_INSTRUCTION_X 0x10 +#define QANSEL_INSTRUCTION_Y 0x11 +#define QANSEL_INSTRUCTION_Z 0x12 +#define QANSEL_INSTRUCTION_H 0x13 +#define QANSEL_INSTRUCTION_S 0x14 +#define QANSEL_INSTRUCTION_T 0x15 +#define QANSEL_INSTRUCTION_RX 0x20 +#define QANSEL_INSTRUCTION_RY 0x21 +#define QANSEL_INSTRUCTION_RZ 0x22 +#define QANSEL_INSTRUCTION_U1 0x23 +#define QANSEL_INSTRUCTION_U2 0x24 +#define QANSEL_INSTRUCTION_U3 0x25 +#define QANSEL_INSTRUCTION_CX 0x30 +#define QANSEL_INSTRUCTION_SWAP 0x31 +#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_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_FLAGS_EQUAL 0b00001 +#define QANSEL_FLAGS_GREATER 0b00010 +#define QANSEL_FLAGS_LESSER 0b00100 + +#endif \ No newline at end of file