From e4b6dd328577071720c58c18153e41dcabf5db10 Mon Sep 17 00:00:00 2001 From: Victor <131750770+pitkro@users.noreply.github.com> Date: Fri, 2 May 2025 14:09:09 +0200 Subject: [PATCH 1/6] added Coordinates and QuantumState class --- src/Qbead.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/Qbead.h b/src/Qbead.h index 80f3b0d..4f3b8ce 100644 --- a/src/Qbead.h +++ b/src/Qbead.h @@ -109,6 +109,55 @@ void connect_callback(uint16_t conn_handle) namespace Qbead { + class Coordinates{ + public: + float x, y, z; + + Coordinates(float argx, float argy, float argz) { + x = argx; + y = argy; + z = argz; + } + Coordinates(float Theta, float Phi) { + if !checkThetaAndPhi(Theta, Phi) { + x = 0; + y = 0; + z = 1; + return; + } + + x = sin(Theta) * cos(Phi); + y = sin(Theta) * sin(Phi); + z = cos(Theta); + } + + float Theta() { + float ll = x * x + y * y + z * z; + float l = sqrt(ll); + float theta = acos(z / l); + return theta; + } + + float Phi() { + float ll = x * x + y * y + z * z; + float l = sqrt(ll); + float phi = atan2(y, x); + return phi; + } + } + +class QuantumState { + private: + Coordinates stateCoordinates; + public: + QuantumState(Coordinates argStateCoordinates) { + stateCoordinates = argStateCoordinates; + } + QuantumState() { + stateCoordinates = Coordinates(0, 0, 1); + } +} + class Qbead { public: Qbead(const uint16_t pin00 = QB_LEDPIN, From 1aa5140adc86d53379303658c5c9031ddd7c85d8 Mon Sep 17 00:00:00 2001 From: Victor <131750770+pitkro@users.noreply.github.com> Date: Fri, 2 May 2025 14:12:55 +0200 Subject: [PATCH 2/6] added debug message --- src/Qbead.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Qbead.h b/src/Qbead.h index 4f3b8ce..6b1836b 100644 --- a/src/Qbead.h +++ b/src/Qbead.h @@ -120,6 +120,7 @@ namespace Qbead { } Coordinates(float Theta, float Phi) { if !checkThetaAndPhi(Theta, Phi) { + Serial.Print("Theta or Phi out of range when creating coordinates class, initializing as 1") x = 0; y = 0; z = 1; From 6fa6898b5ae330862670ce22b6010e61ecd5ccb4 Mon Sep 17 00:00:00 2001 From: Victor <131750770+pitkro@users.noreply.github.com> Date: Sat, 3 May 2025 17:35:45 +0200 Subject: [PATCH 3/6] Update src/Qbead.h Co-authored-by: Ard Geuze <63558466+ardjuh@users.noreply.github.com> --- src/Qbead.h | 117 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 39 deletions(-) diff --git a/src/Qbead.h b/src/Qbead.h index 6b1836b..a7a6daf 100644 --- a/src/Qbead.h +++ b/src/Qbead.h @@ -109,55 +109,94 @@ void connect_callback(uint16_t conn_handle) namespace Qbead { - class Coordinates{ - public: - float x, y, z; - - Coordinates(float argx, float argy, float argz) { - x = argx; - y = argy; - z = argz; - } - Coordinates(float Theta, float Phi) { - if !checkThetaAndPhi(Theta, Phi) { - Serial.Print("Theta or Phi out of range when creating coordinates class, initializing as 1") - x = 0; - y = 0; - z = 1; - return; - } +class Coordinates +{ +public: + float x, y, z; - x = sin(Theta) * cos(Phi); - y = sin(Theta) * sin(Phi); - z = cos(Theta); + Coordinates(float argx, float argy, float argz) + { + x = argx; + y = argy; + z = argz; + } + Coordinates(float theta, float phi) + { + if (!checkThetaAndPhi(theta, phi)) + { + Serial.println("Theta or Phi out of range when creating coordinates class, initializing as 1"); + x = 0; + y = 0; + z = 1; + return; } - float Theta() { - float ll = x * x + y * y + z * z; - float l = sqrt(ll); - float theta = acos(z / l); - return theta; - } + x = sin(theta) * cos(phi); + y = sin(theta) * sin(phi); + z = cos(theta); + } + + float theta() + { + float ll = x * x + y * y + z * z; + float l = sqrt(ll); + float theta = acos(z / l); + return theta; + } + + float phi() + { + float phi = atan2(y, x); + return phi; + } + + void set(float argx, float argy, float argz) + { + x = argx; + y = argy; + z = argz; + } - float Phi() { - float ll = x * x + y * y + z * z; - float l = sqrt(ll); - float phi = atan2(y, x); - return phi; + void set(float theta, float phi) + { + if (!checkThetaAndPhi(theta, phi)) + { + Serial.println("Theta or Phi out of range when creating coordinates class, initializing as 1"); + x = 0; + y = 0; + z = 1; + return; } + + x = sin(theta) * cos(phi); + y = sin(theta) * sin(phi); + z = cos(theta); } +}; -class QuantumState { - private: +class QuantumState +{ +private: Coordinates stateCoordinates; - public: - QuantumState(Coordinates argStateCoordinates) { - stateCoordinates = argStateCoordinates; + +public: + QuantumState(Coordinates argStateCoordinates) : stateCoordinates(argStateCoordinates) {} + QuantumState() : stateCoordinates(0, 0, 1) {} + + void setCoordinates(Coordinates argStateCoordinates) + { + stateCoordinates.set(argStateCoordinates.x, argStateCoordinates.y, argStateCoordinates.z); } - QuantumState() { - stateCoordinates = Coordinates(0, 0, 1); + + int collapse() + { + const float theta = stateCoordinates.theta(); + const float a = cos(theta / 2); + const bool is1 = random(0, 100) < a * a * 100; + this->stateCoordinates.set(0, 0, is1 ? 1 : -1); + return is1 ? 1 : 0; } -} +}; class Qbead { public: From 620ccda0c2288510d145998722ed080e52b9f98f Mon Sep 17 00:00:00 2001 From: Victor <131750770+pitkro@users.noreply.github.com> Date: Tue, 6 May 2025 16:04:41 +0200 Subject: [PATCH 4/6] fixed angle conversion between rad/deg --- src/Qbead.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Qbead.h b/src/Qbead.h index a7a6daf..0f845a3 100644 --- a/src/Qbead.h +++ b/src/Qbead.h @@ -130,6 +130,8 @@ class Coordinates z = 1; return; } + theta = theta*M_PI/180; + phi = phi*M_PI/180; x = sin(theta) * cos(phi); y = sin(theta) * sin(phi); @@ -141,12 +143,14 @@ class Coordinates float ll = x * x + y * y + z * z; float l = sqrt(ll); float theta = acos(z / l); - return theta; + return theta*180/M_PI; } float phi() { float phi = atan2(y, x); + phi = phi*180/M_PI; + if (phi<0) {phi+=360;}// to bring it to [0,360] range return phi; } @@ -167,6 +171,8 @@ class Coordinates z = 1; return; } + theta = theta*M_PI/180; + phi = phi*M_PI/180; x = sin(theta) * cos(phi); y = sin(theta) * sin(phi); From 988860bd6642f9a3b1fbc08142cd7f5e0bf95ee5 Mon Sep 17 00:00:00 2001 From: Victor <131750770+pitkro@users.noreply.github.com> Date: Wed, 7 May 2025 10:47:52 +0200 Subject: [PATCH 5/6] added rounding to setters --- src/Qbead.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Qbead.h b/src/Qbead.h index 0f845a3..af0400f 100644 --- a/src/Qbead.h +++ b/src/Qbead.h @@ -133,9 +133,9 @@ class Coordinates theta = theta*M_PI/180; phi = phi*M_PI/180; - x = sin(theta) * cos(phi); - y = sin(theta) * sin(phi); - z = cos(theta); + x = round(sin(theta) * cos(phi) * 1000) / 1000; + y = round(sin(theta) * sin(phi) * 1000) / 1000; + z = round(cos(theta) * 1000) / 1000; } float theta() @@ -174,9 +174,9 @@ class Coordinates theta = theta*M_PI/180; phi = phi*M_PI/180; - x = sin(theta) * cos(phi); - y = sin(theta) * sin(phi); - z = cos(theta); + x = round(sin(theta) * cos(phi) * 1000) / 1000; + y = round(sin(theta) * sin(phi) * 1000) / 1000; + z = round(cos(theta) * 1000) / 1000; } }; From 7d8c6cf9eed3754ed3c7d9f4d4b144902dc8a9d8 Mon Sep 17 00:00:00 2001 From: Ard Geuze Date: Tue, 27 May 2025 15:21:22 +0200 Subject: [PATCH 6/6] Add final classes --- src/Qbead.h | 220 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 173 insertions(+), 47 deletions(-) diff --git a/src/Qbead.h b/src/Qbead.h index af0400f..37d4e32 100644 --- a/src/Qbead.h +++ b/src/Qbead.h @@ -6,9 +6,11 @@ #include #include #include - +#include #include +using namespace Eigen; + // default configs #define QB_LEDPIN 0 #define QB_PIXELCONFIG NEO_BRG + NEO_KHZ800 @@ -34,6 +36,7 @@ const uint8_t QB_UUID_ACC_CHAR[] = {0x45,0x8d,0x08,0xaa,0xd6,0x63,0x44,0x25,0xbe,0x12,0x9c,0x35,0xc6+3,0x1f,0x0c,0xe3}; const uint8_t zerobuffer20[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; +const std::complex i(0, 1); // TODO manage namespaces better static uint32_t color(uint8_t r, uint8_t g, uint8_t b) { @@ -107,76 +110,114 @@ void connect_callback(uint16_t conn_handle) Serial.println(central_name); } +// In rads +void sphericalToCartesian(float theta, float phi, float& x, float& y, float& z) +{ + // Normalize yaw to be between 0 and 2*PI + phi = fmod(phi, 2 * PI); + if (phi < 0) + { + phi += 2 * PI; + } + if (!checkThetaAndPhi(theta * 180 / PI, phi * 180 / PI)) + { + Serial.print("Theta or Phi out of range when creating coordinates class, initializing as 1"); + Serial.print("Theta: "); + Serial.print(theta); + Serial.print("Phi: "); + Serial.println(phi); + x = 0; + y = 0; + z = 1; + return; + } + + x = sin(theta) * cos(phi); + y = sin(theta) * sin(phi); + z = cos(theta); +} + namespace Qbead { class Coordinates { public: - float x, y, z; + Vector3d v; Coordinates(float argx, float argy, float argz) { - x = argx; - y = argy; - z = argz; + v = Vector3d(argx, argy, argz); + v.normalize(); } + + // In rads Coordinates(float theta, float phi) { - if (!checkThetaAndPhi(theta, phi)) - { - Serial.println("Theta or Phi out of range when creating coordinates class, initializing as 1"); - x = 0; - y = 0; - z = 1; - return; - } - theta = theta*M_PI/180; - phi = phi*M_PI/180; + float x, y, z = 0; + sphericalToCartesian(theta, phi, x, y, z); + v = Vector3d(x, y, z); + } - x = round(sin(theta) * cos(phi) * 1000) / 1000; - y = round(sin(theta) * sin(phi) * 1000) / 1000; - z = round(cos(theta) * 1000) / 1000; + Coordinates(Vector3d vector) + { + v = vector; + v.normalize(); } + // In rads float theta() { - float ll = x * x + y * y + z * z; - float l = sqrt(ll); - float theta = acos(z / l); - return theta*180/M_PI; + return acos(v(2)); } + // In rads float phi() { - float phi = atan2(y, x); - phi = phi*180/M_PI; - if (phi<0) {phi+=360;}// to bring it to [0,360] range - return phi; + return atan2(v(1), v(0)); + } + + Vector2cf stateVector2D() + { + std::complex alpha = cos(theta()/2); + std::complex beta = exp(i*phi()) * sin(theta()/2); + return {alpha, beta}; + } + + float dist(Vector3d other) const + { + Vector3d diff = v - other; + return diff.norm(); } void set(float argx, float argy, float argz) { - x = argx; - y = argy; - z = argz; + v = Vector3d(argx, argy, argz); + v.normalize(); } + // in rads void set(float theta, float phi) { - if (!checkThetaAndPhi(theta, phi)) - { - Serial.println("Theta or Phi out of range when creating coordinates class, initializing as 1"); - x = 0; - y = 0; - z = 1; - return; - } - theta = theta*M_PI/180; - phi = phi*M_PI/180; + float x, y, z = 0; + sphericalToCartesian(theta, phi, x, y, z); + v = Vector3d(x, y, z); + } + + void set(Vector3d vector) { + v = vector; + v.normalize(); + } + + // in rads + void setTheta(float theta) + { + set(theta, phi()); + } - x = round(sin(theta) * cos(phi) * 1000) / 1000; - y = round(sin(theta) * sin(phi) * 1000) / 1000; - z = round(cos(theta) * 1000) / 1000; + // in rads + void setPhi(float phi) + { + set(theta(), phi); } }; @@ -191,16 +232,101 @@ class QuantumState void setCoordinates(Coordinates argStateCoordinates) { - stateCoordinates.set(argStateCoordinates.x, argStateCoordinates.y, argStateCoordinates.z); + stateCoordinates.set(argStateCoordinates.v); + } + + Coordinates getCoordinates() + { + return stateCoordinates; } - int collapse() + void collapse() { const float theta = stateCoordinates.theta(); - const float a = cos(theta / 2); - const bool is1 = random(0, 100) < a * a * 100; + const float a = (cos(theta) + 1) / 2; // probability of measuring |0> + if (a < 0.0001) { + stateCoordinates.set(0, 0, -1); + return; + } else if (a > 0.9999) { + stateCoordinates.set(0, 0, 1); + return; + } + const bool is1 = random(0, 100) <= a * a * 100; this->stateCoordinates.set(0, 0, is1 ? 1 : -1); - return is1 ? 1 : 0; + } + + void applyGate(Matrix2cf gate) + { + Vector2cf stateVector = stateCoordinates.stateVector2D(); + stateVector = gate * stateVector; + stateVector.normalize(); + stateCoordinates.set(2*acos(abs(stateVector.x())), arg(stateVector.y()) - arg(stateVector.x())); + } + + void applyGateType(uint16_t gateType, float rotationDegree = PI) + { + switch (gateType) + { + case 1: + gateX(-rotationDegree); + break; + case 2: + gateY(-rotationDegree); + break; + case 3: + gateZ(rotationDegree); + break; + case 4: + gateX(rotationDegree); + break; + case 5: + gateY(rotationDegree); + break; + case 6: + gateZ(-rotationDegree); + break; + case 7: + gateH(rotationDegree); + break; + default: + break; + } + } + + // Rotate PI around the x axis + void gateX(float rotationDegree = PI) + { + Matrix2cf gateMatrix; + gateMatrix << cos(rotationDegree / 2.0f), -sin(rotationDegree / 2.0f) * i, + -sin(rotationDegree / 2.0f) * i, cos(rotationDegree / 2.0f); // global phase differs from pauli gates but this doesn't matter for bloch sphere + applyGate(gateMatrix); + } + + // Rotate PI around the y axis + void gateZ(float rotationDegree = PI) + { + Matrix2cf gateMatrix; + gateMatrix << exp(-i * rotationDegree / 2.0f), 0, + 0, exp(i * rotationDegree / 2.0f); + applyGate(gateMatrix); + } + + // Rotate PI around the z axis + void gateY(float rotationDegree = PI) + { + Matrix2cf gateMatrix; + gateMatrix << cos(rotationDegree / 2.0f), -sin(rotationDegree / 2.0f), + sin(rotationDegree / 2.0f), cos(rotationDegree / 2.0f); + applyGate(gateMatrix); + } + + // Rotate PI around the xz axis + void gateH(float rotationDegree = PI) + { + Matrix2cf gateMatrix; + gateMatrix << (cos(rotationDegree / 2.0f) - i * sin(rotationDegree / 2.0f) / sqrt(2.0f)), -i * sin(rotationDegree / 2.0f) / sqrt(2.0f), + -i * sin(rotationDegree / 2.0f) / sqrt(2.0f), (cos(rotationDegree / 2.0f) + i * sin(rotationDegree / 2.0f) / sqrt(2.0f)); + applyGate(gateMatrix); } };