]> foleosoft.com Git - QAnsel.git/commitdiff
Sat Mar 9 08:53:46 PM EST 2024
authormiha-q <>
Sun, 10 Mar 2024 01:53:46 +0000 (20:53 -0500)
committermiha-q <>
Sun, 10 Mar 2024 01:53:46 +0000 (20:53 -0500)
src/QAnsel.c
src/bytecode.c [new file with mode: 0644]
src/complex.c
src/core.c [deleted file]
src/display.c
src/openqasm.c [new file with mode: 0644]
src/qansel.h [new file with mode: 0644]

index cb11e3a623d3b0015dab4f84fa01642b6bc67e2f..972218160cd0b1314a3e5522b10cd85a96e3dbb0 100644 (file)
-#include <regex.h>
-#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(&regex, expr, REG_EXTENDED | REG_ICASE)) return 0;
-       int ret = regexec(&regex, 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, &regex, errbuf, sizeof(errbuf));
-               fprintf(stderr, "QAnsel: %s.\n", errbuf);
+               fprintf(stderr, "QAnsel: Invalid display settings.\n");
                exit(1);
        }
-       regfree(&regex);
+       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(&regex, regexes[j], REG_EXTENDED | REG_ICASE))
-                       {
-                               printf("QAnsel: Regex fatal error.\n");
-                               exit(1);
-                       }
-                       ret = regexec(&regex, chunks[i], 10, regmatches, 0);
-                       regfree(&regex);
-                       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, &regex, 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 (file)
index 0000000..63cf248
--- /dev/null
@@ -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;
+}
index f9a57b72a31341cc2708890024711d5f0dd59db0..c1ab4e672cf44ab6d1fe989082326f5174e191bd 100644 (file)
@@ -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 (file)
index dc32ab2..0000000
+++ /dev/null
@@ -1,1107 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <time.h>
-#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);
-       }
-}
index 1862610ae74828f70de96b04d75c37000bdc32e1..5b5ff665af2347293c38b11f501de3007cb6d862 100644 (file)
@@ -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 (file)
index 0000000..f451fa5
--- /dev/null
@@ -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(&regex, expr, REG_EXTENDED | REG_ICASE)) return 0;
+       int ret = regexec(&regex, 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, &regex, errbuf, sizeof(errbuf));
+               fprintf(stderr, "QAnsel: %s.\n", errbuf);
+               exit(1);
+       }
+       regfree(&regex);
+
+       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(&regex, regexes[j], REG_EXTENDED | REG_ICASE))
+                       {
+                               printf("QAnsel: Regex fatal error.\n");
+                               return 0;
+                       }
+                       ret = regexec(&regex, chunks[i], 10, regmatches, 0);
+                       regfree(&regex);
+                       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, &regex, 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 (file)
index 0000000..ef55269
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __QANSEL_H__
+#define __QANSEL_H__
+
+#define QANSEL_MAX_SIZE 1073741824
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <regex.h>
+#include <time.h>
+#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