]> foleosoft.com Git - QAnsel.git/commitdiff
Sun Sep 10 12:28:07 AM EDT 2023
authorserver <[email protected]>
Sun, 10 Sep 2023 04:28:07 +0000 (00:28 -0400)
committerserver <[email protected]>
Sun, 10 Sep 2023 04:28:07 +0000 (00:28 -0400)
13 files changed:
Makefile [new file with mode: 0644]
bin/QAnsel [new file with mode: 0755]
examples/bb84.qsm [new file with mode: 0644]
examples/bellstate.qsm [new file with mode: 0644]
examples/encryption.qsm [new file with mode: 0644]
examples/halfadder.qsm [new file with mode: 0644]
examples/swaptest.qsm [new file with mode: 0644]
examples/teleportation.qsm [new file with mode: 0644]
src/QAnsel.c [new file with mode: 0644]
src/chacha20.c [new file with mode: 0644]
src/complex.c [new file with mode: 0644]
src/display.c [new file with mode: 0644]
src/gates.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..9b20556
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+all:
+       cd src && gcc QAnsel.c -g -o ../bin/QAnsel -lm -I/usr/include/SDL2 -D_REENTRANT -lSDL2
diff --git a/bin/QAnsel b/bin/QAnsel
new file mode 100755 (executable)
index 0000000..baa3cc7
Binary files /dev/null and b/bin/QAnsel differ
diff --git a/examples/bb84.qsm b/examples/bb84.qsm
new file mode 100644 (file)
index 0000000..a283806
--- /dev/null
@@ -0,0 +1,26 @@
+qreg q[2];
+creg c[1];
+
+//Alice sends two bits 00 
+h q[0];
+h q[1];
+
+//Eve tries to measure the first
+measure q[0] -> c[0];
+
+//Bob applies the gate before measuring
+h q[0];
+h q[1];
+
+//The first should now be random noise
+//  while the second unmeasured one
+//  should be 0
+sample;
+
+//In a full BB84 Alice would randomly
+//  apply the gate or not apply the
+//  gate so Eve would have to guess
+//  and would inevitably end up
+//  turning the transferred bits
+//  into random noise whenever there
+//  is a wrong guess.
\ No newline at end of file
diff --git a/examples/bellstate.qsm b/examples/bellstate.qsm
new file mode 100644 (file)
index 0000000..9168026
--- /dev/null
@@ -0,0 +1,5 @@
+qreg q[2];
+h q[0];
+cx q[0], q[1];
+
+sample;
diff --git a/examples/encryption.qsm b/examples/encryption.qsm
new file mode 100644 (file)
index 0000000..6be398b
--- /dev/null
@@ -0,0 +1,6 @@
+qreg q[1];
+creg c[1];
+h q[0];
+measure q[0] -> c[0];
+print c;
+
diff --git a/examples/halfadder.qsm b/examples/halfadder.qsm
new file mode 100644 (file)
index 0000000..af0f80b
--- /dev/null
@@ -0,0 +1,40 @@
+qreg q[3];
+creg c[2];
+
+//0+0
+ccx q[0], q[1], q[2];
+cx q[0], q[1];
+measure q[1] -> c[0];
+measure q[2] -> c[1];
+print c;
+
+reset;
+
+//0+1
+x q[0];
+ccx q[0], q[1], q[2];
+cx q[0], q[1];
+measure q[1] -> c[0];
+measure q[2] -> c[1];
+print c;
+
+reset;
+
+//1+0
+x q[1];
+ccx q[0], q[1], q[2];
+cx q[0], q[1];
+measure q[1] -> c[0];
+measure q[2] -> c[1];
+print c;
+
+reset;
+
+//1+1
+x q[0];
+x q[1];
+ccx q[0], q[1], q[2];
+cx q[0], q[1];
+measure q[1] -> c[0];
+measure q[2] -> c[1];
+print c;
\ No newline at end of file
diff --git a/examples/swaptest.qsm b/examples/swaptest.qsm
new file mode 100644 (file)
index 0000000..19454e0
--- /dev/null
@@ -0,0 +1,9 @@
+qreg q[3];
+u(1,2,3) q[1];
+u(1,2,3) q[2];
+
+h q[0];
+cswap q[0], q[1], q[2];
+h q[0];
+
+sample q[0];
diff --git a/examples/teleportation.qsm b/examples/teleportation.qsm
new file mode 100644 (file)
index 0000000..c9fac7d
--- /dev/null
@@ -0,0 +1,28 @@
+qreg q[3];
+creg c[2];
+
+//qubit to teleport
+u(1,2,3) q[0];
+print q[0]; //show qubit to teleport
+
+//shared entangled qubit
+h q[1];
+cx q[1], q[2];
+
+//correlate qubit to teleport
+cx q[0], q[1];
+
+//weaken correlation
+h q[0];
+
+//measure qubits
+measure q[0] -> c[0];
+measure q[1] -> c[1];
+
+//rotate based on measurement results
+if(c==2) x q[2];
+if(c==1) z q[2];
+if(c==3) x q[2];
+if(c==3) z q[2];
+
+print q[2]; //show teleported qubit
\ No newline at end of file
diff --git a/src/QAnsel.c b/src/QAnsel.c
new file mode 100644 (file)
index 0000000..716d0e1
--- /dev/null
@@ -0,0 +1,875 @@
+#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 11
+
+typedef struct
+{
+    char n[128];
+    uint8_t q0, q1, q2;
+    double arg0, arg1, arg2;
+} QInstr;
+
+double qansel_rand()
+{
+    static uint64_t hiddenVariable = 0;
+    static uint32_t blockNumber = 0;
+    if (hiddenVariable == 0)
+    {
+        struct timespec ts;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        hiddenVariable = (uint64_t)ts.tv_sec * 1000000000LL + ts.tv_nsec;
+    }
+    uint8_t key[32];
+    uint8_t nonce[12];
+    uint64_t tmpVariable;
+    for (uint8_t i = 0; i < 32; i++)
+    {
+        if (i % 8 == 0) tmpVariable = hiddenVariable;
+        key[i] = tmpVariable & 0xFF;
+        tmpVariable >> 8;
+    
+    }
+    for (uint8_t i = 0; i < 12; i++)
+    {
+        nonce[i] = 0;
+    }
+    uint8_t* block = foleo_chacha20(key, nonce, blockNumber++, 4);
+    uint32_t num = 0;
+    for (uint8_t i = 0; i < 4; i++)
+    {
+        num = (num << 8) | block[i];
+    }
+    return ((double)num) / ((double)UINT32_MAX);
+}
+
+void qansel_cnot(cpx_mtx_t* stateVector, uint8_t qubitCount, uint8_t bitA, uint8_t bitB)
+{
+    uint32_t retLen = (uint8_t)pow(2, qubitCount);
+    cpx_mtx_t ret;
+    cpx_mtx_init(&ret, 1, retLen);
+    cpx_t n;
+    for (uint32_t i = 0; i < retLen; i++)
+    {
+        uint8_t bitAVal = (i >> bitA) & 1;
+        uint8_t bitBVal = (i >> bitB) & 1;
+        uint8_t bitBNew = bitAVal ? !bitBVal : bitBVal;
+        uint32_t 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, uint8_t qubitCount, uint8_t bitA, uint8_t bitB)
+{
+    uint32_t retLen = (uint8_t)pow(2, qubitCount);
+    cpx_mtx_t ret;
+    cpx_mtx_init(&ret, 1, retLen);
+    cpx_t n;
+    for (uint32_t i = 0; i < retLen; i++)
+    {
+        uint8_t bitAVal = (i >> bitA) & 1;
+        uint8_t bitBVal = (i >> bitB) & 1;
+        uint8_t bitANew = bitBVal;
+        uint8_t bitBNew = bitAVal;
+        uint32_t 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, uint8_t qubitCount, uint8_t bitA, uint8_t bitB, uint8_t bitC)
+{
+    uint32_t retLen = (uint8_t)pow(2, qubitCount);
+    cpx_mtx_t ret;
+    cpx_mtx_init(&ret, 1, retLen);
+    cpx_t n;
+    for (uint32_t i = 0; i < retLen; i++)
+    {
+        uint8_t bitAVal = (i >> bitA) & 1;
+        uint8_t bitBVal = (i >> bitB) & 1;
+        uint8_t bitCVal = (i >> bitC) & 1;
+        uint8_t bitBNew = bitAVal ? bitCVal : bitBVal;
+        uint8_t bitCNew = bitAVal ? bitBVal : bitCVal;
+        uint32_t 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, uint8_t qubitCount, uint8_t bitA, uint8_t bitB, uint8_t bitC)
+{
+    uint32_t retLen = (uint8_t)pow(2, qubitCount);
+    cpx_mtx_t ret;
+    cpx_mtx_init(&ret, 1, retLen);
+    cpx_t n;
+    for (uint32_t i = 0; i < retLen; i++)
+    {
+        uint8_t bitAVal = (i >> bitA) & 1;
+        uint8_t bitBVal = (i >> bitB) & 1;
+        uint8_t bitCVal = (i >> bitC) & 1;
+        uint8_t bitCNew = (bitAVal && bitBVal) ? !bitCVal : bitCVal;
+        uint32_t 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;
+}
+
+double* qansel_unitary(double theta, double phi, double 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, uint8_t qubitCount, QInstr* instr)
+{
+    cpx_mtx_t tmp;
+    cpx_mtx_t gate;
+    gate.rows = 2;
+    gate.cols = 2;
+    double* gate_ptr;
+    switch (instr->n[0])
+    {
+        case 'h': gate_ptr = Hadamard; break;
+        case 'x': gate_ptr = PauliX; break;
+        case 'y': gate_ptr = PauliY; break;
+        case 'z': gate_ptr = PauliZ; break;
+        case 's': gate_ptr = PhaseS; break;
+        case 't': gate_ptr = PhaseT; break;
+        case 'u':
+            gate_ptr = qansel_unitary(instr->arg0, instr->arg1, instr->arg2);
+            break;
+        default: gate_ptr = Identity; break;
+    }
+
+    cpx_t n;
+    cpx_mtx_t filter;
+    cpx_mtx_init(&filter, 2, 2);
+    uint8_t qubit = qubitCount - (instr->q0) - 1;
+    if (qubit == 0)
+    {
+        memcpy(filter.ptr, gate_ptr, 16 * sizeof(double));
+    }
+    else
+    {
+        memcpy(filter.ptr, Identity, 16 * sizeof(double));
+    }
+
+    for (uint8_t i = 1; i < qubitCount; i++)
+    {
+        cpx_mtx_init(&tmp, filter.rows * 2, filter.cols * 2);
+        if (qubit == i)
+        {
+            gate.ptr = gate_ptr;
+        }
+        else
+        {
+            gate.ptr = Identity;
+        }
+        cpx_mtx_knk(&tmp, &filter, &gate);
+        free(filter.ptr);
+        filter.ptr = tmp.ptr;
+        filter.rows = tmp.rows;
+        filter.cols = tmp.cols;
+    }
+
+    cpx_mtx_init(&tmp, stateVector->rows, stateVector->cols);
+    cpx_mtx_mul(&tmp, stateVector, &filter);
+    free(stateVector->ptr);
+    stateVector->ptr = tmp.ptr;
+    free(filter.ptr);
+    if (instr->n[0] == 'u') free(gate_ptr);
+}
+
+
+uint8_t qansel_measure(cpx_mtx_t* stateVector, uint8_t qubitCount, uint8_t qubit)
+{
+    uint32_t qubitCountPow2 = (uint32_t)pow(2, qubitCount);
+    cpx_t n;
+    double prob0 = 0;
+    for (uint32_t i = 0; i < qubitCountPow2; i++)
+    {
+        uint8_t bit = (i >> qubit) & 1;
+        cpx_mtx_get(stateVector, 0, i, &n);
+        if (bit == 0) prob0 += cpx_magsqr(&n);
+    }
+
+    double r = qansel_rand();
+    uint8_t newBit = r < prob0 ? 0 : 1;
+    double probTot = 0;
+    for (uint32_t i = 0; i < qubitCountPow2; i++)
+    {
+        uint8_t 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);
+    }
+    
+    double multiplier = sqrt(1 / probTot);
+    for (uint32_t i = 0; i < qubitCountPow2; i++)
+    {
+        uint8_t 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;
+}
+
+void qansel_run(uint8_t qubitCount, uint8_t bitCount, QInstr* instr, uint32_t instrLen, uint8_t gfx)
+{
+    uint32_t qubitCountPow2 = (uint32_t)pow(2, qubitCount);
+
+    uint8_t bitVector[bitCount];
+    cpx_mtx_t stateVector;
+    cpx_mtx_init(&stateVector, 1, qubitCountPow2);
+    cpx_mtx_set2(&stateVector, 0, 0, 1, 0);
+    if (gfx) display(&stateVector, qubitCount);
+    uint8_t flags;
+
+    for (uint8_t i = 0; i < bitCount; i++) bitVector[i] = 0;
+    for (uint32_t i = 0; i < instrLen; i++)
+    {
+        if (strcmp(instr[i].n, "measure") == 0)
+        {
+            bitVector[instr[i].q1] = qansel_measure(&stateVector, qubitCount, instr[i].q0);
+        }
+        else if (strcmp(instr[i].n, "cswap") == 0)
+        {
+            qansel_fredkin(&stateVector, qubitCount, instr[i].q0, instr[i].q1, instr[i].q2);
+        }
+        else if (strcmp(instr[i].n, "ccx") == 0)
+        {
+            qansel_toffoli(&stateVector, qubitCount, instr[i].q0, instr[i].q1, instr[i].q2);
+        }
+        else if (strcmp(instr[i].n, "cx") == 0)
+        {
+            qansel_cnot(&stateVector, qubitCount, instr[i].q0, instr[i].q1);
+        }
+        else if (strcmp(instr[i].n, "swap") == 0)
+        {
+            qansel_swap(&stateVector, qubitCount, instr[i].q0, instr[i].q1);
+        }
+        else if (strcmp(instr[i].n, "if_all") == 0)
+        {
+            uint8_t val = 0;
+            for (int32_t j = bitCount - 1; j >= 0; j--)
+            {
+                val = (val << 1) | bitVector[j];
+            }
+            if (val != instr[i].q0) i++;
+        }
+        else if (strcmp(instr[i].n, "if") == 0)
+        {
+            if (bitVector[instr[i].q0] != instr[i].q1) i++;
+        }
+        else if (strcmp(instr[i].n, "printq_all") == 0)
+        {
+            printf("[ "); cpx_mtx_print(&stateVector); printf(" ]\n");
+        }
+        else if (strcmp(instr[i].n, "printc_all") == 0)
+        {
+            for (int32_t j = bitCount - 1; j >= 0; j--)
+            {
+                putchar('0' + bitVector[j]);
+            }
+            putchar('\n');
+        }
+        else if (strcmp(instr[i].n, "printq") == 0)
+        {
+            cpx_mtx_t tmp;
+            cpx_mtx_init(&tmp, 1, 2);
+            for (uint32_t j = 0; j < qubitCountPow2; j++)
+            {
+                if ((j >> instr[i].q0) & 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);
+                }
+            }
+            double 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);
+
+            printf("[ "); cpx_mtx_print(&tmp); printf(" ]\n");
+            cpx_mtx_free(&tmp);
+        }
+        else if (strcmp(instr[i].n, "sample_all") == 0)
+        {
+            for (uint32_t j = 0; j < qubitCountPow2; j++)
+            {
+                uint32_t tmp = j;
+                for (uint8_t k = 0; k < qubitCount; k++)
+                {
+                    putchar('0' + (tmp >> (qubitCount - 1) & 1));
+                    tmp <<= 1;
+                }
+                cpx_t n;
+                cpx_mtx_get(&stateVector, 0, j, &n);
+                printf(": %.00f%%\n", cpx_magsqr(&n) * 100);
+            }
+        }
+        else if (strcmp(instr[i].n, "sample") == 0)
+        {
+            double prob = 0;
+            for (uint32_t j = 0; j < qubitCountPow2; j++)
+            {
+                cpx_t n;
+                cpx_mtx_get(&stateVector, 0, j, &n);
+                if ((j >> instr[i].q0) & 1)
+                {
+                    prob += cpx_magsqr(&n);
+                }
+            }
+            printf("%.00f%%\n", prob * 100.0);
+        }
+        else if (strcmp(instr[i].n, "reset") == 0)
+        {
+            cpx_mtx_set2(&stateVector, 0, 0, 1, 0);
+            for (uint32_t j = 1; j < qubitCountPow2; j++)
+            {
+                cpx_mtx_set2(&stateVector, 0, j, 0, 0);
+            }
+            for (uint8_t j = 0; j < bitCount; j++)
+            {
+                bitVector[j] = 0;
+            }
+        }
+        else
+        {
+            qansel_instruction(&stateVector, qubitCount, instr + i);
+        }
+
+        if (gfx) display(&stateVector, qubitCount);
+    }
+    display(NULL, -1);
+
+    cpx_mtx_free(&stateVector);
+}
+
+void main()
+{
+    char** lines = malloc(0);
+    uint32_t* lineIDs = malloc(0);
+    char* text = malloc(0);
+    uint32_t textLen = 0;
+    uint32_t linesLen = 0;
+    int c;
+    int pc = -1;
+    uint8_t comment = 0;
+    uint8_t commentM = 0;
+    uint32_t lineID = 1;
+    uint8_t skipSpaces = 1;
+    uint8_t inGate = 0;
+    while ( (c = getchar()) != EOF )
+    {
+        if (c == '/' && commentM == 0 && comment == 0)
+        {
+            commentM = 1;
+        }
+        else if (c == '/' && commentM == 1 && comment == 0)
+        {
+            comment = 1;
+            commentM = 0;
+        }
+        else if (c == '\n')
+        {
+            comment = 0;
+            commentM = 0;
+            lineID += 1;
+        }
+        else if (comment || (c == ' ' && skipSpaces)) {}
+        else if (c != '\n' && c != '\t' && c != ';' && (c != ')' || inGate))
+        {
+            skipSpaces = 0;
+            if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
+            if (c == 'u') inGate = 1;
+            text = realloc(text, textLen + 1);
+            text[textLen++] = c;
+            pc = c;
+        }
+        else if (c == ';' || (c == ')' && !inGate))
+        {
+            inGate = 0;
+            skipSpaces = 1;
+            if (c == ')')
+            {
+                text = realloc(text, textLen + 1);
+                text[textLen++] = ')';
+            }
+            text = realloc(text, textLen + 1);
+            text[textLen++] = 0;
+            lineIDs = realloc(lineIDs, (linesLen + 1) * sizeof(uint32_t));
+            lineIDs[linesLen] = lineID;
+            lines = realloc(lines, (linesLen + 1) * sizeof(char*));
+            lines[linesLen] = malloc(strlen(text) + 1);
+            strcpy(lines[linesLen++], text);
+            text = realloc(text, 0);
+            textLen = 0;
+            pc = ';';
+        }
+    }
+    text = realloc(text, textLen + 1);
+    text[textLen++] = 0;
+    if (strlen(text) > 0)
+    {
+        free(text);
+        fprintf(stderr, "QAnsel: Invalid trailing text.\n");
+        exit(1);
+    }
+    free(text);
+    
+    uint8_t qubitCount = 0xFF;
+    uint8_t bitCount = 0xFF;
+    QInstr* instr = malloc(0);
+    uint32_t instrLen = 0;
+
+    uint8_t errFound = 0;
+    for (uint32_t i = 0; i < linesLen; i++)
+    {
+        lineID = i;
+
+        char g;
+        int q0, q1, q2;
+        float a0, a1, a2;
+
+        if (sscanf(lines[i], "qreg q[%i]", &q0) == 1)
+        {
+            if (qubitCount == 0xFF)
+            {
+                qubitCount = q0;
+                if (qubitCount < 1 || qubitCount > QUBITS_MAX)
+                {
+                    fprintf(stderr, "QAnsel: Invalid count");
+                    errFound = 1;
+                    break;
+                }
+            }
+            else
+            {
+                fprintf(stderr, "QAnsel: Repeated initialization");
+                errFound = 1;
+                break;
+            }
+        }
+        else if (sscanf(lines[i], "creg c[%i]", &q0) == 1)
+        {
+            if (bitCount == 0xFF)
+            {
+                bitCount = q0;
+                if (bitCount < 1 || bitCount > QUBITS_MAX)
+                {
+                    fprintf(stderr, "QAnsel: Invalid count");
+                    errFound = 1;
+                    break;
+                }
+            }
+            else
+            {
+                fprintf(stderr, "QAnsel: Repeated initialization");
+                errFound = 1;
+                break;
+            }
+        }
+        else if (sscanf(lines[i], "u(%f,%f,%f) q[%i]", &a0, &a1, &a2, &q0) == 4)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 < 0 || q0 >= qubitCount)
+            {
+                fprintf(stderr, "QAnsel: Invalid index ");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            instr[instrLen].n[0] = 'u';
+            instr[instrLen].n[1] = 0;
+            instr[instrLen].q0 = q0; 
+            instr[instrLen].arg0 = a0; 
+            instr[instrLen].arg1 = a1; 
+            instr[instrLen++].arg2 = a2; 
+        }
+        else if
+        (
+            sscanf(lines[i], "h q[%i]", &q0) == 1
+            || sscanf(lines[i], "x q[%i]", &q0) == 1
+            || sscanf(lines[i], "y q[%i]", &q0) == 1
+            || sscanf(lines[i], "z q[%i]", &q0) == 1
+            || sscanf(lines[i], "t q[%i]", &q0) == 1
+            || sscanf(lines[i], "z q[%i]", &q0) == 1
+        )
+        {
+            g = lines[i][0];
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 < 0 || q0 >= qubitCount)
+            {
+                fprintf(stderr, "QAnsel: Invalid index ");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            instr[instrLen].n[0] = g;
+            instr[instrLen].n[1] = 0;
+            instr[instrLen++].q0 = (uint8_t)q0;
+        }
+        else if (sscanf(lines[i], "cx q[%i], q[%i]", &q0, &q1) == 2)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction before initialization.\n");
+                errFound = 1;
+                break;
+            }            
+            if (q0 > qubitCount || q1 > qubitCount | q0 < 0 || q1 < 0 || q0 == q1)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "cx");
+            instr[instrLen].q0 = q0; 
+            instr[instrLen++].q1 = q1; 
+        }
+        else if (sscanf(lines[i], "swap q[%i], q[%i]", &q0, &q1) == 2)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction before initialization.\n");
+                errFound = 1;
+                break;
+            }            
+            if (q0 > qubitCount || q1 > qubitCount | q0 < 0 || q1 < 0 || q0 == q1)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "swap");
+            instr[instrLen].q0 = q0; 
+            instr[instrLen++].q1 = q1; 
+        }
+        else if
+        (
+            sscanf(lines[i], "cswap q[%i], q[%i], q[%i]", &q0, &q1, &q2) == 3
+            || sscanf(lines[i], "fredkin q[%i], q[%i], q[%i]", &q0, &q1, &q2) == 3
+        )
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (qubitCount < 3)
+            {
+                fprintf(stderr, "QAnsel: Three qubit gate used with insufficient qubits initialized.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 >= qubitCount || q1 >= qubitCount || q2 >= qubitCount || q0 < 0 || q1< 0 || q2 < 0 || q0 == q1 || q1 == q2 || q0 == q2)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "cswap");
+            instr[instrLen].q0 = q0; 
+            instr[instrLen].q1 = q1; 
+            instr[instrLen++].q2 = q2; 
+        }
+        else if
+        (
+            sscanf(lines[i], "ccx q[%i], q[%i], q[%i]", &q0, &q1, &q2) == 3
+            || sscanf(lines[i], "toffoli q[%i], q[%i], q[%i]", &q0, &q1, &q2) == 3
+        )
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (qubitCount < 3)
+            {
+                fprintf(stderr, "QAnsel: Three qubit gate used with insufficient qubits initialized.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 >= qubitCount || q1 >= qubitCount || q2 >= qubitCount || q0 < 0 || q1< 0 || q2 < 0 || q0 == q1 || q1 == q2 || q0 == q2)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "ccx");
+            instr[instrLen].q0 = q0; 
+            instr[instrLen].q1 = q1; 
+            instr[instrLen++].q2 = q2; 
+        }
+        else if (sscanf(lines[i], "measure q[%i] -> c[%i]", &q0, &q1) == 2)
+        {
+            if (bitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Measure instruction used before bit initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 >= qubitCount || q1 >= bitCount || q0 < 0 || q1 < 0)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "measure");
+            instr[instrLen].q0 = q0; 
+            instr[instrLen++].q1 = q1; 
+        }
+        else if (sscanf(lines[i], "if(c==%i)", &q0) == 1)
+        {
+            if (bitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: If instruction used before bit initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 < 0)
+            {
+                fprintf(stderr, "QAnsel: Invalid comparison");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "if_all");
+            instr[instrLen++].q0 = q0; 
+        }
+        else if (sscanf(lines[i], "if(c[%i]==%i)", &q0, &q1) == 2)
+        {
+            if (bitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: If instruction used before bit initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 < 0 || q1 < 0 || q0 > bitCount)
+            {
+                fprintf(stderr, "QAnsel: Invalid comparison");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "if");
+            instr[instrLen].q0 = q0;
+            instr[instrLen++].q1 = q1;
+        }
+        else if (strcmp(lines[i], "print q") == 0)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Qubit instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "printq_all");
+            instrLen++;
+        }
+        else if (strcmp(lines[i], "print c") == 0)
+        {
+            if (bitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Bit instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "printc_all");
+            instrLen++;
+        }
+        else if (sscanf(lines[i], "print q[%i]", &q0) == 1)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Qubit instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 >= qubitCount || q0 < 0)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "printq");
+            instr[instrLen++].q0 = q0; 
+        }
+        else if (sscanf(lines[i], "print c[%i]", &q0) == 1)
+        {
+            if (bitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Bit instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 >= bitCount || q0 < 0)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "printc");
+            instr[instrLen++].q0 = q0; 
+        }
+        else if (strcmp(lines[i], "sample") == 0)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Qubit instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "sample_all");
+            instrLen++;
+        }
+        else if (sscanf(lines[i], "sample q[%i]", &q0) == 1)
+        {
+            if (qubitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Qubit instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            if (q0 >= qubitCount || q0 < 0)
+            {
+                fprintf(stderr, "QAnsel: Invalid index");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "sample");
+            instr[instrLen++].q0 = q0; 
+        }
+        else if (strcmp(lines[i], "reset") == 0)
+        {
+            if (qubitCount == 0xFF || bitCount == 0xFF)
+            {
+                fprintf(stderr, "QAnsel: Instruction used before initialization.\n");
+                errFound = 1;
+                break;
+            }
+            instr = realloc(instr, (instrLen + 1) * sizeof(QInstr));
+            strcpy(instr[instrLen].n, "reset");
+            instrLen++;
+        }
+        else
+        {
+            fprintf(stderr, "QAnsel: Syntax error");
+            errFound = 1;
+            break;
+        }
+    }
+
+    for (uint32_t i = 0; i < linesLen; i++) free(lines[i]);
+    free(lines);
+
+    if (errFound)
+    {
+        printf(" on line %i.\n", lineIDs[lineID]);
+        free(lineIDs);
+        free(instr);
+        exit(1);
+    }
+
+    qansel_run(qubitCount, bitCount, instr, instrLen, 0);
+    free(instr);
+    free(lineIDs);
+}
diff --git a/src/chacha20.c b/src/chacha20.c
new file mode 100644 (file)
index 0000000..6de9777
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __FOLEO_CHACHA20__
+#define __FOLEO_CHACHA20__
+#include <stdio.h>
+#include <stdint.h>
+
+static uint32_t foleo_chacha20_lr(uint32_t a, uint8_t b)
+{
+       return (a << b) | (a >> (32 - b));
+}
+
+static void foleo_chacha20_QR(uint32_t *cc, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
+{
+       cc[a] += cc[b]; cc[d] ^= cc[a]; cc[d] = foleo_chacha20_lr(cc[d], 16);
+       cc[c] += cc[d]; cc[b] ^= cc[c]; cc[b] = foleo_chacha20_lr(cc[b], 12);
+       cc[a] += cc[b]; cc[d] ^= cc[a]; cc[d] = foleo_chacha20_lr(cc[d], 8);
+       cc[c] += cc[d]; cc[b] ^= cc[c]; cc[b] = foleo_chacha20_lr(cc[b], 7);
+}
+
+static void foleo_chacha20_DR(uint32_t *cc)
+{
+       foleo_chacha20_QR(cc, 0, 4,  8, 12);
+       foleo_chacha20_QR(cc, 1, 5,  9, 13);
+       foleo_chacha20_QR(cc, 2, 6, 10, 14);
+       foleo_chacha20_QR(cc, 3, 7, 11, 15);
+       foleo_chacha20_QR(cc, 0, 5, 10, 15);
+       foleo_chacha20_QR(cc, 1, 6, 11, 12);
+       foleo_chacha20_QR(cc, 2, 7,  8, 13);
+       foleo_chacha20_QR(cc, 3, 4,  9, 14);
+}
+
+static void foleo_chacha20_CB(uint32_t *cc)
+{
+       uint8_t i;
+       uint32_t x[16];
+       for (i = 0; i < 16; i++)
+       {
+               x[i] = cc[i];
+       }
+       for (i = 0; i < 10; i++)
+       {
+               foleo_chacha20_DR(cc);
+       }
+       for (i = 0; i < 16; i++)
+       {
+               cc[i] += x[i];
+       }
+}
+
+static void foleo_chacha20_S(uint32_t *cc, uint8_t *cs)
+{
+       for (uint8_t i = 0; i < 16; i++)
+       {
+               cs[4 * i] = (cc[i] & 0xFF);
+               cs[4 * i + 1] = ((cc[i] >> 8) & 0xFF);
+               cs[4 * i + 2] = ((cc[i] >> 16) & 0xFF);
+               cs[4 * i + 3] = ((cc[i] >> 24) & 0xFF);
+       }
+}
+
+static void foleo_chacha20_block(uint8_t key[32], uint8_t nonce[12], uint32_t block, uint8_t out[64])
+{
+       uint32_t cc[] =
+       {
+       0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
+
+          key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24),
+          key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24),
+          key[8] | (key[9] << 8) | (key[10] << 16) | (key[11] << 24),
+          key[12] | (key[13] << 8) | (key[14] << 16) | (key[15] << 24),
+
+          key[16] | (key[17] << 8) | (key[18] << 16) | (key[19] << 24),
+          key[20] | (key[21] << 8) | (key[22] << 16) | (key[23] << 24),
+          key[24] | (key[25] << 8) | (key[26] << 16) | (key[27] << 24),
+          key[28] | (key[29] << 8) | (key[30] << 16) | (key[31] << 24),
+
+       block,
+
+          nonce[0] | (nonce[1] << 8) | (nonce[2] << 16) | (nonce[3] << 24),
+          nonce[4] | (nonce[5] << 8) | (nonce[6] << 16) | (nonce[7] << 24),
+          nonce[8] | (nonce[9] << 8) | (nonce[10] << 16) | (nonce[11] << 24)
+       };
+
+       foleo_chacha20_CB(cc);
+       foleo_chacha20_S(cc, out);
+}
+
+/*Don't use block #0 if you are using this in conjunction with poly1305*/
+uint8_t* foleo_chacha20(uint8_t key[32], uint8_t nonce[12], uint32_t block, size_t count)
+{
+       if (count > (274877906944 - block * 64)) return NULL;
+       uint8_t* ret = malloc(0);
+       uint8_t ccblock[64];
+       uint64_t size = 0;
+       while (count > 64)
+       {
+               ret = realloc(ret, size + 64);
+               foleo_chacha20_block(key, nonce, block++, ccblock);
+               for (uint8_t i = 0; i < 64; i++) ret[size + i] = ccblock[i];
+               size += 64;
+               count -= 64;
+       }
+       if (count > 0)
+       {
+               ret = realloc(ret, size + count);
+               foleo_chacha20_block(key, nonce, block, ccblock);
+               for (uint8_t i = 0; i < count; i++) ret[size + i] = ccblock[i];
+       }
+       return ret;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/complex.c b/src/complex.c
new file mode 100644 (file)
index 0000000..e9736c4
--- /dev/null
@@ -0,0 +1,311 @@
+#ifndef __cpx__
+#define __cpx__
+#include <stdint.h>
+#include <stddef.h>
+#include <math.h>
+
+typedef struct
+{
+    double real, imaginary;
+} cpx_t;
+
+typedef struct
+{
+    double *ptr;
+    size_t rows, cols;
+} cpx_mtx_t;
+
+uint8_t* cpx_str(cpx_t* n)
+{
+    uint8_t* r;
+    size_t z;
+
+    double rl = n->real;
+    double ig = n->imaginary >= 0 ? n->imaginary : -(n->imaginary);
+    if (ig == 0)
+    {
+        z = snprintf(NULL, 0, "%f", rl);
+        r = malloc(z + 1);
+        sprintf(r, "%f", rl);
+
+    }
+    else
+    {
+        uint8_t op = n->imaginary >= 0 ? '+' : '-';
+        z = snprintf(NULL, 0, "%f %c %fi", rl, op, ig);
+        r = malloc(z + 1);
+        sprintf(r, "%f %c %fi", rl, op, ig);
+    }
+    return r;
+}
+
+cpx_t cpx_new(double r, double i)
+{
+    cpx_t n;
+    n.real = r;
+    n.imaginary = i;
+    return n;
+}
+
+void cpx_add(cpx_t* r, cpx_t* a, cpx_t* b)
+{
+    r->real = a->real + b->real;
+    r->imaginary = a->imaginary + b->imaginary;
+}
+
+void cpx_sub(cpx_t* r, cpx_t* a, cpx_t* b)
+{
+    r->real = a->real - b->real;
+    r->imaginary = a->imaginary - b->imaginary;
+}
+
+void cpx_mul(cpx_t* r, cpx_t* a, cpx_t* b)
+{
+    //FOIL
+    double first = a->real * b->real; //real
+    double outer = a->real * b->imaginary; //imaginary
+    double inner = a->imaginary * b->real; //imaginary
+    double last  = -(a->imaginary * b->imaginary); //real
+    r->real = first + last;
+    r->imaginary = outer + inner;
+}
+
+//non-complex matrix multiply
+//  shared = colsA = rowsB
+void cpx_ncpx_mmul(double* ptrR, double* ptrA, double* ptrB, size_t rowsA, size_t colsB, size_t shared)
+{
+    size_t colsA = shared;
+    size_t rowsB = shared;
+    size_t rowsR = rowsA;
+    size_t colsR = colsB;
+    for (size_t rowR = 0; rowR < rowsR; rowR++)
+    {
+        for (size_t colR = 0; colR < colsR; colR++)
+        {
+            size_t posR = colR + rowR * colsR;
+            size_t rowA = rowR;
+            size_t colB = colR;
+            ptrR[posR] = 0;
+            for (size_t i = 0; i < shared; i++)
+            {
+                size_t posA = i + rowA * colsA;
+                size_t posB = colB + i * colsB;
+                ptrR[posR] += ptrA[posA] * ptrB[posB];
+            }
+        }
+    }
+}
+
+//non-complex kronecker product
+void cpx_ncpx_mknk(double* ptrR, double* ptrA, double* ptrB, size_t rowsA, size_t colsA, size_t rowsB, size_t colsB)
+{
+    size_t rowsR = rowsA * rowsB;
+    size_t colsR = colsA * colsB;
+    for (size_t rowR = 0; rowR < rowsR; rowR++)
+    {
+        for (size_t colR = 0; colR < colsR; colR++)
+        {
+            size_t rowA = rowR / rowsB;
+            size_t colA = colR / colsB;
+            size_t rowB = rowR % rowsB;
+            size_t colB = colR % colsB;
+            printf(">%i,%i|%i<\n", colR, rowR, colR + rowR * colsR);
+            ptrR[colR + rowR * colsR] =
+                ptrA[colA + rowA * colsA]
+                * ptrB[colB + rowB * colsB]
+            ;
+        }
+    }
+}
+
+double cpx_magsqr(cpx_t* n)
+{
+    return (n->real * n->real) + (n->imaginary * n->imaginary);
+}
+
+double cpx_mag(cpx_t* n)
+{
+    return sqrt((n->real * n->real) + (n->imaginary * n->imaginary));
+}
+
+void cpx_mtx_mul(cpx_mtx_t* r, cpx_mtx_t* a, cpx_mtx_t* b)
+{
+    r->rows = a->rows;
+    r->cols = b->cols;
+    cpx_ncpx_mmul(r->ptr, a->ptr, b->ptr, a->rows * 2, b->cols * 2, a->cols * 2);
+}
+
+void cpx_mtx_set(cpx_mtx_t* m, size_t row, size_t col, cpx_t* n)
+{
+    row *= 2;
+    col *= 2;
+    size_t cols = m->cols * 2;
+    m->ptr[col + row * cols] = n->real;
+    m->ptr[(col + 1) + row * cols] = -(n->imaginary);
+    m->ptr[col + (row + 1) * cols] = n->imaginary;
+    m->ptr[(col + 1) + (row + 1) * cols] = n->real;
+}
+
+void cpx_mtx_set2(cpx_mtx_t* m, size_t row, size_t col, double real, double imaginary)
+{
+    row *= 2;
+    col *= 2;
+    size_t cols = m->cols * 2;
+    m->ptr[col + row * cols] = real;
+    m->ptr[(col + 1) + row * cols] = -imaginary;
+    m->ptr[col + (row + 1) * cols] = imaginary;
+    m->ptr[(col + 1) + (row + 1) * cols] = real;
+}
+
+void cpx_mtx_get(cpx_mtx_t* m, size_t row, size_t col, cpx_t* n)
+{
+    row *= 2;
+    col *= 2;
+    size_t cols = m->cols * 2;
+    n->real = m->ptr[(col + 1) + (row + 1) * cols];
+    n->imaginary = m->ptr[col + (row + 1) * cols];
+}
+
+double cpx_mtx_get_real(cpx_mtx_t* m, size_t row, size_t col)
+{
+    row *= 2;
+    col *= 2;
+    size_t cols = m->cols * 2;
+    return m->ptr[(col + 1) + (row + 1) * cols];
+}
+
+double cpx_mtx_get_imaginary(cpx_mtx_t* m, size_t row, size_t col)
+{
+    row *= 2;
+    col *= 2;
+    size_t cols = m->cols * 2;
+    return m->ptr[col + (row + 1) * cols];
+}
+
+void cpx_mtx_init(cpx_mtx_t* m, size_t rows, size_t cols)
+{
+    m->rows = rows;
+    m->cols = cols;
+    size_t z = (rows * 2) * (cols * 2);
+    m->ptr = malloc(z * sizeof(double));
+    for (size_t i = 0; i < z; i++) m->ptr[i] = 0;
+}
+
+void cpx_mtx_expand_row(cpx_mtx_t* m)
+{
+    m->rows += 1;
+    size_t z = (m->rows * 2) * (m->cols * 2);
+    m->ptr = realloc(m->ptr, z * sizeof(double));
+}
+
+
+void cpx_mtx_free(cpx_mtx_t* m)
+{
+    if (m->ptr != NULL) free(m->ptr);
+    m->rows = 0;
+    m->cols = 0;
+}
+
+void cpx_mtx_knk2
+(
+    double* ptrR,
+    size_t rowsR,
+    size_t colsR,
+    double* ptrA,
+    size_t rowsA,
+    size_t colsA,
+    double* ptrB,
+    size_t rowsB,
+    size_t colsB
+)
+{
+    for (size_t rowR = 0; rowR < rowsR; rowR++)
+    {
+        for (size_t colR = 0; colR < colsR; colR++)
+        {
+            size_t rowA = rowR / rowsB;
+            size_t colA = colR / colsB;
+            size_t rowB = rowR % rowsB;
+            size_t colB = colR % colsB;
+
+            double r1 = ptrA[((colA * 2) + 1) + ((rowA * 2) + 1) * (colsA * 2)];
+            double i1 = ptrA[(colA * 2) + ((rowA * 2) + 1) * (colsA * 2)];
+            double r2 = ptrB[((colB * 2) + 1) + ((rowB * 2) + 1) * (colsB * 2)];
+            double i2 = ptrB[(colB * 2) + ((rowB * 2) + 1) * (colsB * 2)];
+
+            double first = r1 * r2; //real
+            double outer = r1 * i2; //imaginary
+            double inner = i1 * r2; //imaginary
+            double last  = -(i1 * i2); //real
+            r1 = first + last;
+            i1 = outer + inner;
+
+            ptrR[(colR * 2) + (rowR * 2) * (colsR * 2)] = r1;
+            ptrR[((colR * 2) + 1) + (rowR * 2) * (colsR * 2)] = -i1;
+            ptrR[(colR * 2) + ((rowR * 2) + 1) * (colsR * 2)] = i1;
+            ptrR[((colR * 2) + 1) + ((rowR * 2) + 1) * (colsR * 2)] = r1;
+            
+        }
+    }
+}
+
+void cpx_mtx_knk(cpx_mtx_t* r, cpx_mtx_t* a, cpx_mtx_t* b)
+{
+    size_t rowsA = a->rows;
+    size_t colsA = a->cols;
+    size_t rowsB = b->rows;
+    size_t colsB = b->cols;
+    size_t rowsR = rowsA * rowsB;
+    size_t colsR = colsA * colsB;
+    cpx_mtx_init(r, rowsR, colsR);
+    for (size_t rowR = 0; rowR < rowsR; rowR++)
+    {
+        for (size_t colR = 0; colR < colsR; colR++)
+        {
+            size_t rowA = rowR / rowsB;
+            size_t colA = colR / colsB;
+            size_t rowB = rowR % rowsB;
+            size_t colB = colR % colsB;
+            cpx_t n1, n2;
+            
+            cpx_mtx_get(a, rowA, colA, &n1);
+            cpx_mtx_get(b, rowB, colB, &n2);
+            cpx_mul(&n1, &n1, &n2);
+
+            cpx_mtx_set(r, rowR, colR, &n1);
+        }
+    }
+}
+
+
+void cpx_mtx_(cpx_mtx_t* m)
+{
+    for (size_t r = 0; r < m->rows * 2; r++)
+    {
+        for (size_t c = 0; c < m->cols * 2; c++)
+        {
+            if (c > 0) printf(", ");
+            printf("%f", m->ptr[c + r * m->cols * 2]);
+        }
+        printf("\n");
+    }
+}
+
+void cpx_mtx_print(cpx_mtx_t* m)
+{
+    for (size_t r = 0; r < m->rows; r++)
+    {
+        if (r > 0) printf("\n");
+        for (size_t c = 0; c < m->cols; c++)
+        {
+            cpx_t n;
+            cpx_mtx_get(m, r, c, &n);
+            uint8_t* s = cpx_str(&n);
+            if (c > 0) printf(", ");
+            printf("%s", s);
+            free(s);
+        }
+    }
+}
+
+#endif
diff --git a/src/display.c b/src/display.c
new file mode 100644 (file)
index 0000000..02ff639
--- /dev/null
@@ -0,0 +1,122 @@
+#include <SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+#include "complex.c"
+
+void DrawThickLine(SDL_Renderer* renderer, int x1, int y1, int x2, int y2, int thickness) {
+    int deltaX = x2 - x1;
+    int deltaY = y2 - y1;
+    float length = sqrt(deltaX * deltaX + deltaY * deltaY);
+    float nx = deltaY / length;
+    float ny = -deltaX / length;
+    int halfThickness = thickness / 2;
+
+    for (int i = -halfThickness; i <= halfThickness; ++i) {
+        int offsetx = i * nx;
+        int offsety = i * ny;
+        SDL_RenderDrawLine(renderer, x1 + offsetx, y1 + offsety, x2 + offsetx, y2 + offsety);
+    }
+}
+
+void display(cpx_mtx_t* stateVector, uint8_t qubitCount)
+{
+    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;
+    int SCREEN_WIDTH = 640 * 2;
+    int SCREEN_HEIGHT = 480;
+
+    if (stateVector == NULL)
+    {
+        SDL_DestroyRenderer(renderer);
+        SDL_DestroyWindow(window);
+        SDL_Quit();
+        return;
+    }
+
+    if (displayInitialized == 0)
+    {
+        if (SDL_Init(SDL_INIT_VIDEO))
+        {
+            fprintf(stderr, "Failed to open graphical window.\n");
+            exit(1);
+        }
+        window = SDL_CreateWindow
+        (
+            "D",
+            SDL_WINDOWPOS_UNDEFINED,
+            SDL_WINDOWPOS_UNDEFINED,
+            SCREEN_WIDTH,
+            SCREEN_HEIGHT,
+            SDL_WINDOW_SHOWN
+        );
+        if (window == NULL)
+        {
+            fprintf(stderr, "Failed to open graphical window.\n");
+            exit(1);
+        }
+        renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
+        if (renderer == NULL)
+        {
+            fprintf(stderr, "Failed to open graphical window.\n");
+            exit(1);
+        }
+        displayInitialized = 1;
+    }
+    SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
+    SDL_RenderClear(renderer);
+    SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00);
+
+    double p0 = 0;
+    double i0 = 0;
+    for (int i = -20; i < SCREEN_WIDTH; i++)
+    {
+        double p1 = 0;
+        double i1 = 0;
+        for (int j = 1; j <= qubitCountPow2; j++)
+        {
+            cpx_t n;
+            cpx_mtx_get(stateVector, 0, j - 1, &n);
+            p1 += (sin(i * ((2 * M_PI) / (SCREEN_WIDTH / j))) * (SCREEN_HEIGHT / 4)) * (n.real * n.real) * (n.real < 0 ? -1 : 1);
+            i1 += (cos(i * ((2 * M_PI) / (SCREEN_WIDTH / j))) * (SCREEN_HEIGHT / 4)) * (n.imaginary * n.imaginary) * (n.imaginary < 0 ? -1 : 1);
+        }
+
+        int x0 = i - 1;
+        int y0 = p0;
+        int x1 = i;
+        int y1 = p1;
+
+        x0 += i0 / 4;
+        y0 += i0 / 2;
+        x1 += i1 / 4;
+        y1 += i1 / 2;
+
+        y0 += SCREEN_HEIGHT / 2;
+        y1 += SCREEN_HEIGHT / 2;
+
+        if ( (i0 + i1) / 2 < 0)
+        {
+            SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
+            DrawThickLine(renderer, x0, SCREEN_HEIGHT / 2, x1, SCREEN_HEIGHT / 2, 5);
+            SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00);
+            DrawThickLine(renderer, x0, y0, x1, y1, 5);
+        }
+        else
+        {
+            DrawThickLine(renderer, x0, y0, x1, y1, 5);
+            SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
+            DrawThickLine(renderer, x0, SCREEN_HEIGHT / 2, x1, SCREEN_HEIGHT / 2, 5);
+            SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00);
+        }
+        p0 = p1;
+        i0 = i1;
+    }
+
+    SDL_RenderPresent(renderer); // Update screen.
+    SDL_Delay(500); // Wait for two seconds.
+
+}
\ No newline at end of file
diff --git a/src/gates.c b/src/gates.c
new file mode 100644 (file)
index 0000000..347a72e
--- /dev/null
@@ -0,0 +1,81 @@
+
+double Identity[] = 
+{
+    1, 0,    0, 0,    
+    0, 1,    0, 0,
+
+    0, 0,    1, 0,    
+    0, 0,    0, 1
+};
+
+double PauliX[] = 
+{
+    0, 0,    1, 0,    
+    0, 0,    0, 1,
+
+    1, 0,    0, 0,    
+    0, 1,    0, 0
+};
+
+double PauliY[] =
+{
+    0, 0,    0, 1,
+    0, 0,   -1, 0,
+
+    0,-1,    0, 0,
+    1, 0,    0, 0,
+};
+
+double PauliZ[] = 
+{
+    1, 0,    0, 0,    
+    0, 1,    0, 0,
+
+    0, 0,   -1, 0,    
+    0, 0,    0,-1
+};
+
+//  1/sqrt(2)
+#define R 0.7071067811865475
+double Hadamard[] =
+{
+    R, 0,   R, 0,
+    0, R,   0, R,
+
+    R, 0,  -R, 0,
+    0, R,   0,-R,
+};
+
+double PhaseS[] =
+{
+    1, 0,    0, 0,
+    0, 1,    0, 0,
+
+    0, 0,    0,-1,
+    0, 0,    0, 0
+};
+
+// 1/sqrt(2) + 1/sqrt(2)i
+double PhaseT[] =
+{
+    1, 0,    0, 0,
+    0, 1,    0, 0,
+
+    0, 0,    R,-R,
+    0, 0,    R, R
+};
+
+double ControlledNOT[] = 
+{
+    1, 0,    0, 0,    0, 0,    0, 0,
+    0, 1,    0, 0,    0, 0,    0, 0, 
+
+    0, 0,    1, 0,    0, 0,    0, 0,   
+    0, 0,    0, 1,    0, 0,    0, 0, 
+
+    0, 0,    0, 0,    0, 0,    1, 0,
+    0, 0,    0, 0,    0, 0,    0, 1,
+
+    0, 0,    0, 0,    1, 0,    0, 0,   
+    0, 0,    0, 0,    0, 1,    0, 0, 
+};
\ No newline at end of file