aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-06 22:24:37 +0200
committerhachem <im@hachem.wtf>2026-09-06 22:24:37 +0200
commit5cfc8515fdbe22214dc9840568ad41a73c105200 (patch)
tree4e2b0156f944033ca54760ce4cccff5258581c1c
parentbaecb524fb2b8162409d86d84cdddbd20b930c50 (diff)
add: quantum circuit builder
-rw-r--r--include/core/circuit.h110
-rw-r--r--include/psi.h10
-rw-r--r--src/core/circuit.c306
-rw-r--r--tester/main.c35
4 files changed, 453 insertions, 8 deletions
diff --git a/include/core/circuit.h b/include/core/circuit.h
new file mode 100644
index 0000000..bbc864c
--- /dev/null
+++ b/include/core/circuit.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "core/custom_gate.h"
+#include "maths/vector.h"
+
+enum PsiGateKind
+{
+ PSI_GATE_H,
+ PSI_GATE_X,
+ PSI_GATE_Y,
+ PSI_GATE_Z,
+ PSI_GATE_S,
+ PSI_GATE_T,
+ PSI_GATE_SDG,
+ PSI_GATE_TDG,
+ PSI_GATE_SX,
+ PSI_GATE_SXDG,
+ PSI_GATE_RX,
+ PSI_GATE_RY,
+ PSI_GATE_RZ,
+ PSI_GATE_P,
+ PSI_GATE_U1,
+ PSI_GATE_U2,
+ PSI_GATE_U3,
+ PSI_GATE_CNOT,
+ PSI_GATE_CZ,
+ PSI_GATE_SWAP,
+ PSI_GATE_CRX,
+ PSI_GATE_CRY,
+ PSI_GATE_CRZ,
+ PSI_GATE_CP,
+ PSI_GATE_CCNOT,
+ PSI_GATE_CSWAP,
+ PSI_GATE_MEASURE,
+ PSI_GATE_CUSTOM,
+};
+
+struct PsiGateOp
+{
+ enum PsiGateKind kind;
+ size_t qubits[3];
+ size_t qubit_count;
+ double params[3];
+ size_t param_count;
+ size_t classical;
+ struct PsiCustomGate *custom;
+ size_t *custom_targets;
+ size_t custom_target_count;
+};
+
+const char *psi_gate_op_name(struct PsiGateOp op);
+const size_t *psi_gate_op_quantum_targets(const struct PsiGateOp *op, size_t *out_count);
+const size_t *psi_gate_op_classical_targets(const struct PsiGateOp *op, size_t *out_count);
+bool psi_gate_op_is_measurement(struct PsiGateOp op);
+bool psi_gate_op_is_custom(struct PsiGateOp op);
+bool psi_gate_op_is_non_clifford(struct PsiGateOp op);
+
+struct PsiQuantumCircuit
+{
+ size_t num_qubits;
+ size_t num_classical;
+ struct PsiGateOp *operations;
+ size_t operation_count;
+ size_t operation_capacity;
+ struct PsiVector computed_state;
+ bool is_computed;
+};
+
+struct PsiQuantumCircuit psi_new_quantum_circuit(size_t num_qubits);
+struct PsiQuantumCircuit psi_new_quantum_circuit_with_classical(size_t num_qubits, size_t num_classical);
+void psi_free_quantum_circuit(struct PsiQuantumCircuit *c);
+void psi_reset_circuit(struct PsiQuantumCircuit *c);
+
+void psi_apply_h(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_x(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_y(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_z(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_s(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_t(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_sdg(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_tdg(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_sx(struct PsiQuantumCircuit *c, size_t target);
+void psi_apply_sxdg(struct PsiQuantumCircuit *c, size_t target);
+
+void psi_apply_rx(struct PsiQuantumCircuit *c, size_t target, double theta);
+void psi_apply_ry(struct PsiQuantumCircuit *c, size_t target, double theta);
+void psi_apply_rz(struct PsiQuantumCircuit *c, size_t target, double theta);
+void psi_apply_p(struct PsiQuantumCircuit *c, size_t target, double theta);
+void psi_apply_u1(struct PsiQuantumCircuit *c, size_t target, double lambda);
+void psi_apply_u2(struct PsiQuantumCircuit *c, size_t target, double phi, double lambda);
+void psi_apply_u3(struct PsiQuantumCircuit *c, size_t target, double theta, double phi, double lambda);
+
+void psi_apply_cnot(struct PsiQuantumCircuit *c, size_t control, size_t target);
+void psi_apply_cz(struct PsiQuantumCircuit *c, size_t control, size_t target);
+void psi_apply_swap(struct PsiQuantumCircuit *c, size_t qubit1, size_t qubit2);
+void psi_apply_crx(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta);
+void psi_apply_cry(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta);
+void psi_apply_crz(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta);
+void psi_apply_cp(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta);
+
+void psi_apply_ccnot(struct PsiQuantumCircuit *c, size_t control1, size_t control2, size_t target);
+void psi_apply_cswap(struct PsiQuantumCircuit *c, size_t control, size_t target1, size_t target2);
+
+void psi_measure(struct PsiQuantumCircuit *c, size_t qubit, size_t classical);
+void psi_measure_all(struct PsiQuantumCircuit *c);
+
+void psi_apply_custom(struct PsiQuantumCircuit *c, struct PsiCustomGate gate, const size_t *targets, size_t count);
diff --git a/include/psi.h b/include/psi.h
index 8c62319..b471d0a 100644
--- a/include/psi.h
+++ b/include/psi.h
@@ -5,3 +5,13 @@
#define PSI_VERSION_PATCH 0
const char *psi_version(void);
+
+#include "maths/complex.h"
+#include "maths/vector.h"
+#include "maths/matrix.h"
+
+#include "core/quantum_components.h"
+#include "core/gates.h"
+#include "core/custom_gate.h"
+#include "core/classical_components.h"
+#include "core/circuit.h"
diff --git a/src/core/circuit.c b/src/core/circuit.c
new file mode 100644
index 0000000..1869ee6
--- /dev/null
+++ b/src/core/circuit.c
@@ -0,0 +1,306 @@
+#include "core/circuit.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *psi_gate_op_name(struct PsiGateOp op)
+{
+ switch (op.kind)
+ {
+ case PSI_GATE_H: return "H";
+ case PSI_GATE_X: return "X";
+ case PSI_GATE_Y: return "Y";
+ case PSI_GATE_Z: return "Z";
+ case PSI_GATE_S: return "S";
+ case PSI_GATE_T: return "T";
+ case PSI_GATE_SDG: return "S†";
+ case PSI_GATE_TDG: return "T†";
+ case PSI_GATE_SX: return "√X";
+ case PSI_GATE_SXDG: return "√X†";
+ case PSI_GATE_RX: return "Rx";
+ case PSI_GATE_RY: return "Ry";
+ case PSI_GATE_RZ: return "Rz";
+ case PSI_GATE_P: return "P";
+ case PSI_GATE_U1: return "U1";
+ case PSI_GATE_U2: return "U2";
+ case PSI_GATE_U3: return "U3";
+ case PSI_GATE_CNOT: return "CNOT";
+ case PSI_GATE_CZ: return "CZ";
+ case PSI_GATE_SWAP: return "SWAP";
+ case PSI_GATE_CRX: return "CRx";
+ case PSI_GATE_CRY: return "CRy";
+ case PSI_GATE_CRZ: return "CRz";
+ case PSI_GATE_CP: return "CP";
+ case PSI_GATE_CCNOT: return "CCNOT";
+ case PSI_GATE_CSWAP: return "CSWAP";
+ case PSI_GATE_MEASURE: return "M";
+ case PSI_GATE_CUSTOM: return op.custom->name;
+ }
+
+ return "?";
+}
+
+const size_t *psi_gate_op_quantum_targets(const struct PsiGateOp *op, size_t *out_count)
+{
+ if (op->kind == PSI_GATE_CUSTOM)
+ {
+ *out_count = op->custom_target_count;
+ return op->custom_targets;
+ }
+
+ *out_count = op->qubit_count;
+ return op->qubits;
+}
+
+const size_t *psi_gate_op_classical_targets(const struct PsiGateOp *op, size_t *out_count)
+{
+ if (op->kind == PSI_GATE_MEASURE)
+ {
+ *out_count = 1;
+ return &op->classical;
+ }
+
+ *out_count = 0;
+ return NULL;
+}
+
+bool psi_gate_op_is_measurement(struct PsiGateOp op)
+{
+ return op.kind == PSI_GATE_MEASURE;
+}
+
+bool psi_gate_op_is_custom(struct PsiGateOp op)
+{
+ return op.kind == PSI_GATE_CUSTOM;
+}
+
+bool psi_gate_op_is_non_clifford(struct PsiGateOp op)
+{
+ switch (op.kind)
+ {
+ case PSI_GATE_T:
+ case PSI_GATE_TDG:
+ case PSI_GATE_SX:
+ case PSI_GATE_SXDG:
+ case PSI_GATE_RX:
+ case PSI_GATE_RY:
+ case PSI_GATE_RZ:
+ case PSI_GATE_P:
+ case PSI_GATE_U1:
+ case PSI_GATE_U2:
+ case PSI_GATE_U3:
+ case PSI_GATE_CRX:
+ case PSI_GATE_CRY:
+ case PSI_GATE_CRZ:
+ case PSI_GATE_CP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+struct PsiQuantumCircuit psi_new_quantum_circuit(size_t num_qubits)
+{
+ return psi_new_quantum_circuit_with_classical(num_qubits, 0);
+}
+
+struct PsiQuantumCircuit psi_new_quantum_circuit_with_classical(size_t num_qubits, size_t num_classical)
+{
+ struct PsiQuantumCircuit c;
+ c.num_qubits = num_qubits;
+ c.num_classical = num_classical;
+ c.operations = NULL;
+ c.operation_count = 0;
+ c.operation_capacity = 0;
+ c.computed_state = psi_new_vector(0, PSI_COLUMN_VECTOR);
+ c.is_computed = false;
+
+ return c;
+}
+
+static void free_operations(struct PsiQuantumCircuit *c)
+{
+ for (size_t i = 0; i < c->operation_count; i++)
+ {
+ struct PsiGateOp *op = &c->operations[i];
+ if (op->kind != PSI_GATE_CUSTOM)
+ continue;
+
+ psi_free_custom_gate(op->custom);
+ free(op->custom);
+ free(op->custom_targets);
+ }
+}
+
+void psi_free_quantum_circuit(struct PsiQuantumCircuit *c)
+{
+ free_operations(c);
+ free(c->operations);
+ c->operations = NULL;
+ c->operation_count = 0;
+ c->operation_capacity = 0;
+ psi_free_vector(&c->computed_state);
+ c->is_computed = false;
+}
+
+void psi_reset_circuit(struct PsiQuantumCircuit *c)
+{
+ free_operations(c);
+ c->operation_count = 0;
+ psi_free_vector(&c->computed_state);
+ c->computed_state = psi_new_vector(0, PSI_COLUMN_VECTOR);
+ c->is_computed = false;
+}
+
+static struct PsiGateOp *append_op(struct PsiQuantumCircuit *c)
+{
+ if (c->operation_count == c->operation_capacity)
+ {
+ size_t new_capacity = c->operation_capacity == 0 ? 8 : c->operation_capacity * 2;
+ c->operations = realloc(c->operations, new_capacity * sizeof(struct PsiGateOp));
+ assert(c->operations != NULL);
+ c->operation_capacity = new_capacity;
+ }
+
+ struct PsiGateOp *op = &c->operations[c->operation_count++];
+ memset(op, 0, sizeof(*op));
+ c->is_computed = false;
+
+ return op;
+}
+
+static void push_1q(struct PsiQuantumCircuit *c, enum PsiGateKind kind, size_t target)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = kind;
+ op->qubits[0] = target;
+ op->qubit_count = 1;
+}
+
+static void push_1q_1p(struct PsiQuantumCircuit *c, enum PsiGateKind kind, size_t target, double theta)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = kind;
+ op->qubits[0] = target;
+ op->qubit_count = 1;
+ op->params[0] = theta;
+ op->param_count = 1;
+}
+
+static void push_2q(struct PsiQuantumCircuit *c, enum PsiGateKind kind, size_t a, size_t b)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = kind;
+ op->qubits[0] = a;
+ op->qubits[1] = b;
+ op->qubit_count = 2;
+}
+
+static void push_2q_1p(struct PsiQuantumCircuit *c, enum PsiGateKind kind, size_t control, size_t target, double theta)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = kind;
+ op->qubits[0] = control;
+ op->qubits[1] = target;
+ op->qubit_count = 2;
+ op->params[0] = theta;
+ op->param_count = 1;
+}
+
+static void push_3q(struct PsiQuantumCircuit *c, enum PsiGateKind kind, size_t a, size_t b, size_t d)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = kind;
+ op->qubits[0] = a;
+ op->qubits[1] = b;
+ op->qubits[2] = d;
+ op->qubit_count = 3;
+}
+
+void psi_apply_h(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_H, target); }
+void psi_apply_x(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_X, target); }
+void psi_apply_y(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_Y, target); }
+void psi_apply_z(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_Z, target); }
+void psi_apply_s(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_S, target); }
+void psi_apply_t(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_T, target); }
+void psi_apply_sdg(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_SDG, target); }
+void psi_apply_tdg(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_TDG, target); }
+void psi_apply_sx(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_SX, target); }
+void psi_apply_sxdg(struct PsiQuantumCircuit *c, size_t target) { push_1q(c, PSI_GATE_SXDG, target); }
+
+void psi_apply_rx(struct PsiQuantumCircuit *c, size_t target, double theta) { push_1q_1p(c, PSI_GATE_RX, target, theta); }
+void psi_apply_ry(struct PsiQuantumCircuit *c, size_t target, double theta) { push_1q_1p(c, PSI_GATE_RY, target, theta); }
+void psi_apply_rz(struct PsiQuantumCircuit *c, size_t target, double theta) { push_1q_1p(c, PSI_GATE_RZ, target, theta); }
+void psi_apply_p(struct PsiQuantumCircuit *c, size_t target, double theta) { push_1q_1p(c, PSI_GATE_P, target, theta); }
+void psi_apply_u1(struct PsiQuantumCircuit *c, size_t target, double lambda) { push_1q_1p(c, PSI_GATE_U1, target, lambda); }
+
+void psi_apply_u2(struct PsiQuantumCircuit *c, size_t target, double phi, double lambda)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = PSI_GATE_U2;
+ op->qubits[0] = target;
+ op->qubit_count = 1;
+ op->params[0] = phi;
+ op->params[1] = lambda;
+ op->param_count = 2;
+}
+
+void psi_apply_u3(struct PsiQuantumCircuit *c, size_t target, double theta, double phi, double lambda)
+{
+ struct PsiGateOp *op = append_op(c);
+ op->kind = PSI_GATE_U3;
+ op->qubits[0] = target;
+ op->qubit_count = 1;
+ op->params[0] = theta;
+ op->params[1] = phi;
+ op->params[2] = lambda;
+ op->param_count = 3;
+}
+
+void psi_apply_cnot(struct PsiQuantumCircuit *c, size_t control, size_t target) { push_2q(c, PSI_GATE_CNOT, control, target); }
+void psi_apply_cz(struct PsiQuantumCircuit *c, size_t control, size_t target) { push_2q(c, PSI_GATE_CZ, control, target); }
+void psi_apply_swap(struct PsiQuantumCircuit *c, size_t qubit1, size_t qubit2) { push_2q(c, PSI_GATE_SWAP, qubit1, qubit2); }
+void psi_apply_crx(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta) { push_2q_1p(c, PSI_GATE_CRX, control, target, theta); }
+void psi_apply_cry(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta) { push_2q_1p(c, PSI_GATE_CRY, control, target, theta); }
+void psi_apply_crz(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta) { push_2q_1p(c, PSI_GATE_CRZ, control, target, theta); }
+void psi_apply_cp(struct PsiQuantumCircuit *c, size_t control, size_t target, double theta) { push_2q_1p(c, PSI_GATE_CP, control, target, theta); }
+
+void psi_apply_ccnot(struct PsiQuantumCircuit *c, size_t control1, size_t control2, size_t target) { push_3q(c, PSI_GATE_CCNOT, control1, control2, target); }
+void psi_apply_cswap(struct PsiQuantumCircuit *c, size_t control, size_t target1, size_t target2) { push_3q(c, PSI_GATE_CSWAP, control, target1, target2); }
+
+void psi_measure(struct PsiQuantumCircuit *c, size_t qubit, size_t classical)
+{
+ if (classical >= c->num_classical)
+ c->num_classical = classical + 1;
+
+ struct PsiGateOp *op = append_op(c);
+ op->kind = PSI_GATE_MEASURE;
+ op->qubits[0] = qubit;
+ op->qubit_count = 1;
+ op->classical = classical;
+}
+
+void psi_measure_all(struct PsiQuantumCircuit *c)
+{
+ for (size_t i = 0; i < c->num_qubits; i++)
+ psi_measure(c, i, i);
+}
+
+void psi_apply_custom(struct PsiQuantumCircuit *c, struct PsiCustomGate gate, const size_t *targets, size_t count)
+{
+ struct PsiCustomGate *owned = malloc(sizeof(struct PsiCustomGate));
+ assert(owned != NULL);
+ *owned = gate;
+
+ size_t *owned_targets = malloc(count * sizeof(size_t));
+ assert(owned_targets != NULL || count == 0);
+ if (count > 0)
+ memcpy(owned_targets, targets, count * sizeof(size_t));
+
+ struct PsiGateOp *op = append_op(c);
+ op->kind = PSI_GATE_CUSTOM;
+ op->custom = owned;
+ op->custom_targets = owned_targets;
+ op->custom_target_count = count;
+}
diff --git a/tester/main.c b/tester/main.c
index 13c9257..194fc77 100644
--- a/tester/main.c
+++ b/tester/main.c
@@ -1,12 +1,5 @@
#include <stdio.h>
-#include "core/classical_components.h"
-#include "core/custom_gate.h"
-#include "core/gates.h"
-#include "core/quantum_components.h"
-#include "maths/complex.h"
-#include "maths/matrix.h"
-#include "maths/vector.h"
#include "psi.h"
int main(void)
@@ -128,5 +121,31 @@ int main(void)
psi_free_classical_register(&creg);
- return 0;
+ struct PsiQuantumCircuit circuit = psi_new_quantum_circuit(3);
+ psi_apply_h(&circuit, 0);
+ psi_apply_cnot(&circuit, 0, 1);
+ psi_apply_rx(&circuit, 2, 1.5707963267948966);
+ psi_apply_ccnot(&circuit, 0, 1, 2);
+
+ struct PsiCompositeGateOp cops[] = { { PSI_OP_X, { 0 }, 1 } };
+ struct PsiCustomGate xg = psi_new_custom_gate_from_composite("MYX", 1, cops, 1);
+ size_t ct[] = { 2 };
+ psi_apply_custom(&circuit, xg, ct, 1);
+
+ psi_measure_all(&circuit);
+
+ printf("circuit = %zu qubits, %zu classical, %zu ops\n",
+ circuit.num_qubits, circuit.num_classical, circuit.operation_count);
+ for (size_t i = 0; i < circuit.operation_count; i++)
+ {
+ size_t tc;
+ const size_t *targets = psi_gate_op_quantum_targets(&circuit.operations[i], &tc);
+ printf(" %zu: %s on", i, psi_gate_op_name(circuit.operations[i]));
+ for (size_t j = 0; j < tc; j++)
+ printf(" q%zu", targets[j]);
+ printf("\n");
+ }
+
+ psi_free_quantum_circuit(&circuit);
}
+