aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/circuit.c454
-rw-r--r--src/core/circuit.rs477
-rw-r--r--src/core/classical_components.c32
-rw-r--r--src/core/custom_gate.c202
-rw-r--r--src/core/gates.c244
-rw-r--r--src/core/kernel.c772
-rw-r--r--src/core/noise.c532
-rw-r--r--src/core/quantum_components.c318
-rw-r--r--src/core/runtime.c456
-rw-r--r--src/maths/complex.c122
-rw-r--r--src/maths/format.c265
-rw-r--r--src/maths/matrix.c192
-rw-r--r--src/maths/matrix.rs310
-rw-r--r--src/maths/simd.c424
-rw-r--r--src/maths/vector.c136
-rw-r--r--src/maths/vector.rs258
-rw-r--r--src/psi.c2
-rw-r--r--src/visualizer/grid.c146
-rw-r--r--src/visualizer/grid.h10
-rw-r--r--src/visualizer/horizontal_cli.c600
-rw-r--r--src/visualizer/vertical_cli.c536
21 files changed, 2778 insertions, 3710 deletions
diff --git a/src/core/circuit.c b/src/core/circuit.c
index 8009db5..8c56c33 100644
--- a/src/core/circuit.c
+++ b/src/core/circuit.c
@@ -1,382 +1,442 @@
#include "core/circuit.h"
#include <assert.h>
+#include <math.h>
#include <stdlib.h>
#include <string.h>
+#include "maths/format.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;
- }
+ 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 "?";
+ 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;
- }
+ if (op->kind == PSI_GATE_CUSTOM)
+ {
+ *out_count = op->custom_target_count;
+ return op->custom_targets;
+ }
- *out_count = op->qubit_count;
- return op->qubits;
+ *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;
- }
+ if (op->kind == PSI_GATE_MEASURE)
+ {
+ *out_count = 1;
+ return &op->classical;
+ }
- *out_count = 0;
- return NULL;
+ *out_count = 0;
+ return NULL;
}
bool psi_gate_op_is_measurement(struct PsiGateOp op)
{
- return op.kind == PSI_GATE_MEASURE;
+ return op.kind == PSI_GATE_MEASURE;
}
bool psi_gate_op_is_custom(struct PsiGateOp op)
{
- return op.kind == PSI_GATE_CUSTOM;
+ 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;
- }
+ 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);
+ 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;
+ 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;
+ 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;
+ 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);
- }
+ 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;
+ 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;
+ 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;
- }
+ 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;
+ struct PsiGateOp* op = &c->operations[c->operation_count++];
+ memset(op, 0, sizeof(*op));
+ c->is_computed = false;
- return op;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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);
+ push_1q(c, PSI_GATE_H, target);
}
void psi_apply_x(struct PsiQuantumCircuit* c, size_t target)
{
- push_1q(c, PSI_GATE_X, 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);
+ push_1q(c, PSI_GATE_Y, target);
}
void psi_apply_z(struct PsiQuantumCircuit* c, size_t target)
{
- push_1q(c, PSI_GATE_Z, 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);
+ push_1q(c, PSI_GATE_S, target);
}
void psi_apply_t(struct PsiQuantumCircuit* c, size_t target)
{
- push_1q(c, PSI_GATE_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);
+ push_1q(c, PSI_GATE_SDG, target);
}
void psi_apply_tdg(struct PsiQuantumCircuit* c, size_t target)
{
- push_1q(c, PSI_GATE_TDG, 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);
+ push_1q(c, PSI_GATE_SX, target);
}
void psi_apply_sxdg(struct PsiQuantumCircuit* c, size_t target)
{
- push_1q(c, PSI_GATE_SXDG, 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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;
+ 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;
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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;
+ 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;
+ 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);
+ 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;
+ 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;
+}
+
+void psi_print_circuit(const struct PsiQuantumCircuit* circuit, FILE* out)
+{
+ size_t nq = circuit->num_qubits;
+ fprintf(out, "QuantumCircuit (%zu qubits, %zu classical)\n", nq, circuit->num_classical);
+ fprintf(out, "Operations:\n");
+
+ for (size_t i = 0; i < circuit->operation_count; i++)
+ {
+ struct PsiGateOp op = circuit->operations[i];
+
+ if (op.kind == PSI_GATE_MEASURE)
+ {
+ fprintf(out, " %zu: %s q%zu → c%zu\n", i, psi_gate_op_name(op), op.qubits[0],
+ op.classical);
+ continue;
+ }
+
+ if (op.kind == PSI_GATE_CUSTOM)
+ fprintf(out, " %zu: [%s] on [", i, op.custom->name);
+ else
+ fprintf(out, " %zu: %s on [", i, psi_gate_op_name(op));
+
+ size_t target_count;
+ const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count);
+ for (size_t j = 0; j < target_count; j++)
+ {
+ fprintf(out, "%zu", targets[j]);
+ if (j != target_count - 1)
+ fputs(", ", out);
+ }
+ fputs("]\n", out);
+ }
+
+ if (!circuit->is_computed)
+ {
+ fputs("State: (not computed)\n", out);
+ return;
+ }
+
+ fputs("State:\n", out);
+ size_t dim = (size_t)1 << nq;
+ for (size_t i = 0; i < dim; i++)
+ {
+ struct PsiComplex amp = circuit->computed_state.data[i];
+ if (fabs(amp.real) < 1e-10 && fabs(amp.imaginary) < 1e-10)
+ continue;
- 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));
+ char basis[65];
+ for (size_t b = 0; b < nq; b++)
+ basis[b] = ((i >> (nq - 1 - b)) & 1) ? '1' : '0';
+ basis[nq] = '\0';
- struct PsiGateOp* op = append_op(c);
- op->kind = PSI_GATE_CUSTOM;
- op->custom = owned;
- op->custom_targets = owned_targets;
- op->custom_target_count = count;
+ char amp_buf[64];
+ fprintf(out, " |%s⟩: %s\n", basis, psi_format_amplitude(amp, amp_buf, sizeof amp_buf));
+ }
}
diff --git a/src/core/circuit.rs b/src/core/circuit.rs
deleted file mode 100644
index 6647f58..0000000
--- a/src/core/circuit.rs
+++ /dev/null
@@ -1,477 +0,0 @@
-use super::{CustomGate, QuantumState, Runtime, RuntimeConfig};
-use crate::{format_amplitude, format_probability, Vector};
-use core::fmt;
-use std::sync::Arc;
-
-#[derive(Clone)]
-pub enum GateOp {
- H(usize),
- X(usize),
- Y(usize),
- Z(usize),
- S(usize),
- T(usize),
- Sdg(usize),
- Tdg(usize),
- Sx(usize),
- Sxdg(usize),
- Rx(usize, f64),
- Ry(usize, f64),
- Rz(usize, f64),
- P(usize, f64),
- U1(usize, f64),
- U2(usize, f64, f64),
- U3(usize, f64, f64, f64),
- CNOT(usize, usize),
- CZ(usize, usize),
- SWAP(usize, usize),
- CRx(usize, usize, f64),
- CRy(usize, usize, f64),
- CRz(usize, usize, f64),
- CP(usize, usize, f64),
- CCNOT(usize, usize, usize),
- CSWAP(usize, usize, usize),
- Measure(usize, usize),
- Custom(Arc<CustomGate>, Vec<usize>),
-}
-
-impl GateOp {
- pub fn name(&self) -> &str {
- match self {
- GateOp::H(_) => "H",
- GateOp::X(_) => "X",
- GateOp::Y(_) => "Y",
- GateOp::Z(_) => "Z",
- GateOp::S(_) => "S",
- GateOp::T(_) => "T",
- GateOp::Sdg(_) => "S†",
- GateOp::Tdg(_) => "T†",
- GateOp::Sx(_) => "√X",
- GateOp::Sxdg(_) => "√X†",
- GateOp::Rx(_, _) => "Rx",
- GateOp::Ry(_, _) => "Ry",
- GateOp::Rz(_, _) => "Rz",
- GateOp::P(_, _) => "P",
- GateOp::U1(_, _) => "U1",
- GateOp::U2(_, _, _) => "U2",
- GateOp::U3(_, _, _, _) => "U3",
- GateOp::CRx(_, _, _) => "CRx",
- GateOp::CRy(_, _, _) => "CRy",
- GateOp::CRz(_, _, _) => "CRz",
- GateOp::CP(_, _, _) => "CP",
- GateOp::CNOT(_, _) => "CNOT",
- GateOp::CZ(_, _) => "CZ",
- GateOp::SWAP(_, _) => "SWAP",
- GateOp::CCNOT(_, _, _) => "CCNOT",
- GateOp::CSWAP(_, _, _) => "CSWAP",
- GateOp::Measure(_, _) => "M",
- GateOp::Custom(gate, _) => &gate.name,
- }
- }
-
- pub fn quantum_targets(&self) -> Vec<usize> {
- match self {
- GateOp::H(t)
- | GateOp::X(t)
- | GateOp::Y(t)
- | GateOp::Z(t)
- | GateOp::S(t)
- | GateOp::T(t)
- | GateOp::Sdg(t)
- | GateOp::Tdg(t)
- | GateOp::Sx(t)
- | GateOp::Sxdg(t)
- | GateOp::Rx(t, _)
- | GateOp::Ry(t, _)
- | GateOp::Rz(t, _)
- | GateOp::P(t, _)
- | GateOp::U1(t, _)
- | GateOp::U2(t, _, _)
- | GateOp::U3(t, _, _, _) => vec![*t],
- GateOp::CNOT(c, t)
- | GateOp::CZ(c, t)
- | GateOp::SWAP(c, t)
- | GateOp::CRx(c, t, _)
- | GateOp::CRy(c, t, _)
- | GateOp::CRz(c, t, _)
- | GateOp::CP(c, t, _) => vec![*c, *t],
- GateOp::CCNOT(c1, c2, t) | GateOp::CSWAP(c1, c2, t) => vec![*c1, *c2, *t],
- GateOp::Measure(q, _) => vec![*q],
- GateOp::Custom(_, targets) => targets.clone(),
- }
- }
-
- pub fn classical_targets(&self) -> Vec<usize> {
- match self {
- GateOp::Measure(_, c) => vec![*c],
- _ => vec![],
- }
- }
-
- pub fn is_measurement(&self) -> bool {
- matches!(self, GateOp::Measure(_, _))
- }
-
- pub fn is_custom(&self) -> bool {
- matches!(self, GateOp::Custom(_, _))
- }
-
- pub fn is_non_clifford(&self) -> bool {
- matches!(
- self,
- GateOp::T(_)
- | GateOp::Tdg(_)
- | GateOp::Sx(_)
- | GateOp::Sxdg(_)
- | GateOp::Rx(_, _)
- | GateOp::Ry(_, _)
- | GateOp::Rz(_, _)
- | GateOp::P(_, _)
- | GateOp::U1(_, _)
- | GateOp::U2(_, _, _)
- | GateOp::U3(_, _, _, _)
- | GateOp::CRx(_, _, _)
- | GateOp::CRy(_, _, _)
- | GateOp::CRz(_, _, _)
- | GateOp::CP(_, _, _)
- )
- }
-}
-
-pub struct QuantumCircuit {
- num_qubits: usize,
- num_classical: usize,
- operations: Vec<GateOp>,
- computed_state: Option<QuantumState>,
-}
-
-impl QuantumCircuit {
- pub fn new(num_qubits: usize) -> QuantumCircuit {
- QuantumCircuit {
- num_qubits,
- num_classical: 0,
- operations: Vec::new(),
- computed_state: None,
- }
- }
-
- pub fn with_classical(num_qubits: usize, num_classical: usize) -> QuantumCircuit {
- QuantumCircuit {
- num_qubits,
- num_classical,
- operations: Vec::new(),
- computed_state: None,
- }
- }
-
- pub fn num_qubits(&self) -> usize {
- self.num_qubits
- }
-
- pub fn num_classical(&self) -> usize {
- self.num_classical
- }
-
- pub fn operations(&self) -> &[GateOp] {
- &self.operations
- }
-
- pub fn is_computed(&self) -> bool {
- self.computed_state.is_some()
- }
-
- pub fn compute(&mut self) -> &QuantumState {
- self.compute_with(Runtime::default())
- }
-
- pub fn compute_with(&mut self, runtime: Runtime) -> &QuantumState {
- if self.computed_state.is_none() {
- self.computed_state = Some(runtime.compute(self.num_qubits, &self.operations));
- }
- self.computed_state.as_ref().unwrap()
- }
-
- pub fn compute_with_config(&mut self, config: RuntimeConfig) -> &QuantumState {
- if self.computed_state.is_none() {
- self.computed_state = Some(config.compute(self.num_qubits, &self.operations));
- }
- self.computed_state.as_ref().unwrap()
- }
-
- pub fn state(&mut self) -> &QuantumState {
- self.compute()
- }
-
- pub fn state_with(&mut self, runtime: Runtime) -> &QuantumState {
- self.compute_with(runtime)
- }
-
- pub fn state_with_config(&mut self, config: RuntimeConfig) -> &QuantumState {
- self.compute_with_config(config)
- }
-
- pub fn h(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::H(target));
- self.computed_state = None;
- self
- }
-
- pub fn x(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::X(target));
- self.computed_state = None;
- self
- }
-
- pub fn y(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::Y(target));
- self.computed_state = None;
- self
- }
-
- pub fn z(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::Z(target));
- self.computed_state = None;
- self
- }
-
- pub fn s(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::S(target));
- self.computed_state = None;
- self
- }
-
- pub fn t(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::T(target));
- self.computed_state = None;
- self
- }
-
- pub fn sdg(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::Sdg(target));
- self.computed_state = None;
- self
- }
-
- pub fn tdg(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::Tdg(target));
- self.computed_state = None;
- self
- }
-
- pub fn sx(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::Sx(target));
- self.computed_state = None;
- self
- }
-
- pub fn sxdg(&mut self, target: usize) -> &mut Self {
- self.operations.push(GateOp::Sxdg(target));
- self.computed_state = None;
- self
- }
-
- pub fn rx(&mut self, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::Rx(target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn ry(&mut self, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::Ry(target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn rz(&mut self, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::Rz(target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn p(&mut self, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::P(target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn u1(&mut self, target: usize, lambda: f64) -> &mut Self {
- self.operations.push(GateOp::U1(target, lambda));
- self.computed_state = None;
- self
- }
-
- pub fn u2(&mut self, target: usize, phi: f64, lambda: f64) -> &mut Self {
- self.operations.push(GateOp::U2(target, phi, lambda));
- self.computed_state = None;
- self
- }
-
- pub fn u3(&mut self, target: usize, theta: f64, phi: f64, lambda: f64) -> &mut Self {
- self.operations.push(GateOp::U3(target, theta, phi, lambda));
- self.computed_state = None;
- self
- }
-
- pub fn crx(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::CRx(control, target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn cry(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::CRy(control, target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn crz(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::CRz(control, target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn cp(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
- self.operations.push(GateOp::CP(control, target, theta));
- self.computed_state = None;
- self
- }
-
- pub fn cnot(&mut self, control: usize, target: usize) -> &mut Self {
- self.operations.push(GateOp::CNOT(control, target));
- self.computed_state = None;
- self
- }
-
- pub fn cx(&mut self, control: usize, target: usize) -> &mut Self {
- self.cnot(control, target)
- }
-
- pub fn cz(&mut self, control: usize, target: usize) -> &mut Self {
- self.operations.push(GateOp::CZ(control, target));
- self.computed_state = None;
- self
- }
-
- pub fn swap(&mut self, qubit1: usize, qubit2: usize) -> &mut Self {
- self.operations.push(GateOp::SWAP(qubit1, qubit2));
- self.computed_state = None;
- self
- }
-
- pub fn ccnot(&mut self, control1: usize, control2: usize, target: usize) -> &mut Self {
- self.operations
- .push(GateOp::CCNOT(control1, control2, target));
- self.computed_state = None;
- self
- }
-
- pub fn toffoli(&mut self, control1: usize, control2: usize, target: usize) -> &mut Self {
- self.ccnot(control1, control2, target)
- }
-
- pub fn cswap(&mut self, control: usize, target1: usize, target2: usize) -> &mut Self {
- self.operations
- .push(GateOp::CSWAP(control, target1, target2));
- self.computed_state = None;
- self
- }
-
- pub fn fredkin(&mut self, control: usize, target1: usize, target2: usize) -> &mut Self {
- self.cswap(control, target1, target2)
- }
-
- pub fn measure(&mut self, qubit: usize, classical: usize) -> &mut Self {
- if classical >= self.num_classical {
- self.num_classical = classical + 1;
- }
- self.operations.push(GateOp::Measure(qubit, classical));
- self
- }
-
- pub fn measure_all(&mut self) -> &mut Self {
- for i in 0..self.num_qubits {
- self.measure(i, i);
- }
- self
- }
-
- pub fn custom(&mut self, gate: &Arc<CustomGate>, targets: &[usize]) -> &mut Self {
- self.operations
- .push(GateOp::Custom(Arc::clone(gate), targets.to_vec()));
- self.computed_state = None;
- self
- }
-
- pub fn apply_custom(&mut self, gate: CustomGate, targets: &[usize]) -> &mut Self {
- self.operations
- .push(GateOp::Custom(Arc::new(gate), targets.to_vec()));
- self.computed_state = None;
- self
- }
-
- pub fn reset(&mut self) -> &mut Self {
- self.operations.clear();
- self.computed_state = None;
- self
- }
-
- pub fn probability(&mut self, state_index: usize) -> f64 {
- self.compute();
- let state = self.computed_state.as_ref().unwrap();
- let amp = state.get(state_index);
- amp.norm2()
- }
-
- pub fn probabilities(&mut self) -> Vec<f64> {
- self.compute();
- let n = 1 << self.num_qubits;
- let state = self.computed_state.as_ref().unwrap();
- (0..n).map(|i| state.get(i).norm2()).collect()
- }
-
- pub fn print_probabilities(&mut self) {
- let probs = self.probabilities();
- let n = self.num_qubits;
- println!("Probabilities:");
- for (i, p) in probs.iter().enumerate() {
- if *p > 1e-10 {
- let basis: String = format!("{:0width$b}", i, width = n);
- println!(" |{}⟩: {}", basis, format_probability(*p));
- }
- }
- }
-}
-
-impl fmt::Display for QuantumCircuit {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- writeln!(
- f,
- "QuantumCircuit ({} qubits, {} classical)",
- self.num_qubits, self.num_classical
- )?;
- writeln!(f, "Operations:")?;
- for (i, op) in self.operations.iter().enumerate() {
- match op {
- GateOp::Measure(q, c) => writeln!(f, " {}: {} q{} → c{}", i, op.name(), q, c)?,
- GateOp::Custom(gate, targets) => {
- writeln!(f, " {}: [{}] on {:?}", i, gate.name, targets)?
- }
- _ => writeln!(f, " {}: {} on {:?}", i, op.name(), op.quantum_targets())?,
- }
- }
- if let Some(state) = &self.computed_state {
- writeln!(f, "State:")?;
- let n = 1 << self.num_qubits;
- for i in 0..n {
- let amp = state.get(i);
- if amp.real.abs() > 1e-10 || amp.imaginary.abs() > 1e-10 {
- let basis: String = format!("{:0width$b}", i, width = self.num_qubits);
- writeln!(f, " |{}⟩: {}", basis, format_amplitude(&amp))?;
- }
- }
- } else {
- writeln!(f, "State: (not computed)")?;
- }
- Ok(())
- }
-}
diff --git a/src/core/classical_components.c b/src/core/classical_components.c
index 3ffeb88..3404c6b 100644
--- a/src/core/classical_components.c
+++ b/src/core/classical_components.c
@@ -5,31 +5,31 @@
struct PsiClassicalBit psi_new_classical_bit(const char* name, bool state)
{
- return (struct PsiClassicalBit){
- name,
- state,
- };
+ return (struct PsiClassicalBit){
+ name,
+ state,
+ };
}
struct PsiClassicalRegister psi_new_classical_register(const char* name, const char** names,
size_t count)
{
- struct PsiClassicalBit* bits = malloc(count * sizeof(struct PsiClassicalBit));
- assert(bits != NULL || count == 0);
+ struct PsiClassicalBit* bits = malloc(count * sizeof(struct PsiClassicalBit));
+ assert(bits != NULL || count == 0);
- for (size_t i = 0; i < count; i++)
- bits[i] = psi_new_classical_bit(names[i], false);
+ for (size_t i = 0; i < count; i++)
+ bits[i] = psi_new_classical_bit(names[i], false);
- return (struct PsiClassicalRegister){
- name,
- bits,
- count,
- };
+ return (struct PsiClassicalRegister){
+ name,
+ bits,
+ count,
+ };
}
void psi_free_classical_register(struct PsiClassicalRegister* reg)
{
- free(reg->bits);
- reg->bits = NULL;
- reg->num_bits = 0;
+ free(reg->bits);
+ reg->bits = NULL;
+ reg->num_bits = 0;
}
diff --git a/src/core/custom_gate.c b/src/core/custom_gate.c
index dd41635..2dce185 100644
--- a/src/core/custom_gate.c
+++ b/src/core/custom_gate.c
@@ -9,157 +9,157 @@
struct PsiCustomGate psi_new_custom_gate_from_matrix(const char* name, struct PsiMatrix matrix)
{
- assert(matrix.rows == matrix.cols);
+ assert(matrix.rows == matrix.cols);
- size_t dim = matrix.rows;
- assert(dim > 0 && (dim & (dim - 1)) == 0);
+ size_t dim = matrix.rows;
+ assert(dim > 0 && (dim & (dim - 1)) == 0);
- size_t num_qubits = 0;
- while (((size_t)1 << num_qubits) < dim)
- num_qubits++;
+ size_t num_qubits = 0;
+ while (((size_t)1 << num_qubits) < dim)
+ num_qubits++;
- struct PsiCustomGate gate;
- gate.name = name;
- gate.num_qubits = num_qubits;
- gate.kind = PSI_CUSTOM_GATE_MATRIX;
- gate.definition.matrix = matrix;
+ struct PsiCustomGate gate;
+ gate.name = name;
+ gate.num_qubits = num_qubits;
+ gate.kind = PSI_CUSTOM_GATE_MATRIX;
+ gate.definition.matrix = matrix;
- return gate;
+ return gate;
}
struct PsiCustomGate psi_new_custom_gate_from_composite(const char* name, size_t num_qubits,
const struct PsiCompositeGateOp* ops,
size_t op_count)
{
- struct PsiCompositeGateOp* owned = malloc(op_count * sizeof(struct PsiCompositeGateOp));
- assert(owned != NULL || op_count == 0);
+ struct PsiCompositeGateOp* owned = malloc(op_count * sizeof(struct PsiCompositeGateOp));
+ assert(owned != NULL || op_count == 0);
- if (op_count > 0)
- memcpy(owned, ops, op_count * sizeof(struct PsiCompositeGateOp));
+ if (op_count > 0)
+ memcpy(owned, ops, op_count * sizeof(struct PsiCompositeGateOp));
- struct PsiCustomGate gate;
- gate.name = name;
- gate.num_qubits = num_qubits;
- gate.kind = PSI_CUSTOM_GATE_COMPOSITE;
- gate.definition.composite.ops = owned;
- gate.definition.composite.count = op_count;
+ struct PsiCustomGate gate;
+ gate.name = name;
+ gate.num_qubits = num_qubits;
+ gate.kind = PSI_CUSTOM_GATE_COMPOSITE;
+ gate.definition.composite.ops = owned;
+ gate.definition.composite.count = op_count;
- return gate;
+ return gate;
}
void psi_free_custom_gate(struct PsiCustomGate* gate)
{
- if (gate->kind == PSI_CUSTOM_GATE_MATRIX)
- {
- psi_free_matrix(&gate->definition.matrix);
- return;
- }
+ if (gate->kind == PSI_CUSTOM_GATE_MATRIX)
+ {
+ psi_free_matrix(&gate->definition.matrix);
+ return;
+ }
- free(gate->definition.composite.ops);
- gate->definition.composite.ops = NULL;
- gate->definition.composite.count = 0;
+ free(gate->definition.composite.ops);
+ gate->definition.composite.ops = NULL;
+ gate->definition.composite.count = 0;
}
static struct PsiQuantumGate op_gate(enum PsiCompositeOp op)
{
- switch (op)
- {
- case PSI_OP_H: return psi_hadamard_gate();
- case PSI_OP_X: return psi_pauli_x_gate();
- case PSI_OP_Y: return psi_pauli_y_gate();
- case PSI_OP_Z: return psi_pauli_z_gate();
- case PSI_OP_S: return psi_s_gate();
- case PSI_OP_T: return psi_t_gate();
- case PSI_OP_CNOT: return psi_cnot_gate();
- case PSI_OP_CZ: return psi_cz_gate();
- case PSI_OP_SWAP: return psi_swap_gate();
- case PSI_OP_CCNOT: return psi_toffoli_gate();
- case PSI_OP_CSWAP: return psi_fredkin_gate();
- }
+ switch (op)
+ {
+ case PSI_OP_H: return psi_hadamard_gate();
+ case PSI_OP_X: return psi_pauli_x_gate();
+ case PSI_OP_Y: return psi_pauli_y_gate();
+ case PSI_OP_Z: return psi_pauli_z_gate();
+ case PSI_OP_S: return psi_s_gate();
+ case PSI_OP_T: return psi_t_gate();
+ case PSI_OP_CNOT: return psi_cnot_gate();
+ case PSI_OP_CZ: return psi_cz_gate();
+ case PSI_OP_SWAP: return psi_swap_gate();
+ case PSI_OP_CCNOT: return psi_toffoli_gate();
+ case PSI_OP_CSWAP: return psi_fredkin_gate();
+ }
- return psi_identity_gate();
+ return psi_identity_gate();
}
static bool find_target(const size_t* targets, size_t count, size_t q, size_t* pos)
{
- for (size_t i = 0; i < count; i++)
- if (targets[i] == q)
- {
- *pos = i;
- return true;
- }
+ for (size_t i = 0; i < count; i++)
+ if (targets[i] == q)
+ {
+ *pos = i;
+ return true;
+ }
- return false;
+ return false;
}
static struct PsiMatrix build_full_operator(struct PsiMatrix gate_matrix, const size_t* targets,
size_t num_gate_qubits, size_t total_qubits)
{
- size_t dim = (size_t)1 << total_qubits;
- size_t gate_dim = gate_matrix.rows;
+ size_t dim = (size_t)1 << total_qubits;
+ size_t gate_dim = gate_matrix.rows;
- struct PsiMatrix result = psi_new_matrix(dim, dim);
+ struct PsiMatrix result = psi_new_matrix(dim, dim);
- for (size_t i = 0; i < dim; i++)
- for (size_t j = 0; j < dim; j++)
- {
- size_t gate_i = 0;
- size_t gate_j = 0;
- bool match_non_targets = true;
+ for (size_t i = 0; i < dim; i++)
+ for (size_t j = 0; j < dim; j++)
+ {
+ size_t gate_i = 0;
+ size_t gate_j = 0;
+ bool match_non_targets = true;
- for (size_t q = 0; q < total_qubits; q++)
- {
- size_t bit_i = (i >> (total_qubits - 1 - q)) & 1;
- size_t bit_j = (j >> (total_qubits - 1 - q)) & 1;
+ for (size_t q = 0; q < total_qubits; q++)
+ {
+ size_t bit_i = (i >> (total_qubits - 1 - q)) & 1;
+ size_t bit_j = (j >> (total_qubits - 1 - q)) & 1;
- size_t pos;
- if (find_target(targets, num_gate_qubits, q, &pos))
- {
- gate_i |= bit_i << (num_gate_qubits - 1 - pos);
- gate_j |= bit_j << (num_gate_qubits - 1 - pos);
- }
- else if (bit_i != bit_j)
- {
- match_non_targets = false;
- break;
- }
- }
+ size_t pos;
+ if (find_target(targets, num_gate_qubits, q, &pos))
+ {
+ gate_i |= bit_i << (num_gate_qubits - 1 - pos);
+ gate_j |= bit_j << (num_gate_qubits - 1 - pos);
+ }
+ else if (bit_i != bit_j)
+ {
+ match_non_targets = false;
+ break;
+ }
+ }
- if (match_non_targets)
- result.data[i * dim + j] = gate_matrix.data[gate_i * gate_dim + gate_j];
- }
+ if (match_non_targets)
+ result.data[i * dim + j] = gate_matrix.data[gate_i * gate_dim + gate_j];
+ }
- return result;
+ return result;
}
static struct PsiMatrix compute_composite_matrix(struct PsiCustomGate gate)
{
- size_t dim = (size_t)1 << gate.num_qubits;
- struct PsiMatrix result = psi_identity_matrix(dim);
+ size_t dim = (size_t)1 << gate.num_qubits;
+ struct PsiMatrix result = psi_identity_matrix(dim);
- for (size_t i = 0; i < gate.definition.composite.count; i++)
- {
- struct PsiCompositeGateOp step = gate.definition.composite.ops[i];
- struct PsiQuantumGate g = op_gate(step.op);
+ for (size_t i = 0; i < gate.definition.composite.count; i++)
+ {
+ struct PsiCompositeGateOp step = gate.definition.composite.ops[i];
+ struct PsiQuantumGate g = op_gate(step.op);
- struct PsiMatrix full =
- build_full_operator(g.matrix, step.targets, step.target_count, gate.num_qubits);
- struct PsiMatrix next = psi_dot_matrix(full, result);
+ struct PsiMatrix full =
+ build_full_operator(g.matrix, step.targets, step.target_count, gate.num_qubits);
+ struct PsiMatrix next = psi_dot_matrix(full, result);
- psi_free_matrix(&full);
- psi_free_matrix(&result);
- psi_free_quantum_gate(&g);
- result = next;
- }
+ psi_free_matrix(&full);
+ psi_free_matrix(&result);
+ psi_free_quantum_gate(&g);
+ result = next;
+ }
- return result;
+ return result;
}
struct PsiQuantumGate psi_to_quantum_gate(struct PsiCustomGate gate)
{
- if (gate.kind == PSI_CUSTOM_GATE_MATRIX)
- return psi_new_quantum_gate(gate.name, psi_clone_matrix(gate.definition.matrix),
- gate.num_qubits);
+ if (gate.kind == PSI_CUSTOM_GATE_MATRIX)
+ return psi_new_quantum_gate(gate.name, psi_clone_matrix(gate.definition.matrix),
+ gate.num_qubits);
- return psi_new_quantum_gate(gate.name, compute_composite_matrix(gate), gate.num_qubits);
+ return psi_new_quantum_gate(gate.name, compute_composite_matrix(gate), gate.num_qubits);
}
diff --git a/src/core/gates.c b/src/core/gates.c
index 51605c9..57d2e97 100644
--- a/src/core/gates.c
+++ b/src/core/gates.c
@@ -6,266 +6,266 @@ static const double INV_SQRT_2 = 0.7071067811865476;
struct PsiMatrix psi_rx_matrix(double theta)
{
- double cos_h = cos(theta / 2.0);
- double sin_h = sin(theta / 2.0);
+ double cos_h = cos(theta / 2.0);
+ double sin_h = sin(theta / 2.0);
- return psi_matrix(2, 2, psi_new_complex(cos_h, 0.0), psi_new_complex(0.0, -sin_h),
- psi_new_complex(0.0, -sin_h), psi_new_complex(cos_h, 0.0));
+ return psi_matrix(2, 2, psi_new_complex(cos_h, 0.0), psi_new_complex(0.0, -sin_h),
+ psi_new_complex(0.0, -sin_h), psi_new_complex(cos_h, 0.0));
}
struct PsiMatrix psi_ry_matrix(double theta)
{
- double cos_h = cos(theta / 2.0);
- double sin_h = sin(theta / 2.0);
+ double cos_h = cos(theta / 2.0);
+ double sin_h = sin(theta / 2.0);
- return psi_matrix(2, 2, psi_new_complex(cos_h, 0.0), psi_new_complex(-sin_h, 0.0),
- psi_new_complex(sin_h, 0.0), psi_new_complex(cos_h, 0.0));
+ return psi_matrix(2, 2, psi_new_complex(cos_h, 0.0), psi_new_complex(-sin_h, 0.0),
+ psi_new_complex(sin_h, 0.0), psi_new_complex(cos_h, 0.0));
}
struct PsiMatrix psi_rz_matrix(double theta)
{
- double half = theta / 2.0;
+ double half = theta / 2.0;
- return psi_matrix(2, 2, psi_new_complex(cos(half), -sin(half)), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(cos(half), sin(half)));
+ return psi_matrix(2, 2, psi_new_complex(cos(half), -sin(half)), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(cos(half), sin(half)));
}
struct PsiMatrix psi_p_matrix(double theta)
{
- return psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(cos(theta), sin(theta)));
+ return psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(cos(theta), sin(theta)));
}
struct PsiMatrix psi_u1_matrix(double lambda)
{
- return psi_p_matrix(lambda);
+ return psi_p_matrix(lambda);
}
struct PsiMatrix psi_u2_matrix(double phi, double lambda)
{
- return psi_matrix(
- 2, 2, psi_new_complex(INV_SQRT_2, 0.0),
- psi_new_complex(-INV_SQRT_2 * cos(lambda), -INV_SQRT_2 * sin(lambda)),
- psi_new_complex(INV_SQRT_2 * cos(phi), INV_SQRT_2 * sin(phi)),
- psi_new_complex(cos(phi + lambda) * INV_SQRT_2, sin(phi + lambda) * INV_SQRT_2));
+ return psi_matrix(
+ 2, 2, psi_new_complex(INV_SQRT_2, 0.0),
+ psi_new_complex(-INV_SQRT_2 * cos(lambda), -INV_SQRT_2 * sin(lambda)),
+ psi_new_complex(INV_SQRT_2 * cos(phi), INV_SQRT_2 * sin(phi)),
+ psi_new_complex(cos(phi + lambda) * INV_SQRT_2, sin(phi + lambda) * INV_SQRT_2));
}
struct PsiMatrix psi_u3_matrix(double theta, double phi, double lambda)
{
- double cos_h = cos(theta / 2.0);
- double sin_h = sin(theta / 2.0);
+ double cos_h = cos(theta / 2.0);
+ double sin_h = sin(theta / 2.0);
- return psi_matrix(2, 2, psi_new_complex(cos_h, 0.0),
- psi_new_complex(-sin_h * cos(lambda), -sin_h * sin(lambda)),
- psi_new_complex(sin_h * cos(phi), sin_h * sin(phi)),
- psi_new_complex(cos_h * cos(phi + lambda), cos_h * sin(phi + lambda)));
+ return psi_matrix(2, 2, psi_new_complex(cos_h, 0.0),
+ psi_new_complex(-sin_h * cos(lambda), -sin_h * sin(lambda)),
+ psi_new_complex(sin_h * cos(phi), sin_h * sin(phi)),
+ psi_new_complex(cos_h * cos(phi + lambda), cos_h * sin(phi + lambda)));
}
struct PsiMatrix psi_crx_matrix(double theta)
{
- double cos_h = cos(theta / 2.0);
- double sin_h = sin(theta / 2.0);
+ double cos_h = cos(theta / 2.0);
+ double sin_h = sin(theta / 2.0);
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 2, 2, psi_new_complex(cos_h, 0.0));
- psi_set_matrix(&m, 2, 3, psi_new_complex(0.0, -sin_h));
- psi_set_matrix(&m, 3, 2, psi_new_complex(0.0, -sin_h));
- psi_set_matrix(&m, 3, 3, psi_new_complex(cos_h, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 2, 2, psi_new_complex(cos_h, 0.0));
+ psi_set_matrix(&m, 2, 3, psi_new_complex(0.0, -sin_h));
+ psi_set_matrix(&m, 3, 2, psi_new_complex(0.0, -sin_h));
+ psi_set_matrix(&m, 3, 3, psi_new_complex(cos_h, 0.0));
- return m;
+ return m;
}
struct PsiMatrix psi_cry_matrix(double theta)
{
- double cos_h = cos(theta / 2.0);
- double sin_h = sin(theta / 2.0);
+ double cos_h = cos(theta / 2.0);
+ double sin_h = sin(theta / 2.0);
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 2, 2, psi_new_complex(cos_h, 0.0));
- psi_set_matrix(&m, 2, 3, psi_new_complex(-sin_h, 0.0));
- psi_set_matrix(&m, 3, 2, psi_new_complex(sin_h, 0.0));
- psi_set_matrix(&m, 3, 3, psi_new_complex(cos_h, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 2, 2, psi_new_complex(cos_h, 0.0));
+ psi_set_matrix(&m, 2, 3, psi_new_complex(-sin_h, 0.0));
+ psi_set_matrix(&m, 3, 2, psi_new_complex(sin_h, 0.0));
+ psi_set_matrix(&m, 3, 3, psi_new_complex(cos_h, 0.0));
- return m;
+ return m;
}
struct PsiMatrix psi_crz_matrix(double theta)
{
- double half = theta / 2.0;
+ double half = theta / 2.0;
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 2, 2, psi_new_complex(cos(half), -sin(half)));
- psi_set_matrix(&m, 3, 3, psi_new_complex(cos(half), sin(half)));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 2, 2, psi_new_complex(cos(half), -sin(half)));
+ psi_set_matrix(&m, 3, 3, psi_new_complex(cos(half), sin(half)));
- return m;
+ return m;
}
struct PsiMatrix psi_cp_matrix(double theta)
{
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 3, 3, psi_new_complex(cos(theta), sin(theta)));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 3, 3, psi_new_complex(cos(theta), sin(theta)));
- return m;
+ return m;
}
struct PsiQuantumGate psi_hadamard_gate(void)
{
- struct PsiMatrix m =
- psi_matrix(2, 2, psi_new_complex(INV_SQRT_2, 0.0), psi_new_complex(INV_SQRT_2, 0.0),
- psi_new_complex(INV_SQRT_2, 0.0), psi_new_complex(-INV_SQRT_2, 0.0));
+ struct PsiMatrix m =
+ psi_matrix(2, 2, psi_new_complex(INV_SQRT_2, 0.0), psi_new_complex(INV_SQRT_2, 0.0),
+ psi_new_complex(INV_SQRT_2, 0.0), psi_new_complex(-INV_SQRT_2, 0.0));
- return psi_new_quantum_gate_from_matrix("H", m);
+ return psi_new_quantum_gate_from_matrix("H", m);
}
struct PsiQuantumGate psi_pauli_x_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(1.0, 0.0),
- psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(1.0, 0.0),
+ psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0));
- return psi_new_quantum_gate_from_matrix("X", m);
+ return psi_new_quantum_gate_from_matrix("X", m);
}
struct PsiQuantumGate psi_pauli_y_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(0.0, -1.0),
- psi_new_complex(0.0, 1.0), psi_new_complex(0.0, 0.0));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(0.0, -1.0),
+ psi_new_complex(0.0, 1.0), psi_new_complex(0.0, 0.0));
- return psi_new_quantum_gate_from_matrix("Y", m);
+ return psi_new_quantum_gate_from_matrix("Y", m);
}
struct PsiQuantumGate psi_pauli_z_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(-1.0, 0.0));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(-1.0, 0.0));
- return psi_new_quantum_gate_from_matrix("Z", m);
+ return psi_new_quantum_gate_from_matrix("Z", m);
}
struct PsiQuantumGate psi_s_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 1.0));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 1.0));
- return psi_new_quantum_gate_from_matrix("S", m);
+ return psi_new_quantum_gate_from_matrix("S", m);
}
struct PsiQuantumGate psi_t_gate(void)
{
- struct PsiMatrix m =
- psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(INV_SQRT_2, INV_SQRT_2));
+ struct PsiMatrix m =
+ psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(INV_SQRT_2, INV_SQRT_2));
- return psi_new_quantum_gate_from_matrix("T", m);
+ return psi_new_quantum_gate_from_matrix("T", m);
}
struct PsiQuantumGate psi_sdg_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, -1.0));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, -1.0));
- return psi_new_quantum_gate_from_matrix("S†", m);
+ return psi_new_quantum_gate_from_matrix("S†", m);
}
struct PsiQuantumGate psi_tdg_gate(void)
{
- struct PsiMatrix m =
- psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(INV_SQRT_2, -INV_SQRT_2));
+ struct PsiMatrix m =
+ psi_matrix(2, 2, psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(INV_SQRT_2, -INV_SQRT_2));
- return psi_new_quantum_gate_from_matrix("T†", m);
+ return psi_new_quantum_gate_from_matrix("T†", m);
}
struct PsiQuantumGate psi_sx_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.5, 0.5), psi_new_complex(0.5, -0.5),
- psi_new_complex(0.5, -0.5), psi_new_complex(0.5, 0.5));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.5, 0.5), psi_new_complex(0.5, -0.5),
+ psi_new_complex(0.5, -0.5), psi_new_complex(0.5, 0.5));
- return psi_new_quantum_gate_from_matrix("√X", m);
+ return psi_new_quantum_gate_from_matrix("√X", m);
}
struct PsiQuantumGate psi_sxdg_gate(void)
{
- struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.5, -0.5), psi_new_complex(0.5, 0.5),
- psi_new_complex(0.5, 0.5), psi_new_complex(0.5, -0.5));
+ struct PsiMatrix m = psi_matrix(2, 2, psi_new_complex(0.5, -0.5), psi_new_complex(0.5, 0.5),
+ psi_new_complex(0.5, 0.5), psi_new_complex(0.5, -0.5));
- return psi_new_quantum_gate_from_matrix("√X†", m);
+ return psi_new_quantum_gate_from_matrix("√X†", m);
}
struct PsiQuantumGate psi_identity_gate(void)
{
- return psi_new_quantum_gate_from_matrix("I", psi_identity_matrix(2));
+ return psi_new_quantum_gate_from_matrix("I", psi_identity_matrix(2));
}
struct PsiQuantumGate psi_cnot_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 2, 2, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 3, 3, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 2, 3, psi_new_complex(1.0, 0.0));
- psi_set_matrix(&m, 3, 2, psi_new_complex(1.0, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 2, 2, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 3, 3, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 2, 3, psi_new_complex(1.0, 0.0));
+ psi_set_matrix(&m, 3, 2, psi_new_complex(1.0, 0.0));
- return psi_new_quantum_gate_from_matrix("CNOT", m);
+ return psi_new_quantum_gate_from_matrix("CNOT", m);
}
struct PsiQuantumGate psi_cz_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 3, 3, psi_new_complex(-1.0, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 3, 3, psi_new_complex(-1.0, 0.0));
- return psi_new_quantum_gate_from_matrix("CZ", m);
+ return psi_new_quantum_gate_from_matrix("CZ", m);
}
struct PsiQuantumGate psi_swap_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 1, 1, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 2, 2, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 1, 2, psi_new_complex(1.0, 0.0));
- psi_set_matrix(&m, 2, 1, psi_new_complex(1.0, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 1, 1, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 2, 2, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 1, 2, psi_new_complex(1.0, 0.0));
+ psi_set_matrix(&m, 2, 1, psi_new_complex(1.0, 0.0));
- return psi_new_quantum_gate_from_matrix("SWAP", m);
+ return psi_new_quantum_gate_from_matrix("SWAP", m);
}
struct PsiQuantumGate psi_iswap_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 1, 1, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 2, 2, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 1, 2, psi_new_complex(0.0, 1.0));
- psi_set_matrix(&m, 2, 1, psi_new_complex(0.0, 1.0));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 1, 1, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 2, 2, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 1, 2, psi_new_complex(0.0, 1.0));
+ psi_set_matrix(&m, 2, 1, psi_new_complex(0.0, 1.0));
- return psi_new_quantum_gate_from_matrix("iSWAP", m);
+ return psi_new_quantum_gate_from_matrix("iSWAP", m);
}
struct PsiQuantumGate psi_sqrt_swap_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(4);
- psi_set_matrix(&m, 1, 1, psi_new_complex(0.5, 0.5));
- psi_set_matrix(&m, 1, 2, psi_new_complex(0.5, -0.5));
- psi_set_matrix(&m, 2, 1, psi_new_complex(0.5, -0.5));
- psi_set_matrix(&m, 2, 2, psi_new_complex(0.5, 0.5));
+ struct PsiMatrix m = psi_identity_matrix(4);
+ psi_set_matrix(&m, 1, 1, psi_new_complex(0.5, 0.5));
+ psi_set_matrix(&m, 1, 2, psi_new_complex(0.5, -0.5));
+ psi_set_matrix(&m, 2, 1, psi_new_complex(0.5, -0.5));
+ psi_set_matrix(&m, 2, 2, psi_new_complex(0.5, 0.5));
- return psi_new_quantum_gate_from_matrix("√SWAP", m);
+ return psi_new_quantum_gate_from_matrix("√SWAP", m);
}
struct PsiQuantumGate psi_toffoli_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(8);
- psi_set_matrix(&m, 6, 6, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 7, 7, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 6, 7, psi_new_complex(1.0, 0.0));
- psi_set_matrix(&m, 7, 6, psi_new_complex(1.0, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(8);
+ psi_set_matrix(&m, 6, 6, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 7, 7, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 6, 7, psi_new_complex(1.0, 0.0));
+ psi_set_matrix(&m, 7, 6, psi_new_complex(1.0, 0.0));
- return psi_new_quantum_gate_from_matrix("CCNOT", m);
+ return psi_new_quantum_gate_from_matrix("CCNOT", m);
}
struct PsiQuantumGate psi_fredkin_gate(void)
{
- struct PsiMatrix m = psi_identity_matrix(8);
- psi_set_matrix(&m, 5, 5, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 6, 6, psi_new_complex(0.0, 0.0));
- psi_set_matrix(&m, 5, 6, psi_new_complex(1.0, 0.0));
- psi_set_matrix(&m, 6, 5, psi_new_complex(1.0, 0.0));
+ struct PsiMatrix m = psi_identity_matrix(8);
+ psi_set_matrix(&m, 5, 5, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 6, 6, psi_new_complex(0.0, 0.0));
+ psi_set_matrix(&m, 5, 6, psi_new_complex(1.0, 0.0));
+ psi_set_matrix(&m, 6, 5, psi_new_complex(1.0, 0.0));
- return psi_new_quantum_gate_from_matrix("CSWAP", m);
+ return psi_new_quantum_gate_from_matrix("CSWAP", m);
}
diff --git a/src/core/kernel.c b/src/core/kernel.c
index def0782..377982f 100644
--- a/src/core/kernel.c
+++ b/src/core/kernel.c
@@ -8,598 +8,598 @@
static char* dup_string(const char* s)
{
- size_t n = strlen(s) + 1;
- char* p = malloc(n);
- assert(p != NULL);
- memcpy(p, s, n);
+ size_t n = strlen(s) + 1;
+ char* p = malloc(n);
+ assert(p != NULL);
+ memcpy(p, s, n);
- return p;
+ return p;
}
static size_t* dup_targets(const size_t* targets, size_t count)
{
- size_t* p = malloc(count * sizeof(size_t));
- assert(p != NULL || count == 0);
+ size_t* p = malloc(count * sizeof(size_t));
+ assert(p != NULL || count == 0);
- if (count > 0)
- memcpy(p, targets, count * sizeof(size_t));
+ if (count > 0)
+ memcpy(p, targets, count * sizeof(size_t));
- return p;
+ return p;
}
static bool starts_with(const char* s, const char* prefix)
{
- return strncmp(s, prefix, strlen(prefix)) == 0;
+ return strncmp(s, prefix, strlen(prefix)) == 0;
}
static enum PsiGateType detect_gate_type(const char* name, struct PsiMatrix matrix)
{
- static const char* diagonal[] = { "Z", "S", "T", "Sdg", "Tdg", "Rz",
- "P", "U1", "CZ", "CP", "CRz" };
- for (size_t i = 0; i < sizeof(diagonal) / sizeof(diagonal[0]); i++)
- if (starts_with(name, diagonal[i]))
- return PSI_GATE_TYPE_DIAGONAL;
+ static const char* diagonal[] = { "Z", "S", "T", "Sdg", "Tdg", "Rz",
+ "P", "U1", "CZ", "CP", "CRz" };
+ for (size_t i = 0; i < sizeof(diagonal) / sizeof(diagonal[0]); i++)
+ if (starts_with(name, diagonal[i]))
+ return PSI_GATE_TYPE_DIAGONAL;
- static const char* controlled[] = { "CNOT", "CZ", "SWAP", "CRx", "CRy",
- "CRz", "CP", "CCNOT", "CSWAP" };
- for (size_t i = 0; i < sizeof(controlled) / sizeof(controlled[0]); i++)
- if (starts_with(name, controlled[i]))
- return PSI_GATE_TYPE_CONTROLLED;
+ static const char* controlled[] = { "CNOT", "CZ", "SWAP", "CRx", "CRy",
+ "CRz", "CP", "CCNOT", "CSWAP" };
+ for (size_t i = 0; i < sizeof(controlled) / sizeof(controlled[0]); i++)
+ if (starts_with(name, controlled[i]))
+ return PSI_GATE_TYPE_CONTROLLED;
- if (matrix.rows == 2 && matrix.cols == 2)
- {
- bool is_diag = fabs(matrix.data[1].real) < 1e-10 &&
- fabs(matrix.data[1].imaginary) < 1e-10 && fabs(matrix.data[2].real) < 1e-10 &&
- fabs(matrix.data[2].imaginary) < 1e-10;
- if (is_diag)
- return PSI_GATE_TYPE_DIAGONAL;
- }
+ if (matrix.rows == 2 && matrix.cols == 2)
+ {
+ bool is_diag = fabs(matrix.data[1].real) < 1e-10 &&
+ fabs(matrix.data[1].imaginary) < 1e-10 && fabs(matrix.data[2].real) < 1e-10 &&
+ fabs(matrix.data[2].imaginary) < 1e-10;
+ if (is_diag)
+ return PSI_GATE_TYPE_DIAGONAL;
+ }
- return PSI_GATE_TYPE_NON_DIAGONAL;
+ return PSI_GATE_TYPE_NON_DIAGONAL;
}
struct PsiKernel psi_new_kernel(const char* name, struct PsiMatrix matrix, const size_t* targets,
size_t target_count)
{
- struct PsiKernel kernel;
- kernel.matrix = matrix;
- kernel.targets = dup_targets(targets, target_count);
- kernel.target_count = target_count;
- kernel.name = dup_string(name);
- kernel.gate_type = detect_gate_type(name, matrix);
+ struct PsiKernel kernel;
+ kernel.matrix = matrix;
+ kernel.targets = dup_targets(targets, target_count);
+ kernel.target_count = target_count;
+ kernel.name = dup_string(name);
+ kernel.gate_type = detect_gate_type(name, matrix);
- return kernel;
+ return kernel;
}
struct PsiKernel psi_clone_kernel(struct PsiKernel kernel)
{
- struct PsiKernel copy;
- copy.matrix = psi_clone_matrix(kernel.matrix);
- copy.targets = dup_targets(kernel.targets, kernel.target_count);
- copy.target_count = kernel.target_count;
- copy.name = dup_string(kernel.name);
- copy.gate_type = kernel.gate_type;
+ struct PsiKernel copy;
+ copy.matrix = psi_clone_matrix(kernel.matrix);
+ copy.targets = dup_targets(kernel.targets, kernel.target_count);
+ copy.target_count = kernel.target_count;
+ copy.name = dup_string(kernel.name);
+ copy.gate_type = kernel.gate_type;
- return copy;
+ return copy;
}
void psi_free_kernel(struct PsiKernel* kernel)
{
- psi_free_matrix(&kernel->matrix);
- free(kernel->targets);
- free(kernel->name);
- kernel->targets = NULL;
- kernel->name = NULL;
- kernel->target_count = 0;
+ psi_free_matrix(&kernel->matrix);
+ free(kernel->targets);
+ free(kernel->name);
+ kernel->targets = NULL;
+ kernel->name = NULL;
+ kernel->target_count = 0;
}
static bool targets_equal(struct PsiKernel a, struct PsiKernel b)
{
- if (a.target_count != b.target_count)
- return false;
+ if (a.target_count != b.target_count)
+ return false;
- for (size_t i = 0; i < a.target_count; i++)
- if (a.targets[i] != b.targets[i])
- return false;
+ for (size_t i = 0; i < a.target_count; i++)
+ if (a.targets[i] != b.targets[i])
+ return false;
- return true;
+ return true;
}
bool psi_kernels_share_qubits(struct PsiKernel a, struct PsiKernel b)
{
- for (size_t i = 0; i < a.target_count; i++)
- for (size_t j = 0; j < b.target_count; j++)
- if (a.targets[i] == b.targets[j])
- return true;
+ for (size_t i = 0; i < a.target_count; i++)
+ for (size_t j = 0; j < b.target_count; j++)
+ if (a.targets[i] == b.targets[j])
+ return true;
- return false;
+ return false;
}
bool psi_kernels_commute(struct PsiKernel a, struct PsiKernel b)
{
- if (!psi_kernels_share_qubits(a, b))
- return true;
+ if (!psi_kernels_share_qubits(a, b))
+ return true;
- if (a.gate_type == PSI_GATE_TYPE_DIAGONAL && b.gate_type == PSI_GATE_TYPE_DIAGONAL &&
- targets_equal(a, b))
- return true;
+ if (a.gate_type == PSI_GATE_TYPE_DIAGONAL && b.gate_type == PSI_GATE_TYPE_DIAGONAL &&
+ targets_equal(a, b))
+ return true;
- return false;
+ return false;
}
bool psi_kernels_can_fuse(struct PsiKernel a, struct PsiKernel b)
{
- if (a.target_count != 1 || b.target_count != 1)
- return false;
+ if (a.target_count != 1 || b.target_count != 1)
+ return false;
- return a.targets[0] == b.targets[0];
+ return a.targets[0] == b.targets[0];
}
bool psi_fuse_kernels(struct PsiKernel a, struct PsiKernel b, struct PsiKernel* out)
{
- if (!psi_kernels_can_fuse(a, b))
- return false;
+ if (!psi_kernels_can_fuse(a, b))
+ return false;
- enum PsiGateType new_type =
- a.gate_type == PSI_GATE_TYPE_DIAGONAL && b.gate_type == PSI_GATE_TYPE_DIAGONAL
- ? PSI_GATE_TYPE_DIAGONAL
- : PSI_GATE_TYPE_NON_DIAGONAL;
+ enum PsiGateType new_type =
+ a.gate_type == PSI_GATE_TYPE_DIAGONAL && b.gate_type == PSI_GATE_TYPE_DIAGONAL
+ ? PSI_GATE_TYPE_DIAGONAL
+ : PSI_GATE_TYPE_NON_DIAGONAL;
- size_t name_len = strlen(a.name) + strlen(b.name) + 2;
- char* fused_name = malloc(name_len);
- assert(fused_name != NULL);
- snprintf(fused_name, name_len, "%s+%s", a.name, b.name);
+ size_t name_len = strlen(a.name) + strlen(b.name) + 2;
+ char* fused_name = malloc(name_len);
+ assert(fused_name != NULL);
+ snprintf(fused_name, name_len, "%s+%s", a.name, b.name);
- out->matrix = psi_dot_matrix(b.matrix, a.matrix);
- out->targets = dup_targets(a.targets, a.target_count);
- out->target_count = a.target_count;
- out->name = fused_name;
- out->gate_type = new_type;
+ out->matrix = psi_dot_matrix(b.matrix, a.matrix);
+ out->targets = dup_targets(a.targets, a.target_count);
+ out->target_count = a.target_count;
+ out->name = fused_name;
+ out->gate_type = new_type;
- return true;
+ return true;
}
static struct PsiComplex* apply_kernel(const struct PsiComplex* state, struct PsiKernel kernel,
size_t num_qubits)
{
- size_t dim = (size_t)1 << num_qubits;
- size_t g = kernel.target_count;
- size_t gate_dim = (size_t)1 << g;
+ size_t dim = (size_t)1 << num_qubits;
+ size_t g = kernel.target_count;
+ size_t gate_dim = (size_t)1 << g;
- size_t* target_bits = malloc(g * sizeof(size_t));
- assert(target_bits != NULL || g == 0);
- for (size_t k = 0; k < g; k++)
- target_bits[k] = num_qubits - 1 - kernel.targets[k];
+ size_t* target_bits = malloc(g * sizeof(size_t));
+ assert(target_bits != NULL || g == 0);
+ for (size_t k = 0; k < g; k++)
+ target_bits[k] = num_qubits - 1 - kernel.targets[k];
- size_t non_target_mask = dim - 1;
- for (size_t k = 0; k < g; k++)
- non_target_mask &= ~((size_t)1 << target_bits[k]);
+ size_t non_target_mask = dim - 1;
+ for (size_t k = 0; k < g; k++)
+ non_target_mask &= ~((size_t)1 << target_bits[k]);
- struct PsiComplex* new_state = malloc(dim * sizeof(struct PsiComplex));
- assert(new_state != NULL);
+ struct PsiComplex* new_state = malloc(dim * sizeof(struct PsiComplex));
+ assert(new_state != NULL);
- for (size_t i = 0; i < dim; i++)
- {
- size_t target_idx = 0;
- for (size_t k = 0; k < g; k++)
- if ((i >> target_bits[k]) & 1)
- target_idx |= (size_t)1 << (g - 1 - k);
+ for (size_t i = 0; i < dim; i++)
+ {
+ size_t target_idx = 0;
+ for (size_t k = 0; k < g; k++)
+ if ((i >> target_bits[k]) & 1)
+ target_idx |= (size_t)1 << (g - 1 - k);
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t j = 0; j < gate_dim; j++)
- {
- struct PsiComplex gate_elem = kernel.matrix.data[target_idx * gate_dim + j];
- if (fabs(gate_elem.real) < 1e-15 && fabs(gate_elem.imaginary) < 1e-15)
- continue;
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t j = 0; j < gate_dim; j++)
+ {
+ struct PsiComplex gate_elem = kernel.matrix.data[target_idx * gate_dim + j];
+ if (fabs(gate_elem.real) < 1e-15 && fabs(gate_elem.imaginary) < 1e-15)
+ continue;
- size_t source_idx = i & non_target_mask;
- for (size_t k = 0; k < g; k++)
- if ((j >> (g - 1 - k)) & 1)
- source_idx |= (size_t)1 << target_bits[k];
+ size_t source_idx = i & non_target_mask;
+ for (size_t k = 0; k < g; k++)
+ if ((j >> (g - 1 - k)) & 1)
+ source_idx |= (size_t)1 << target_bits[k];
- sum = psi_add_complex(sum, psi_mul_complex(gate_elem, state[source_idx]));
- }
+ sum = psi_add_complex(sum, psi_mul_complex(gate_elem, state[source_idx]));
+ }
- new_state[i] = sum;
- }
+ new_state[i] = sum;
+ }
- free(target_bits);
- return new_state;
+ free(target_bits);
+ return new_state;
}
struct PsiKernelBatch psi_new_kernel_batch(size_t num_qubits)
{
- struct PsiKernelBatch batch;
- batch.kernels = NULL;
- batch.count = 0;
- batch.capacity = 0;
- batch.num_qubits = num_qubits;
+ struct PsiKernelBatch batch;
+ batch.kernels = NULL;
+ batch.count = 0;
+ batch.capacity = 0;
+ batch.num_qubits = num_qubits;
- return batch;
+ return batch;
}
void psi_free_kernel_batch(struct PsiKernelBatch* batch)
{
- for (size_t i = 0; i < batch->count; i++)
- psi_free_kernel(&batch->kernels[i]);
+ for (size_t i = 0; i < batch->count; i++)
+ psi_free_kernel(&batch->kernels[i]);
- free(batch->kernels);
- batch->kernels = NULL;
- batch->count = 0;
- batch->capacity = 0;
+ free(batch->kernels);
+ batch->kernels = NULL;
+ batch->count = 0;
+ batch->capacity = 0;
}
void psi_add_kernel(struct PsiKernelBatch* batch, struct PsiKernel kernel)
{
- if (batch->count == batch->capacity)
- {
- size_t new_capacity = batch->capacity == 0 ? 8 : batch->capacity * 2;
- batch->kernels = realloc(batch->kernels, new_capacity * sizeof(struct PsiKernel));
- assert(batch->kernels != NULL);
- batch->capacity = new_capacity;
- }
+ if (batch->count == batch->capacity)
+ {
+ size_t new_capacity = batch->capacity == 0 ? 8 : batch->capacity * 2;
+ batch->kernels = realloc(batch->kernels, new_capacity * sizeof(struct PsiKernel));
+ assert(batch->kernels != NULL);
+ batch->capacity = new_capacity;
+ }
- batch->kernels[batch->count++] = kernel;
+ batch->kernels[batch->count++] = kernel;
}
void psi_optimize_kernel_batch(struct PsiKernelBatch* batch)
{
- if (batch->count < 2)
- return;
+ if (batch->count < 2)
+ return;
- size_t original = batch->count;
- struct PsiKernel* out = malloc(original * sizeof(struct PsiKernel));
- assert(out != NULL);
- size_t out_count = 0;
+ size_t original = batch->count;
+ struct PsiKernel* out = malloc(original * sizeof(struct PsiKernel));
+ assert(out != NULL);
+ size_t out_count = 0;
- size_t i = 0;
- while (i < batch->count)
- {
- if (i + 1 < batch->count)
- {
- struct PsiKernel fused;
- if (psi_fuse_kernels(batch->kernels[i], batch->kernels[i + 1], &fused))
- {
- psi_free_kernel(&batch->kernels[i]);
- psi_free_kernel(&batch->kernels[i + 1]);
- out[out_count++] = fused;
- i += 2;
- continue;
- }
- }
+ size_t i = 0;
+ while (i < batch->count)
+ {
+ if (i + 1 < batch->count)
+ {
+ struct PsiKernel fused;
+ if (psi_fuse_kernels(batch->kernels[i], batch->kernels[i + 1], &fused))
+ {
+ psi_free_kernel(&batch->kernels[i]);
+ psi_free_kernel(&batch->kernels[i + 1]);
+ out[out_count++] = fused;
+ i += 2;
+ continue;
+ }
+ }
- out[out_count++] = batch->kernels[i];
- i += 1;
- }
+ out[out_count++] = batch->kernels[i];
+ i += 1;
+ }
- free(batch->kernels);
- batch->kernels = out;
- batch->count = out_count;
- batch->capacity = original;
+ free(batch->kernels);
+ batch->kernels = out;
+ batch->count = out_count;
+ batch->capacity = original;
}
void psi_execute_kernel_batch(struct PsiKernelBatch batch, struct PsiVector* state)
{
- size_t dim = (size_t)1 << batch.num_qubits;
- assert(state->size == dim);
+ size_t dim = (size_t)1 << batch.num_qubits;
+ assert(state->size == dim);
- for (size_t i = 0; i < batch.count; i++)
- {
- struct PsiComplex* next = apply_kernel(state->data, batch.kernels[i], batch.num_qubits);
- free(state->data);
- state->data = next;
- }
+ for (size_t i = 0; i < batch.count; i++)
+ {
+ struct PsiComplex* next = apply_kernel(state->data, batch.kernels[i], batch.num_qubits);
+ free(state->data);
+ state->data = next;
+ }
}
void psi_apply_kernel(struct PsiVector* state, struct PsiKernel kernel, size_t num_qubits)
{
- struct PsiComplex* next = apply_kernel(state->data, kernel, num_qubits);
- free(state->data);
- state->data = next;
+ struct PsiComplex* next = apply_kernel(state->data, kernel, num_qubits);
+ free(state->data);
+ state->data = next;
}
static void push_kernel(struct PsiKernel** kernels, size_t* count, size_t* capacity,
struct PsiKernel kernel)
{
- if (*count == *capacity)
- {
- size_t new_capacity = *capacity == 0 ? 8 : *capacity * 2;
- *kernels = realloc(*kernels, new_capacity * sizeof(struct PsiKernel));
- assert(*kernels != NULL);
- *capacity = new_capacity;
- }
+ if (*count == *capacity)
+ {
+ size_t new_capacity = *capacity == 0 ? 8 : *capacity * 2;
+ *kernels = realloc(*kernels, new_capacity * sizeof(struct PsiKernel));
+ assert(*kernels != NULL);
+ *capacity = new_capacity;
+ }
- (*kernels)[(*count)++] = kernel;
+ (*kernels)[(*count)++] = kernel;
}
static bool layer_can_add(struct PsiExecutionLayer layer, struct PsiKernel kernel)
{
- for (size_t i = 0; i < layer.count; i++)
- if (psi_kernels_share_qubits(layer.kernels[i], kernel))
- return false;
+ for (size_t i = 0; i < layer.count; i++)
+ if (psi_kernels_share_qubits(layer.kernels[i], kernel))
+ return false;
- return true;
+ return true;
}
static void free_layer(struct PsiExecutionLayer* layer)
{
- for (size_t i = 0; i < layer->count; i++)
- psi_free_kernel(&layer->kernels[i]);
+ for (size_t i = 0; i < layer->count; i++)
+ psi_free_kernel(&layer->kernels[i]);
- free(layer->kernels);
- layer->kernels = NULL;
- layer->count = 0;
- layer->capacity = 0;
+ free(layer->kernels);
+ layer->kernels = NULL;
+ layer->count = 0;
+ layer->capacity = 0;
}
struct PsiStructureAwareBatch psi_new_structure_aware_batch(size_t num_qubits)
{
- struct PsiStructureAwareBatch batch;
- batch.kernels = NULL;
- batch.count = 0;
- batch.capacity = 0;
- batch.layers = NULL;
- batch.layer_count = 0;
- batch.layer_capacity = 0;
- batch.num_qubits = num_qubits;
- batch.optimised = false;
+ struct PsiStructureAwareBatch batch;
+ batch.kernels = NULL;
+ batch.count = 0;
+ batch.capacity = 0;
+ batch.layers = NULL;
+ batch.layer_count = 0;
+ batch.layer_capacity = 0;
+ batch.num_qubits = num_qubits;
+ batch.optimised = false;
- return batch;
+ return batch;
}
static void clear_layers(struct PsiStructureAwareBatch* batch)
{
- for (size_t i = 0; i < batch->layer_count; i++)
- free_layer(&batch->layers[i]);
+ for (size_t i = 0; i < batch->layer_count; i++)
+ free_layer(&batch->layers[i]);
- free(batch->layers);
- batch->layers = NULL;
- batch->layer_count = 0;
- batch->layer_capacity = 0;
+ free(batch->layers);
+ batch->layers = NULL;
+ batch->layer_count = 0;
+ batch->layer_capacity = 0;
}
void psi_free_structure_aware_batch(struct PsiStructureAwareBatch* batch)
{
- for (size_t i = 0; i < batch->count; i++)
- psi_free_kernel(&batch->kernels[i]);
+ for (size_t i = 0; i < batch->count; i++)
+ psi_free_kernel(&batch->kernels[i]);
- free(batch->kernels);
- batch->kernels = NULL;
- batch->count = 0;
- batch->capacity = 0;
- clear_layers(batch);
+ free(batch->kernels);
+ batch->kernels = NULL;
+ batch->count = 0;
+ batch->capacity = 0;
+ clear_layers(batch);
}
void psi_add_structure_aware_kernel(struct PsiStructureAwareBatch* batch, struct PsiKernel kernel)
{
- push_kernel(&batch->kernels, &batch->count, &batch->capacity, kernel);
- batch->optimised = false;
+ push_kernel(&batch->kernels, &batch->count, &batch->capacity, kernel);
+ batch->optimised = false;
}
static struct PsiKernel remove_kernel_at(struct PsiStructureAwareBatch* batch, size_t index)
{
- struct PsiKernel removed = batch->kernels[index];
- for (size_t i = index; i + 1 < batch->count; i++)
- batch->kernels[i] = batch->kernels[i + 1];
+ struct PsiKernel removed = batch->kernels[index];
+ for (size_t i = index; i + 1 < batch->count; i++)
+ batch->kernels[i] = batch->kernels[i + 1];
- batch->count--;
- return removed;
+ batch->count--;
+ return removed;
}
static void insert_kernel_at(struct PsiStructureAwareBatch* batch, size_t index,
struct PsiKernel kernel)
{
- if (batch->count == batch->capacity)
- {
- size_t new_capacity = batch->capacity == 0 ? 8 : batch->capacity * 2;
- batch->kernels = realloc(batch->kernels, new_capacity * sizeof(struct PsiKernel));
- assert(batch->kernels != NULL);
- batch->capacity = new_capacity;
- }
+ if (batch->count == batch->capacity)
+ {
+ size_t new_capacity = batch->capacity == 0 ? 8 : batch->capacity * 2;
+ batch->kernels = realloc(batch->kernels, new_capacity * sizeof(struct PsiKernel));
+ assert(batch->kernels != NULL);
+ batch->capacity = new_capacity;
+ }
- for (size_t i = batch->count; i > index; i--)
- batch->kernels[i] = batch->kernels[i - 1];
+ for (size_t i = batch->count; i > index; i--)
+ batch->kernels[i] = batch->kernels[i - 1];
- batch->kernels[index] = kernel;
- batch->count++;
+ batch->kernels[index] = kernel;
+ batch->count++;
}
static void reorder_commuting_gates(struct PsiStructureAwareBatch* batch)
{
- bool changed = true;
- size_t iterations = 0;
- const size_t MAX_ITERATIONS = 100;
+ bool changed = true;
+ size_t iterations = 0;
+ const size_t MAX_ITERATIONS = 100;
- while (changed && iterations < MAX_ITERATIONS)
- {
- changed = false;
- iterations++;
+ while (changed && iterations < MAX_ITERATIONS)
+ {
+ changed = false;
+ iterations++;
- for (size_t i = 0; i + 1 < batch->count; i++)
- {
- struct PsiKernel current = batch->kernels[i];
- struct PsiKernel next = batch->kernels[i + 1];
+ for (size_t i = 0; i + 1 < batch->count; i++)
+ {
+ struct PsiKernel current = batch->kernels[i];
+ struct PsiKernel next = batch->kernels[i + 1];
- if (current.target_count != 1 || next.target_count != 1 ||
- current.targets[0] == next.targets[0] || !psi_kernels_commute(current, next))
- continue;
+ if (current.target_count != 1 || next.target_count != 1 ||
+ current.targets[0] == next.targets[0] || !psi_kernels_commute(current, next))
+ continue;
- for (size_t j = i + 2; j < batch->count; j++)
- {
- struct PsiKernel candidate = batch->kernels[j];
- if (candidate.target_count != 1 || candidate.targets[0] != current.targets[0])
- continue;
+ for (size_t j = i + 2; j < batch->count; j++)
+ {
+ struct PsiKernel candidate = batch->kernels[j];
+ if (candidate.target_count != 1 || candidate.targets[0] != current.targets[0])
+ continue;
- bool can_move = true;
- for (size_t k = i + 1; k < j; k++)
- {
- struct PsiKernel between = batch->kernels[k];
- if (psi_kernels_share_qubits(between, current) &&
- !psi_kernels_commute(current, between))
- {
- can_move = false;
- break;
- }
- }
+ bool can_move = true;
+ for (size_t k = i + 1; k < j; k++)
+ {
+ struct PsiKernel between = batch->kernels[k];
+ if (psi_kernels_share_qubits(between, current) &&
+ !psi_kernels_commute(current, between))
+ {
+ can_move = false;
+ break;
+ }
+ }
- if (can_move && psi_kernels_can_fuse(current, candidate))
- {
- struct PsiKernel moved = remove_kernel_at(batch, j);
- insert_kernel_at(batch, i + 1, moved);
- changed = true;
- break;
- }
- }
- }
- }
+ if (can_move && psi_kernels_can_fuse(current, candidate))
+ {
+ struct PsiKernel moved = remove_kernel_at(batch, j);
+ insert_kernel_at(batch, i + 1, moved);
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
}
static void multi_pass_fusion(struct PsiStructureAwareBatch* batch)
{
- bool changed = true;
- size_t iterations = 0;
- const size_t MAX_ITERATIONS = 50;
+ bool changed = true;
+ size_t iterations = 0;
+ const size_t MAX_ITERATIONS = 50;
- while (changed && iterations < MAX_ITERATIONS)
- {
- changed = false;
- iterations++;
+ while (changed && iterations < MAX_ITERATIONS)
+ {
+ changed = false;
+ iterations++;
- struct PsiKernel* new_kernels = NULL;
- size_t new_count = 0;
- size_t new_capacity = 0;
+ struct PsiKernel* new_kernels = NULL;
+ size_t new_count = 0;
+ size_t new_capacity = 0;
- size_t i = 0;
- while (i < batch->count)
- {
- if (i + 1 < batch->count)
- {
- struct PsiKernel fused;
- if (psi_fuse_kernels(batch->kernels[i], batch->kernels[i + 1], &fused))
- {
- psi_free_kernel(&batch->kernels[i]);
- psi_free_kernel(&batch->kernels[i + 1]);
- push_kernel(&new_kernels, &new_count, &new_capacity, fused);
- i += 2;
- changed = true;
- continue;
- }
- }
+ size_t i = 0;
+ while (i < batch->count)
+ {
+ if (i + 1 < batch->count)
+ {
+ struct PsiKernel fused;
+ if (psi_fuse_kernels(batch->kernels[i], batch->kernels[i + 1], &fused))
+ {
+ psi_free_kernel(&batch->kernels[i]);
+ psi_free_kernel(&batch->kernels[i + 1]);
+ push_kernel(&new_kernels, &new_count, &new_capacity, fused);
+ i += 2;
+ changed = true;
+ continue;
+ }
+ }
- push_kernel(&new_kernels, &new_count, &new_capacity, batch->kernels[i]);
- i++;
- }
+ push_kernel(&new_kernels, &new_count, &new_capacity, batch->kernels[i]);
+ i++;
+ }
- free(batch->kernels);
- batch->kernels = new_kernels;
- batch->count = new_count;
- batch->capacity = new_capacity;
- }
+ free(batch->kernels);
+ batch->kernels = new_kernels;
+ batch->count = new_count;
+ batch->capacity = new_capacity;
+ }
}
static void build_execution_layers(struct PsiStructureAwareBatch* batch)
{
- clear_layers(batch);
+ clear_layers(batch);
- for (size_t i = 0; i < batch->count; i++)
- {
- struct PsiKernel kernel = batch->kernels[i];
- bool placed = false;
+ for (size_t i = 0; i < batch->count; i++)
+ {
+ struct PsiKernel kernel = batch->kernels[i];
+ bool placed = false;
- for (size_t l = 0; l < batch->layer_count; l++)
- if (layer_can_add(batch->layers[l], kernel))
- {
- struct PsiExecutionLayer* layer = &batch->layers[l];
- push_kernel(&layer->kernels, &layer->count, &layer->capacity,
- psi_clone_kernel(kernel));
- placed = true;
- break;
- }
+ for (size_t l = 0; l < batch->layer_count; l++)
+ if (layer_can_add(batch->layers[l], kernel))
+ {
+ struct PsiExecutionLayer* layer = &batch->layers[l];
+ push_kernel(&layer->kernels, &layer->count, &layer->capacity,
+ psi_clone_kernel(kernel));
+ placed = true;
+ break;
+ }
- if (placed)
- continue;
+ if (placed)
+ continue;
- if (batch->layer_count == batch->layer_capacity)
- {
- size_t new_capacity = batch->layer_capacity == 0 ? 4 : batch->layer_capacity * 2;
- batch->layers = realloc(batch->layers, new_capacity * sizeof(struct PsiExecutionLayer));
- assert(batch->layers != NULL);
- batch->layer_capacity = new_capacity;
- }
+ if (batch->layer_count == batch->layer_capacity)
+ {
+ size_t new_capacity = batch->layer_capacity == 0 ? 4 : batch->layer_capacity * 2;
+ batch->layers = realloc(batch->layers, new_capacity * sizeof(struct PsiExecutionLayer));
+ assert(batch->layers != NULL);
+ batch->layer_capacity = new_capacity;
+ }
- struct PsiExecutionLayer layer;
- layer.kernels = NULL;
- layer.count = 0;
- layer.capacity = 0;
- push_kernel(&layer.kernels, &layer.count, &layer.capacity, psi_clone_kernel(kernel));
- batch->layers[batch->layer_count++] = layer;
- }
+ struct PsiExecutionLayer layer;
+ layer.kernels = NULL;
+ layer.count = 0;
+ layer.capacity = 0;
+ push_kernel(&layer.kernels, &layer.count, &layer.capacity, psi_clone_kernel(kernel));
+ batch->layers[batch->layer_count++] = layer;
+ }
}
void psi_optimize_structure_aware_batch(struct PsiStructureAwareBatch* batch)
{
- if (batch->optimised || batch->count < 2)
- return;
+ if (batch->optimised || batch->count < 2)
+ return;
- reorder_commuting_gates(batch);
- multi_pass_fusion(batch);
- build_execution_layers(batch);
- batch->optimised = true;
+ reorder_commuting_gates(batch);
+ multi_pass_fusion(batch);
+ build_execution_layers(batch);
+ batch->optimised = true;
}
void psi_execute_structure_aware_batch(struct PsiStructureAwareBatch batch, struct PsiVector* state)
{
- size_t dim = (size_t)1 << batch.num_qubits;
- assert(state->size == dim);
+ size_t dim = (size_t)1 << batch.num_qubits;
+ assert(state->size == dim);
- for (size_t i = 0; i < batch.count; i++)
- {
- struct PsiComplex* next = apply_kernel(state->data, batch.kernels[i], batch.num_qubits);
- free(state->data);
- state->data = next;
- }
+ for (size_t i = 0; i < batch.count; i++)
+ {
+ struct PsiComplex* next = apply_kernel(state->data, batch.kernels[i], batch.num_qubits);
+ free(state->data);
+ state->data = next;
+ }
}
void psi_execute_structure_aware_batch_layered(struct PsiStructureAwareBatch batch,
struct PsiVector* state)
{
- size_t dim = (size_t)1 << batch.num_qubits;
- assert(state->size == dim);
+ size_t dim = (size_t)1 << batch.num_qubits;
+ assert(state->size == dim);
- for (size_t l = 0; l < batch.layer_count; l++)
- for (size_t k = 0; k < batch.layers[l].count; k++)
- {
- struct PsiComplex* next =
- apply_kernel(state->data, batch.layers[l].kernels[k], batch.num_qubits);
- free(state->data);
- state->data = next;
- }
+ for (size_t l = 0; l < batch.layer_count; l++)
+ for (size_t k = 0; k < batch.layers[l].count; k++)
+ {
+ struct PsiComplex* next =
+ apply_kernel(state->data, batch.layers[l].kernels[k], batch.num_qubits);
+ free(state->data);
+ state->data = next;
+ }
}
struct PsiKernelStats psi_structure_aware_batch_stats(struct PsiStructureAwareBatch batch)
{
- struct PsiKernelStats stats;
- stats.total_kernels = batch.count;
- stats.single_qubit = 0;
- stats.two_qubit = 0;
- stats.multi_qubit = 0;
- stats.diagonal = 0;
- stats.execution_layers = batch.layer_count;
+ struct PsiKernelStats stats;
+ stats.total_kernels = batch.count;
+ stats.single_qubit = 0;
+ stats.two_qubit = 0;
+ stats.multi_qubit = 0;
+ stats.diagonal = 0;
+ stats.execution_layers = batch.layer_count;
- for (size_t i = 0; i < batch.count; i++)
- {
- struct PsiKernel kernel = batch.kernels[i];
+ for (size_t i = 0; i < batch.count; i++)
+ {
+ struct PsiKernel kernel = batch.kernels[i];
- if (kernel.target_count == 1)
- stats.single_qubit++;
- else if (kernel.target_count == 2)
- stats.two_qubit++;
- else if (kernel.target_count > 2)
- stats.multi_qubit++;
+ if (kernel.target_count == 1)
+ stats.single_qubit++;
+ else if (kernel.target_count == 2)
+ stats.two_qubit++;
+ else if (kernel.target_count > 2)
+ stats.multi_qubit++;
- if (kernel.gate_type == PSI_GATE_TYPE_DIAGONAL)
- stats.diagonal++;
- }
+ if (kernel.gate_type == PSI_GATE_TYPE_DIAGONAL)
+ stats.diagonal++;
+ }
- return stats;
+ return stats;
}
diff --git a/src/core/noise.c b/src/core/noise.c
index 5f141c8..0f73c48 100644
--- a/src/core/noise.c
+++ b/src/core/noise.c
@@ -7,415 +7,415 @@
struct PsiKrausOperator psi_new_kraus_operator(const char* name, struct PsiMatrix matrix)
{
- return (struct PsiKrausOperator){
- matrix,
- name,
- };
+ return (struct PsiKrausOperator){
+ matrix,
+ name,
+ };
}
void psi_free_kraus_operator(struct PsiKrausOperator* op)
{
- psi_free_matrix(&op->matrix);
+ psi_free_matrix(&op->matrix);
}
struct PsiNoiseChannel psi_new_noise_channel(const char* name,
const struct PsiKrausOperator* operators, size_t count,
size_t num_qubits)
{
- struct PsiKrausOperator* owned = malloc(count * sizeof(struct PsiKrausOperator));
- assert(owned != NULL || count == 0);
+ struct PsiKrausOperator* owned = malloc(count * sizeof(struct PsiKrausOperator));
+ assert(owned != NULL || count == 0);
- if (count > 0)
- memcpy(owned, operators, count * sizeof(struct PsiKrausOperator));
+ if (count > 0)
+ memcpy(owned, operators, count * sizeof(struct PsiKrausOperator));
- return (struct PsiNoiseChannel){
- name,
- owned,
- count,
- num_qubits,
- };
+ return (struct PsiNoiseChannel){
+ name,
+ owned,
+ count,
+ num_qubits,
+ };
}
void psi_free_noise_channel(struct PsiNoiseChannel* channel)
{
- for (size_t i = 0; i < channel->operator_count; i++)
- psi_free_matrix(&channel->operators[i].matrix);
+ for (size_t i = 0; i < channel->operator_count; i++)
+ psi_free_matrix(&channel->operators[i].matrix);
- free(channel->operators);
- channel->operators = NULL;
- channel->operator_count = 0;
+ free(channel->operators);
+ channel->operators = NULL;
+ channel->operator_count = 0;
}
struct PsiNoiseChannel psi_depolarising_channel(double p)
{
- double sqrt_1_p = sqrt(1.0 - p);
- double sqrt_p3 = sqrt(p / 3.0);
+ double sqrt_1_p = sqrt(1.0 - p);
+ double sqrt_p3 = sqrt(p / 3.0);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0",
- psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_p, 0.0))),
- psi_new_kraus_operator(
- "K1(X)",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(sqrt_p3, 0.0),
- psi_new_complex(sqrt_p3, 0.0), psi_new_complex(0.0, 0.0))),
- psi_new_kraus_operator(
- "K2(Y)",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(0.0, -sqrt_p3),
- psi_new_complex(0.0, sqrt_p3), psi_new_complex(0.0, 0.0))),
- psi_new_kraus_operator("K3(Z)",
- psi_matrix(2, 2, psi_new_complex(sqrt_p3, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(-sqrt_p3, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0",
+ psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_p, 0.0))),
+ psi_new_kraus_operator(
+ "K1(X)",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(sqrt_p3, 0.0),
+ psi_new_complex(sqrt_p3, 0.0), psi_new_complex(0.0, 0.0))),
+ psi_new_kraus_operator(
+ "K2(Y)",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(0.0, -sqrt_p3),
+ psi_new_complex(0.0, sqrt_p3), psi_new_complex(0.0, 0.0))),
+ psi_new_kraus_operator("K3(Z)",
+ psi_matrix(2, 2, psi_new_complex(sqrt_p3, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(-sqrt_p3, 0.0))),
+ };
- return psi_new_noise_channel("Depolarising", ops, 4, 1);
+ return psi_new_noise_channel("Depolarising", ops, 4, 1);
}
struct PsiNoiseChannel psi_amplitude_damping_channel(double gamma)
{
- double sqrt_gamma = sqrt(gamma);
- double sqrt_1_gamma = sqrt(1.0 - gamma);
+ double sqrt_gamma = sqrt(gamma);
+ double sqrt_1_gamma = sqrt(1.0 - gamma);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0",
- psi_matrix(2, 2, psi_new_complex(1.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_gamma, 0.0))),
- psi_new_kraus_operator("K1",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_gamma, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0",
+ psi_matrix(2, 2, psi_new_complex(1.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_gamma, 0.0))),
+ psi_new_kraus_operator("K1",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_gamma, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0))),
+ };
- return psi_new_noise_channel("AmplitudeDamping", ops, 2, 1);
+ return psi_new_noise_channel("AmplitudeDamping", ops, 2, 1);
}
struct PsiNoiseChannel psi_phase_damping_channel(double gamma)
{
- double sqrt_gamma = sqrt(gamma);
- double sqrt_1_gamma = sqrt(1.0 - gamma);
+ double sqrt_gamma = sqrt(gamma);
+ double sqrt_1_gamma = sqrt(1.0 - gamma);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0",
- psi_matrix(2, 2, psi_new_complex(1.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_gamma, 0.0))),
- psi_new_kraus_operator("K1",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_gamma, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0",
+ psi_matrix(2, 2, psi_new_complex(1.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_gamma, 0.0))),
+ psi_new_kraus_operator("K1",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_gamma, 0.0))),
+ };
- return psi_new_noise_channel("PhaseDamping", ops, 2, 1);
+ return psi_new_noise_channel("PhaseDamping", ops, 2, 1);
}
struct PsiNoiseChannel psi_bit_flip_channel(double p)
{
- double sqrt_1_p = sqrt(1.0 - p);
- double sqrt_p = sqrt(p);
+ double sqrt_1_p = sqrt(1.0 - p);
+ double sqrt_p = sqrt(p);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0(I)",
- psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_p, 0.0))),
- psi_new_kraus_operator("K1(X)",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_p, 0.0),
- psi_new_complex(sqrt_p, 0.0), psi_new_complex(0.0, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0(I)",
+ psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_p, 0.0))),
+ psi_new_kraus_operator("K1(X)",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_p, 0.0),
+ psi_new_complex(sqrt_p, 0.0), psi_new_complex(0.0, 0.0))),
+ };
- return psi_new_noise_channel("BitFlip", ops, 2, 1);
+ return psi_new_noise_channel("BitFlip", ops, 2, 1);
}
struct PsiNoiseChannel psi_phase_flip_channel(double p)
{
- double sqrt_1_p = sqrt(1.0 - p);
- double sqrt_p = sqrt(p);
+ double sqrt_1_p = sqrt(1.0 - p);
+ double sqrt_p = sqrt(p);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0(I)",
- psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_p, 0.0))),
- psi_new_kraus_operator("K1(Z)",
- psi_matrix(2, 2, psi_new_complex(sqrt_p, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(-sqrt_p, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0(I)",
+ psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_p, 0.0))),
+ psi_new_kraus_operator("K1(Z)",
+ psi_matrix(2, 2, psi_new_complex(sqrt_p, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(-sqrt_p, 0.0))),
+ };
- return psi_new_noise_channel("PhaseFlip", ops, 2, 1);
+ return psi_new_noise_channel("PhaseFlip", ops, 2, 1);
}
struct PsiNoiseChannel psi_bit_phase_flip_channel(double p)
{
- double sqrt_1_p = sqrt(1.0 - p);
- double sqrt_p = sqrt(p);
+ double sqrt_1_p = sqrt(1.0 - p);
+ double sqrt_p = sqrt(p);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0(I)",
- psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_p, 0.0))),
- psi_new_kraus_operator("K1(Y)",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
- psi_new_complex(0.0, -sqrt_p),
- psi_new_complex(0.0, sqrt_p), psi_new_complex(0.0, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0(I)",
+ psi_matrix(2, 2, psi_new_complex(sqrt_1_p, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_p, 0.0))),
+ psi_new_kraus_operator("K1(Y)",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
+ psi_new_complex(0.0, -sqrt_p),
+ psi_new_complex(0.0, sqrt_p), psi_new_complex(0.0, 0.0))),
+ };
- return psi_new_noise_channel("BitPhaseFlip", ops, 2, 1);
+ return psi_new_noise_channel("BitPhaseFlip", ops, 2, 1);
}
struct PsiNoiseChannel psi_generalised_amplitude_damping_channel(double p, double gamma)
{
- double sqrt_p = sqrt(p);
- double sqrt_1_p = sqrt(1.0 - p);
- double sqrt_gamma = sqrt(gamma);
- double sqrt_1_gamma = sqrt(1.0 - gamma);
+ double sqrt_p = sqrt(p);
+ double sqrt_1_p = sqrt(1.0 - p);
+ double sqrt_gamma = sqrt(gamma);
+ double sqrt_1_gamma = sqrt(1.0 - gamma);
- struct PsiKrausOperator ops[] = {
- psi_new_kraus_operator("K0",
- psi_matrix(2, 2, psi_new_complex(sqrt_p, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_p * sqrt_1_gamma, 0.0))),
- psi_new_kraus_operator("K1",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_p * sqrt_gamma, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0))),
- psi_new_kraus_operator("K2",
- psi_matrix(2, 2, psi_new_complex(sqrt_1_p * sqrt_1_gamma, 0.0),
- psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_p, 0.0))),
- psi_new_kraus_operator(
- "K3",
- psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
- psi_new_complex(sqrt_1_p * sqrt_gamma, 0.0), psi_new_complex(0.0, 0.0))),
- };
+ struct PsiKrausOperator ops[] = {
+ psi_new_kraus_operator("K0",
+ psi_matrix(2, 2, psi_new_complex(sqrt_p, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_p * sqrt_1_gamma, 0.0))),
+ psi_new_kraus_operator("K1",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_p * sqrt_gamma, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0))),
+ psi_new_kraus_operator("K2",
+ psi_matrix(2, 2, psi_new_complex(sqrt_1_p * sqrt_1_gamma, 0.0),
+ psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_p, 0.0))),
+ psi_new_kraus_operator(
+ "K3",
+ psi_matrix(2, 2, psi_new_complex(0.0, 0.0), psi_new_complex(0.0, 0.0),
+ psi_new_complex(sqrt_1_p * sqrt_gamma, 0.0), psi_new_complex(0.0, 0.0))),
+ };
- return psi_new_noise_channel("GeneralisedAmplitudeDamping", ops, 4, 1);
+ return psi_new_noise_channel("GeneralisedAmplitudeDamping", ops, 4, 1);
}
struct PsiDensityMatrix psi_new_density_matrix(size_t num_qubits)
{
- size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex* data = calloc(dim * dim, sizeof(struct PsiComplex));
- assert(data != NULL);
- data[0] = psi_new_complex(1.0, 0.0);
+ size_t dim = (size_t)1 << num_qubits;
+ struct PsiComplex* data = calloc(dim * dim, sizeof(struct PsiComplex));
+ assert(data != NULL);
+ data[0] = psi_new_complex(1.0, 0.0);
- return (struct PsiDensityMatrix){
- data,
- dim,
- num_qubits,
- };
+ return (struct PsiDensityMatrix){
+ data,
+ dim,
+ num_qubits,
+ };
}
struct PsiDensityMatrix psi_new_density_matrix_from_state(const struct PsiComplex* state,
size_t len)
{
- size_t dim = len;
- size_t num_qubits = 0;
- while (((size_t)1 << num_qubits) < dim)
- num_qubits++;
+ size_t dim = len;
+ size_t num_qubits = 0;
+ while (((size_t)1 << num_qubits) < dim)
+ num_qubits++;
- struct PsiComplex* data = malloc(dim * dim * sizeof(struct PsiComplex));
- assert(data != NULL);
+ struct PsiComplex* data = malloc(dim * dim * sizeof(struct PsiComplex));
+ assert(data != NULL);
- for (size_t i = 0; i < dim; i++)
- for (size_t j = 0; j < dim; j++)
- data[i * dim + j] = psi_mul_complex(state[i], psi_conjugate_complex(state[j]));
+ for (size_t i = 0; i < dim; i++)
+ for (size_t j = 0; j < dim; j++)
+ data[i * dim + j] = psi_mul_complex(state[i], psi_conjugate_complex(state[j]));
- return (struct PsiDensityMatrix){
- data,
- dim,
- num_qubits,
- };
+ return (struct PsiDensityMatrix){
+ data,
+ dim,
+ num_qubits,
+ };
}
void psi_free_density_matrix(struct PsiDensityMatrix* dm)
{
- free(dm->data);
- dm->data = NULL;
- dm->dim = 0;
- dm->num_qubits = 0;
+ free(dm->data);
+ dm->data = NULL;
+ dm->dim = 0;
+ dm->num_qubits = 0;
}
struct PsiComplex psi_get_density_matrix(struct PsiDensityMatrix dm, size_t row, size_t col)
{
- assert(row < dm.dim && col < dm.dim);
- return dm.data[row * dm.dim + col];
+ assert(row < dm.dim && col < dm.dim);
+ return dm.data[row * dm.dim + col];
}
void psi_set_density_matrix(struct PsiDensityMatrix* dm, size_t row, size_t col,
struct PsiComplex value)
{
- assert(row < dm->dim && col < dm->dim);
- dm->data[row * dm->dim + col] = value;
+ assert(row < dm->dim && col < dm->dim);
+ dm->data[row * dm->dim + col] = value;
}
struct PsiComplex psi_trace_density_matrix(struct PsiDensityMatrix dm)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < dm.dim; i++)
- sum = psi_add_complex(sum, dm.data[i * dm.dim + i]);
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < dm.dim; i++)
+ sum = psi_add_complex(sum, dm.data[i * dm.dim + i]);
- return sum;
+ return sum;
}
double psi_purity_density_matrix(struct PsiDensityMatrix dm)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < dm.dim; i++)
- for (size_t j = 0; j < dm.dim; j++)
- sum = psi_add_complex(
- sum, psi_mul_complex(dm.data[i * dm.dim + j], dm.data[j * dm.dim + i]));
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < dm.dim; i++)
+ for (size_t j = 0; j < dm.dim; j++)
+ sum = psi_add_complex(
+ sum, psi_mul_complex(dm.data[i * dm.dim + j], dm.data[j * dm.dim + i]));
- return sum.real;
+ return sum.real;
}
bool psi_is_pure_density_matrix(struct PsiDensityMatrix dm, double tolerance)
{
- return fabs(psi_purity_density_matrix(dm) - 1.0) < tolerance;
+ return fabs(psi_purity_density_matrix(dm) - 1.0) < tolerance;
}
void psi_density_matrix_probabilities(struct PsiDensityMatrix dm, double* out)
{
- for (size_t i = 0; i < dm.dim; i++)
- out[i] = dm.data[i * dm.dim + i].real;
+ for (size_t i = 0; i < dm.dim; i++)
+ out[i] = dm.data[i * dm.dim + i].real;
}
void psi_apply_unitary_density_matrix(struct PsiDensityMatrix* dm, struct PsiMatrix gate,
const size_t* targets, size_t target_count)
{
- size_t g = target_count;
- size_t gate_dim = (size_t)1 << g;
- size_t dim = dm->dim;
+ size_t g = target_count;
+ size_t gate_dim = (size_t)1 << g;
+ size_t dim = dm->dim;
- size_t* target_bits = malloc(g * sizeof(size_t));
- assert(target_bits != NULL || g == 0);
- for (size_t t = 0; t < g; t++)
- target_bits[t] = dm->num_qubits - 1 - targets[t];
+ size_t* target_bits = malloc(g * sizeof(size_t));
+ assert(target_bits != NULL || g == 0);
+ for (size_t t = 0; t < g; t++)
+ target_bits[t] = dm->num_qubits - 1 - targets[t];
- size_t non_target_mask = dim - 1;
- for (size_t t = 0; t < g; t++)
- non_target_mask &= ~((size_t)1 << target_bits[t]);
+ size_t non_target_mask = dim - 1;
+ for (size_t t = 0; t < g; t++)
+ non_target_mask &= ~((size_t)1 << target_bits[t]);
- struct PsiComplex* new_data = calloc(dim * dim, sizeof(struct PsiComplex));
- assert(new_data != NULL);
+ struct PsiComplex* new_data = calloc(dim * dim, sizeof(struct PsiComplex));
+ assert(new_data != NULL);
- for (size_t i = 0; i < dim; i++)
- for (size_t j = 0; j < dim; j++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < dim; i++)
+ for (size_t j = 0; j < dim; j++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t k = 0; k < gate_dim; k++)
- for (size_t l = 0; l < gate_dim; l++)
- {
- size_t src_i = i & non_target_mask;
- size_t src_j = j & non_target_mask;
+ for (size_t k = 0; k < gate_dim; k++)
+ for (size_t l = 0; l < gate_dim; l++)
+ {
+ size_t src_i = i & non_target_mask;
+ size_t src_j = j & non_target_mask;
- for (size_t idx = 0; idx < g; idx++)
- {
- if ((k >> (g - 1 - idx)) & 1)
- src_i |= (size_t)1 << target_bits[idx];
- if ((l >> (g - 1 - idx)) & 1)
- src_j |= (size_t)1 << target_bits[idx];
- }
+ for (size_t idx = 0; idx < g; idx++)
+ {
+ if ((k >> (g - 1 - idx)) & 1)
+ src_i |= (size_t)1 << target_bits[idx];
+ if ((l >> (g - 1 - idx)) & 1)
+ src_j |= (size_t)1 << target_bits[idx];
+ }
- size_t tgt_i = 0;
- size_t tgt_j = 0;
- for (size_t idx = 0; idx < g; idx++)
- {
- if ((i >> target_bits[idx]) & 1)
- tgt_i |= (size_t)1 << (g - 1 - idx);
- if ((j >> target_bits[idx]) & 1)
- tgt_j |= (size_t)1 << (g - 1 - idx);
- }
+ size_t tgt_i = 0;
+ size_t tgt_j = 0;
+ for (size_t idx = 0; idx < g; idx++)
+ {
+ if ((i >> target_bits[idx]) & 1)
+ tgt_i |= (size_t)1 << (g - 1 - idx);
+ if ((j >> target_bits[idx]) & 1)
+ tgt_j |= (size_t)1 << (g - 1 - idx);
+ }
- struct PsiComplex u_ik = gate.data[tgt_i * gate_dim + k];
- struct PsiComplex u_jl_dag =
- psi_conjugate_complex(gate.data[tgt_j * gate_dim + l]);
- struct PsiComplex rho_kl = dm->data[src_i * dim + src_j];
+ struct PsiComplex u_ik = gate.data[tgt_i * gate_dim + k];
+ struct PsiComplex u_jl_dag =
+ psi_conjugate_complex(gate.data[tgt_j * gate_dim + l]);
+ struct PsiComplex rho_kl = dm->data[src_i * dim + src_j];
- sum = psi_add_complex(sum,
- psi_mul_complex(psi_mul_complex(u_ik, rho_kl), u_jl_dag));
- }
+ sum = psi_add_complex(sum,
+ psi_mul_complex(psi_mul_complex(u_ik, rho_kl), u_jl_dag));
+ }
- new_data[i * dim + j] = sum;
- }
+ new_data[i * dim + j] = sum;
+ }
- free(target_bits);
- free(dm->data);
- dm->data = new_data;
+ free(target_bits);
+ free(dm->data);
+ dm->data = new_data;
}
void psi_apply_noise_channel(struct PsiDensityMatrix* dm, struct PsiNoiseChannel channel,
size_t target)
{
- assert(channel.num_qubits == 1);
+ assert(channel.num_qubits == 1);
- size_t dim = dm->dim;
- size_t target_bit = dm->num_qubits - 1 - target;
+ size_t dim = dm->dim;
+ size_t target_bit = dm->num_qubits - 1 - target;
- struct PsiComplex* new_data = calloc(dim * dim, sizeof(struct PsiComplex));
- assert(new_data != NULL);
+ struct PsiComplex* new_data = calloc(dim * dim, sizeof(struct PsiComplex));
+ assert(new_data != NULL);
- for (size_t op = 0; op < channel.operator_count; op++)
- {
- struct PsiMatrix k = channel.operators[op].matrix;
+ for (size_t op = 0; op < channel.operator_count; op++)
+ {
+ struct PsiMatrix k = channel.operators[op].matrix;
- for (size_t i = 0; i < dim; i++)
- for (size_t j = 0; j < dim; j++)
- {
- size_t i_target = (i >> target_bit) & 1;
- size_t j_target = (j >> target_bit) & 1;
+ for (size_t i = 0; i < dim; i++)
+ for (size_t j = 0; j < dim; j++)
+ {
+ size_t i_target = (i >> target_bit) & 1;
+ size_t j_target = (j >> target_bit) & 1;
- for (size_t ki = 0; ki < 2; ki++)
- for (size_t kj = 0; kj < 2; kj++)
- {
- size_t src_i = (i & ~((size_t)1 << target_bit)) | (ki << target_bit);
- size_t src_j = (j & ~((size_t)1 << target_bit)) | (kj << target_bit);
+ for (size_t ki = 0; ki < 2; ki++)
+ for (size_t kj = 0; kj < 2; kj++)
+ {
+ size_t src_i = (i & ~((size_t)1 << target_bit)) | (ki << target_bit);
+ size_t src_j = (j & ~((size_t)1 << target_bit)) | (kj << target_bit);
- struct PsiComplex k_elem = k.data[i_target * 2 + ki];
- struct PsiComplex k_dag_elem =
- psi_conjugate_complex(k.data[j_target * 2 + kj]);
- struct PsiComplex rho_elem = dm->data[src_i * dim + src_j];
+ struct PsiComplex k_elem = k.data[i_target * 2 + ki];
+ struct PsiComplex k_dag_elem =
+ psi_conjugate_complex(k.data[j_target * 2 + kj]);
+ struct PsiComplex rho_elem = dm->data[src_i * dim + src_j];
- struct PsiComplex term =
- psi_mul_complex(psi_mul_complex(k_elem, rho_elem), k_dag_elem);
- new_data[i * dim + j] = psi_add_complex(new_data[i * dim + j], term);
- }
- }
- }
+ struct PsiComplex term =
+ psi_mul_complex(psi_mul_complex(k_elem, rho_elem), k_dag_elem);
+ new_data[i * dim + j] = psi_add_complex(new_data[i * dim + j], term);
+ }
+ }
+ }
- free(dm->data);
- dm->data = new_data;
+ free(dm->data);
+ dm->data = new_data;
}
double psi_measure_probability_density_matrix(struct PsiDensityMatrix dm, size_t qubit,
size_t outcome)
{
- size_t target_bit = dm.num_qubits - 1 - qubit;
- double prob = 0.0;
+ size_t target_bit = dm.num_qubits - 1 - qubit;
+ double prob = 0.0;
- for (size_t i = 0; i < dm.dim; i++)
- if (((i >> target_bit) & 1) == outcome)
- prob += dm.data[i * dm.dim + i].real;
+ for (size_t i = 0; i < dm.dim; i++)
+ if (((i >> target_bit) & 1) == outcome)
+ prob += dm.data[i * dm.dim + i].real;
- return prob;
+ return prob;
}
double psi_fidelity_density_matrix(struct PsiDensityMatrix dm, const struct PsiComplex* state)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < dm.dim; i++)
- for (size_t j = 0; j < dm.dim; j++)
- sum = psi_add_complex(sum,
- psi_mul_complex(psi_mul_complex(psi_conjugate_complex(state[i]),
- dm.data[i * dm.dim + j]),
- state[j]));
+ for (size_t i = 0; i < dm.dim; i++)
+ for (size_t j = 0; j < dm.dim; j++)
+ sum = psi_add_complex(sum,
+ psi_mul_complex(psi_mul_complex(psi_conjugate_complex(state[i]),
+ dm.data[i * dm.dim + j]),
+ state[j]));
- return sum.real;
+ return sum.real;
}
diff --git a/src/core/quantum_components.c b/src/core/quantum_components.c
index a62a911..5870906 100644
--- a/src/core/quantum_components.c
+++ b/src/core/quantum_components.c
@@ -6,262 +6,262 @@
struct PsiVector psi_new_state_0(void)
{
- return psi_column_vector(psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0));
+ return psi_column_vector(psi_new_complex(1.0, 0.0), psi_new_complex(0.0, 0.0));
}
struct PsiVector psi_new_state_1(void)
{
- return psi_column_vector(psi_new_complex(0.0, 0.0), psi_new_complex(1.0, 0.0));
+ return psi_column_vector(psi_new_complex(0.0, 0.0), psi_new_complex(1.0, 0.0));
}
struct PsiQuantumGate psi_new_quantum_gate(const char* name, struct PsiMatrix matrix,
size_t num_qubits)
{
- size_t expected_dim = (size_t)1 << num_qubits;
- assert(matrix.rows == expected_dim);
- assert(matrix.cols == expected_dim);
+ size_t expected_dim = (size_t)1 << num_qubits;
+ assert(matrix.rows == expected_dim);
+ assert(matrix.cols == expected_dim);
- return (struct PsiQuantumGate){
- name,
- matrix,
- num_qubits,
- };
+ return (struct PsiQuantumGate){
+ name,
+ matrix,
+ num_qubits,
+ };
}
struct PsiQuantumGate psi_new_quantum_gate_from_matrix(const char* name, struct PsiMatrix matrix)
{
- assert(matrix.rows == matrix.cols);
+ assert(matrix.rows == matrix.cols);
- size_t dim = matrix.rows;
- assert(dim > 0 && (dim & (dim - 1)) == 0);
+ size_t dim = matrix.rows;
+ assert(dim > 0 && (dim & (dim - 1)) == 0);
- size_t num_qubits = 0;
- while (((size_t)1 << num_qubits) < dim)
- num_qubits++;
+ size_t num_qubits = 0;
+ while (((size_t)1 << num_qubits) < dim)
+ num_qubits++;
- return (struct PsiQuantumGate){
- name,
- matrix,
- num_qubits,
- };
+ return (struct PsiQuantumGate){
+ name,
+ matrix,
+ num_qubits,
+ };
}
void psi_free_quantum_gate(struct PsiQuantumGate* gate)
{
- psi_free_matrix(&gate->matrix);
+ psi_free_matrix(&gate->matrix);
}
struct PsiQuantumBit psi_new_quantum_bit(const char* name, struct PsiVector state)
{
- return (struct PsiQuantumBit){
- name,
- state,
- };
+ return (struct PsiQuantumBit){
+ name,
+ state,
+ };
}
void psi_free_quantum_bit(struct PsiQuantumBit* bit)
{
- psi_free_vector(&bit->state);
+ psi_free_vector(&bit->state);
}
static void update_register(struct PsiQuantumRegister* reg)
{
- psi_free_vector(&reg->state_vector);
+ psi_free_vector(&reg->state_vector);
- if (reg->num_qubits == 0)
- {
- reg->state_vector = psi_new_vector(0, PSI_COLUMN_VECTOR);
- return;
- }
+ if (reg->num_qubits == 0)
+ {
+ reg->state_vector = psi_new_vector(0, PSI_COLUMN_VECTOR);
+ return;
+ }
- struct PsiMatrix result = psi_matrix_from_vector(reg->qubits[0].state);
- for (size_t i = 1; i < reg->num_qubits; i++)
- {
- struct PsiMatrix part = psi_matrix_from_vector(reg->qubits[i].state);
- struct PsiMatrix next = psi_kronecker_matrix(result, part);
- psi_free_matrix(&result);
- psi_free_matrix(&part);
- result = next;
- }
+ struct PsiMatrix result = psi_matrix_from_vector(reg->qubits[0].state);
+ for (size_t i = 1; i < reg->num_qubits; i++)
+ {
+ struct PsiMatrix part = psi_matrix_from_vector(reg->qubits[i].state);
+ struct PsiMatrix next = psi_kronecker_matrix(result, part);
+ psi_free_matrix(&result);
+ psi_free_matrix(&part);
+ result = next;
+ }
- reg->state_vector = psi_vector_from_matrix(result, PSI_COLUMN_VECTOR);
- psi_free_matrix(&result);
+ reg->state_vector = psi_vector_from_matrix(result, PSI_COLUMN_VECTOR);
+ psi_free_matrix(&result);
}
struct PsiQuantumRegister psi_new_quantum_register(const char* name, const char** names,
size_t count)
{
- struct PsiQuantumBit* qubits = malloc(count * sizeof(struct PsiQuantumBit));
- assert(qubits != NULL || count == 0);
+ struct PsiQuantumBit* qubits = malloc(count * sizeof(struct PsiQuantumBit));
+ assert(qubits != NULL || count == 0);
- for (size_t i = 0; i < count; i++)
- qubits[i] = psi_new_quantum_bit(names[i], psi_new_state_0());
+ for (size_t i = 0; i < count; i++)
+ qubits[i] = psi_new_quantum_bit(names[i], psi_new_state_0());
- struct PsiQuantumRegister reg = {
- name,
- psi_new_vector(0, PSI_COLUMN_VECTOR),
- qubits,
- count,
- };
+ struct PsiQuantumRegister reg = {
+ name,
+ psi_new_vector(0, PSI_COLUMN_VECTOR),
+ qubits,
+ count,
+ };
- update_register(&reg);
- return reg;
+ update_register(&reg);
+ return reg;
}
struct PsiQuantumRegister
psi_new_quantum_register_from(const char* name, const struct PsiQuantumBit* bits, size_t count)
{
- struct PsiQuantumBit* qubits = malloc(count * sizeof(struct PsiQuantumBit));
- assert(qubits != NULL || count == 0);
+ struct PsiQuantumBit* qubits = malloc(count * sizeof(struct PsiQuantumBit));
+ assert(qubits != NULL || count == 0);
- for (size_t i = 0; i < count; i++)
- qubits[i] = psi_new_quantum_bit(bits[i].name, psi_clone_vector(bits[i].state));
+ for (size_t i = 0; i < count; i++)
+ qubits[i] = psi_new_quantum_bit(bits[i].name, psi_clone_vector(bits[i].state));
- struct PsiQuantumRegister reg = {
- name,
- psi_new_vector(0, PSI_COLUMN_VECTOR),
- qubits,
- count,
- };
+ struct PsiQuantumRegister reg = {
+ name,
+ psi_new_vector(0, PSI_COLUMN_VECTOR),
+ qubits,
+ count,
+ };
- update_register(&reg);
- return reg;
+ update_register(&reg);
+ return reg;
}
void psi_free_quantum_register(struct PsiQuantumRegister* reg)
{
- for (size_t i = 0; i < reg->num_qubits; i++)
- psi_free_quantum_bit(&reg->qubits[i]);
+ for (size_t i = 0; i < reg->num_qubits; i++)
+ psi_free_quantum_bit(&reg->qubits[i]);
- free(reg->qubits);
- reg->qubits = NULL;
- reg->num_qubits = 0;
- psi_free_vector(&reg->state_vector);
+ free(reg->qubits);
+ reg->qubits = NULL;
+ reg->num_qubits = 0;
+ psi_free_vector(&reg->state_vector);
}
static bool targets_contain(const size_t* targets, size_t count, size_t value)
{
- for (size_t i = 0; i < count; i++)
- if (targets[i] == value)
- return true;
+ for (size_t i = 0; i < count; i++)
+ if (targets[i] == value)
+ return true;
- return false;
+ return false;
}
static struct PsiMatrix build_contiguous_operator(struct PsiQuantumRegister reg,
struct PsiQuantumGate gate, size_t start_idx)
{
- size_t n = reg.num_qubits;
- size_t g = gate.num_qubits;
+ size_t n = reg.num_qubits;
+ size_t g = gate.num_qubits;
- bool has_result = false;
- struct PsiMatrix result = { 0 };
+ bool has_result = false;
+ struct PsiMatrix result = { 0 };
- for (size_t i = 0; i < n; i++)
- {
- if (i > start_idx && i < start_idx + g)
- continue;
+ for (size_t i = 0; i < n; i++)
+ {
+ if (i > start_idx && i < start_idx + g)
+ continue;
- struct PsiMatrix part =
- i == start_idx ? psi_clone_matrix(gate.matrix) : psi_identity_matrix(2);
+ struct PsiMatrix part =
+ i == start_idx ? psi_clone_matrix(gate.matrix) : psi_identity_matrix(2);
- if (!has_result)
- {
- result = part;
- has_result = true;
- continue;
- }
+ if (!has_result)
+ {
+ result = part;
+ has_result = true;
+ continue;
+ }
- struct PsiMatrix next = psi_kronecker_matrix(result, part);
- psi_free_matrix(&result);
- psi_free_matrix(&part);
- result = next;
- }
+ struct PsiMatrix next = psi_kronecker_matrix(result, part);
+ psi_free_matrix(&result);
+ psi_free_matrix(&part);
+ result = next;
+ }
- if (!has_result)
- return psi_identity_matrix((size_t)1 << n);
+ if (!has_result)
+ return psi_identity_matrix((size_t)1 << n);
- return result;
+ return result;
}
static struct PsiMatrix build_full_operator(struct PsiQuantumRegister reg,
struct PsiQuantumGate gate, const size_t* targets,
size_t target_count)
{
- size_t n = reg.num_qubits;
- size_t g = gate.num_qubits;
- size_t dim = (size_t)1 << n;
+ size_t n = reg.num_qubits;
+ size_t g = gate.num_qubits;
+ size_t dim = (size_t)1 << n;
- bool contiguous = true;
- for (size_t i = 1; i < target_count; i++)
- if (targets[i] != targets[i - 1] + 1)
- {
- contiguous = false;
- break;
- }
+ bool contiguous = true;
+ for (size_t i = 1; i < target_count; i++)
+ if (targets[i] != targets[i - 1] + 1)
+ {
+ contiguous = false;
+ break;
+ }
- if (contiguous && g == n)
- return psi_clone_matrix(gate.matrix);
+ if (contiguous && g == n)
+ return psi_clone_matrix(gate.matrix);
- if (contiguous)
- return build_contiguous_operator(reg, gate, targets[0]);
+ if (contiguous)
+ return build_contiguous_operator(reg, gate, targets[0]);
- struct PsiMatrix result = psi_new_matrix(dim, dim);
+ struct PsiMatrix result = psi_new_matrix(dim, dim);
- for (size_t col = 0; col < dim; col++)
- for (size_t row = 0; row < dim; row++)
- {
- size_t target_row_bits = 0;
- size_t target_col_bits = 0;
+ for (size_t col = 0; col < dim; col++)
+ for (size_t row = 0; row < dim; row++)
+ {
+ size_t target_row_bits = 0;
+ size_t target_col_bits = 0;
- for (size_t i = 0; i < target_count; i++)
- {
- size_t qubit_pos = n - 1 - targets[i];
- if ((row >> qubit_pos) & 1)
- target_row_bits |= (size_t)1 << (g - 1 - i);
- if ((col >> qubit_pos) & 1)
- target_col_bits |= (size_t)1 << (g - 1 - i);
- }
+ for (size_t i = 0; i < target_count; i++)
+ {
+ size_t qubit_pos = n - 1 - targets[i];
+ if ((row >> qubit_pos) & 1)
+ target_row_bits |= (size_t)1 << (g - 1 - i);
+ if ((col >> qubit_pos) & 1)
+ target_col_bits |= (size_t)1 << (g - 1 - i);
+ }
- bool non_target_match = true;
- for (size_t q = 0; q < n; q++)
- {
- if (targets_contain(targets, target_count, q))
- continue;
+ bool non_target_match = true;
+ for (size_t q = 0; q < n; q++)
+ {
+ if (targets_contain(targets, target_count, q))
+ continue;
- size_t qubit_pos = n - 1 - q;
- if (((row >> qubit_pos) & 1) != ((col >> qubit_pos) & 1))
- {
- non_target_match = false;
- break;
- }
- }
+ size_t qubit_pos = n - 1 - q;
+ if (((row >> qubit_pos) & 1) != ((col >> qubit_pos) & 1))
+ {
+ non_target_match = false;
+ break;
+ }
+ }
- if (non_target_match)
- result.data[row * result.cols + col] =
- psi_get_matrix(gate.matrix, target_row_bits, target_col_bits);
- }
+ if (non_target_match)
+ result.data[row * result.cols + col] =
+ psi_get_matrix(gate.matrix, target_row_bits, target_col_bits);
+ }
- return result;
+ return result;
}
void psi_apply_gate(struct PsiQuantumRegister* reg, struct PsiQuantumGate gate,
const size_t* targets, size_t target_count)
{
- size_t n = reg->num_qubits;
+ size_t n = reg->num_qubits;
- assert(gate.num_qubits == target_count);
- for (size_t i = 0; i < target_count; i++)
- assert(targets[i] < n);
+ assert(gate.num_qubits == target_count);
+ for (size_t i = 0; i < target_count; i++)
+ assert(targets[i] < n);
- for (size_t i = 0; i < target_count; i++)
- for (size_t j = i + 1; j < target_count; j++)
- assert(targets[i] != targets[j]);
+ for (size_t i = 0; i < target_count; i++)
+ for (size_t j = i + 1; j < target_count; j++)
+ assert(targets[i] != targets[j]);
- struct PsiMatrix full_operator = build_full_operator(*reg, gate, targets, target_count);
- struct PsiVector new_state = psi_mul_vector_matrix(reg->state_vector, full_operator);
+ struct PsiMatrix full_operator = build_full_operator(*reg, gate, targets, target_count);
+ struct PsiVector new_state = psi_mul_vector_matrix(reg->state_vector, full_operator);
- psi_free_vector(&reg->state_vector);
- psi_free_matrix(&full_operator);
- reg->state_vector = new_state;
+ psi_free_vector(&reg->state_vector);
+ psi_free_matrix(&full_operator);
+ reg->state_vector = new_state;
}
diff --git a/src/core/runtime.c b/src/core/runtime.c
index 24cbe26..9c95214 100644
--- a/src/core/runtime.c
+++ b/src/core/runtime.c
@@ -8,304 +8,304 @@
struct PsiRuntimeConfig psi_new_runtime_config(void)
{
- struct PsiRuntimeConfig config;
- config.parallel = false;
- config.simd = false;
- config.batched = false;
- config.structure_aware = false;
- config.parallel_threshold = PSI_PARALLEL_THRESHOLD;
+ struct PsiRuntimeConfig config;
+ config.parallel = false;
+ config.simd = false;
+ config.batched = false;
+ config.structure_aware = false;
+ config.parallel_threshold = PSI_PARALLEL_THRESHOLD;
- return config;
+ return config;
}
struct PsiRuntimeConfig psi_optimal_runtime_config(void)
{
- struct PsiRuntimeConfig config = psi_new_runtime_config();
- config.structure_aware = true;
- config.simd = true;
- config.parallel = true;
+ struct PsiRuntimeConfig config = psi_new_runtime_config();
+ config.structure_aware = true;
+ config.simd = true;
+ config.parallel = true;
- return config;
+ return config;
}
struct PsiRuntimeConfig psi_runtime_to_config(enum PsiRuntime runtime)
{
- struct PsiRuntimeConfig config = psi_new_runtime_config();
+ struct PsiRuntimeConfig config = psi_new_runtime_config();
- switch (runtime)
- {
- case PSI_RUNTIME_BASIC: break;
- case PSI_RUNTIME_BASIC_MT: config.parallel = true; break;
- case PSI_RUNTIME_BATCHED: config.batched = true; break;
- case PSI_RUNTIME_BATCHED_MT:
- config.batched = true;
- config.parallel = true;
- break;
- case PSI_RUNTIME_SIMD:
- config.batched = true;
- config.simd = true;
- break;
- case PSI_RUNTIME_SIMD_MT:
- config.batched = true;
- config.simd = true;
- config.parallel = true;
- break;
- case PSI_RUNTIME_STRUCTURE_AWARE:
- config.structure_aware = true;
- config.simd = true;
- break;
- case PSI_RUNTIME_STRUCTURE_AWARE_MT:
- config.structure_aware = true;
- config.simd = true;
- config.parallel = true;
- break;
- }
+ switch (runtime)
+ {
+ case PSI_RUNTIME_BASIC: break;
+ case PSI_RUNTIME_BASIC_MT: config.parallel = true; break;
+ case PSI_RUNTIME_BATCHED: config.batched = true; break;
+ case PSI_RUNTIME_BATCHED_MT:
+ config.batched = true;
+ config.parallel = true;
+ break;
+ case PSI_RUNTIME_SIMD:
+ config.batched = true;
+ config.simd = true;
+ break;
+ case PSI_RUNTIME_SIMD_MT:
+ config.batched = true;
+ config.simd = true;
+ config.parallel = true;
+ break;
+ case PSI_RUNTIME_STRUCTURE_AWARE:
+ config.structure_aware = true;
+ config.simd = true;
+ break;
+ case PSI_RUNTIME_STRUCTURE_AWARE_MT:
+ config.structure_aware = true;
+ config.simd = true;
+ config.parallel = true;
+ break;
+ }
- return config;
+ return config;
}
static bool op_to_kernel(struct PsiGateOp op, struct PsiKernel* out)
{
- struct PsiMatrix matrix;
- const char* name;
+ struct PsiMatrix matrix;
+ const char* name;
- switch (op.kind)
- {
- case PSI_GATE_H:
- matrix = psi_hadamard_gate().matrix;
- name = "H";
- break;
- case PSI_GATE_X:
- matrix = psi_pauli_x_gate().matrix;
- name = "X";
- break;
- case PSI_GATE_Y:
- matrix = psi_pauli_y_gate().matrix;
- name = "Y";
- break;
- case PSI_GATE_Z:
- matrix = psi_pauli_z_gate().matrix;
- name = "Z";
- break;
- case PSI_GATE_S:
- matrix = psi_s_gate().matrix;
- name = "S";
- break;
- case PSI_GATE_T:
- matrix = psi_t_gate().matrix;
- name = "T";
- break;
- case PSI_GATE_SDG:
- matrix = psi_sdg_gate().matrix;
- name = "Sdg";
- break;
- case PSI_GATE_TDG:
- matrix = psi_tdg_gate().matrix;
- name = "Tdg";
- break;
- case PSI_GATE_SX:
- matrix = psi_sx_gate().matrix;
- name = "Sx";
- break;
- case PSI_GATE_SXDG:
- matrix = psi_sxdg_gate().matrix;
- name = "Sxdg";
- break;
- case PSI_GATE_RX:
- matrix = psi_rx_matrix(op.params[0]);
- name = "Rx";
- break;
- case PSI_GATE_RY:
- matrix = psi_ry_matrix(op.params[0]);
- name = "Ry";
- break;
- case PSI_GATE_RZ:
- matrix = psi_rz_matrix(op.params[0]);
- name = "Rz";
- break;
- case PSI_GATE_P:
- matrix = psi_p_matrix(op.params[0]);
- name = "P";
- break;
- case PSI_GATE_U1:
- matrix = psi_u1_matrix(op.params[0]);
- name = "U1";
- break;
- case PSI_GATE_U2:
- matrix = psi_u2_matrix(op.params[0], op.params[1]);
- name = "U2";
- break;
- case PSI_GATE_U3:
- matrix = psi_u3_matrix(op.params[0], op.params[1], op.params[2]);
- name = "U3";
- break;
- case PSI_GATE_CNOT:
- matrix = psi_cnot_gate().matrix;
- name = "CNOT";
- break;
- case PSI_GATE_CZ:
- matrix = psi_cz_gate().matrix;
- name = "CZ";
- break;
- case PSI_GATE_SWAP:
- matrix = psi_swap_gate().matrix;
- name = "SWAP";
- break;
- case PSI_GATE_CRX:
- matrix = psi_crx_matrix(op.params[0]);
- name = "CRx";
- break;
- case PSI_GATE_CRY:
- matrix = psi_cry_matrix(op.params[0]);
- name = "CRy";
- break;
- case PSI_GATE_CRZ:
- matrix = psi_crz_matrix(op.params[0]);
- name = "CRz";
- break;
- case PSI_GATE_CP:
- matrix = psi_cp_matrix(op.params[0]);
- name = "CP";
- break;
- case PSI_GATE_CCNOT:
- matrix = psi_toffoli_gate().matrix;
- name = "CCNOT";
- break;
- case PSI_GATE_CSWAP:
- matrix = psi_fredkin_gate().matrix;
- name = "CSWAP";
- break;
- case PSI_GATE_MEASURE: return false;
- case PSI_GATE_CUSTOM:
- matrix = psi_to_quantum_gate(*op.custom).matrix;
- name = "Custom";
- break;
- }
+ switch (op.kind)
+ {
+ case PSI_GATE_H:
+ matrix = psi_hadamard_gate().matrix;
+ name = "H";
+ break;
+ case PSI_GATE_X:
+ matrix = psi_pauli_x_gate().matrix;
+ name = "X";
+ break;
+ case PSI_GATE_Y:
+ matrix = psi_pauli_y_gate().matrix;
+ name = "Y";
+ break;
+ case PSI_GATE_Z:
+ matrix = psi_pauli_z_gate().matrix;
+ name = "Z";
+ break;
+ case PSI_GATE_S:
+ matrix = psi_s_gate().matrix;
+ name = "S";
+ break;
+ case PSI_GATE_T:
+ matrix = psi_t_gate().matrix;
+ name = "T";
+ break;
+ case PSI_GATE_SDG:
+ matrix = psi_sdg_gate().matrix;
+ name = "Sdg";
+ break;
+ case PSI_GATE_TDG:
+ matrix = psi_tdg_gate().matrix;
+ name = "Tdg";
+ break;
+ case PSI_GATE_SX:
+ matrix = psi_sx_gate().matrix;
+ name = "Sx";
+ break;
+ case PSI_GATE_SXDG:
+ matrix = psi_sxdg_gate().matrix;
+ name = "Sxdg";
+ break;
+ case PSI_GATE_RX:
+ matrix = psi_rx_matrix(op.params[0]);
+ name = "Rx";
+ break;
+ case PSI_GATE_RY:
+ matrix = psi_ry_matrix(op.params[0]);
+ name = "Ry";
+ break;
+ case PSI_GATE_RZ:
+ matrix = psi_rz_matrix(op.params[0]);
+ name = "Rz";
+ break;
+ case PSI_GATE_P:
+ matrix = psi_p_matrix(op.params[0]);
+ name = "P";
+ break;
+ case PSI_GATE_U1:
+ matrix = psi_u1_matrix(op.params[0]);
+ name = "U1";
+ break;
+ case PSI_GATE_U2:
+ matrix = psi_u2_matrix(op.params[0], op.params[1]);
+ name = "U2";
+ break;
+ case PSI_GATE_U3:
+ matrix = psi_u3_matrix(op.params[0], op.params[1], op.params[2]);
+ name = "U3";
+ break;
+ case PSI_GATE_CNOT:
+ matrix = psi_cnot_gate().matrix;
+ name = "CNOT";
+ break;
+ case PSI_GATE_CZ:
+ matrix = psi_cz_gate().matrix;
+ name = "CZ";
+ break;
+ case PSI_GATE_SWAP:
+ matrix = psi_swap_gate().matrix;
+ name = "SWAP";
+ break;
+ case PSI_GATE_CRX:
+ matrix = psi_crx_matrix(op.params[0]);
+ name = "CRx";
+ break;
+ case PSI_GATE_CRY:
+ matrix = psi_cry_matrix(op.params[0]);
+ name = "CRy";
+ break;
+ case PSI_GATE_CRZ:
+ matrix = psi_crz_matrix(op.params[0]);
+ name = "CRz";
+ break;
+ case PSI_GATE_CP:
+ matrix = psi_cp_matrix(op.params[0]);
+ name = "CP";
+ break;
+ case PSI_GATE_CCNOT:
+ matrix = psi_toffoli_gate().matrix;
+ name = "CCNOT";
+ break;
+ case PSI_GATE_CSWAP:
+ matrix = psi_fredkin_gate().matrix;
+ name = "CSWAP";
+ break;
+ case PSI_GATE_MEASURE: return false;
+ case PSI_GATE_CUSTOM:
+ matrix = psi_to_quantum_gate(*op.custom).matrix;
+ name = "Custom";
+ break;
+ }
- size_t target_count;
- const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count);
- *out = psi_new_kernel(name, matrix, targets, target_count);
+ size_t target_count;
+ const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count);
+ *out = psi_new_kernel(name, matrix, targets, target_count);
- return true;
+ return true;
}
static struct PsiVector new_zero_state(size_t num_qubits)
{
- size_t dim = (size_t)1 << num_qubits;
- struct PsiVector state = psi_new_vector(dim, PSI_COLUMN_VECTOR);
- state.data[0] = psi_new_complex(1.0, 0.0);
+ size_t dim = (size_t)1 << num_qubits;
+ struct PsiVector state = psi_new_vector(dim, PSI_COLUMN_VECTOR);
+ state.data[0] = psi_new_complex(1.0, 0.0);
- return state;
+ return state;
}
static void execute_kernels(struct PsiVector* state, const struct PsiKernel* kernels, size_t count,
size_t num_qubits, struct PsiRuntimeConfig config)
{
- bool use_parallel = config.parallel && num_qubits >= config.parallel_threshold;
+ bool use_parallel = config.parallel && num_qubits >= config.parallel_threshold;
- for (size_t i = 0; i < count; i++)
- {
- struct PsiKernel kernel = kernels[i];
+ for (size_t i = 0; i < count; i++)
+ {
+ struct PsiKernel kernel = kernels[i];
- if (config.simd && kernel.target_count == 1)
- {
- struct PsiComplex gate[2][2] = {
- { kernel.matrix.data[0], kernel.matrix.data[1] },
- { kernel.matrix.data[2], kernel.matrix.data[3] },
- };
+ if (config.simd && kernel.target_count == 1)
+ {
+ struct PsiComplex gate[2][2] = {
+ { kernel.matrix.data[0], kernel.matrix.data[1] },
+ { kernel.matrix.data[2], kernel.matrix.data[3] },
+ };
- if (use_parallel)
- psi_apply_single_qubit_gate_simd_parallel(state->data, gate, kernel.targets[0],
- num_qubits);
- else
- psi_apply_single_qubit_gate_simd(state->data, gate, kernel.targets[0], num_qubits);
- }
- else
- psi_apply_kernel(state, kernel, num_qubits);
- }
+ if (use_parallel)
+ psi_apply_single_qubit_gate_simd_parallel(state->data, gate, kernel.targets[0],
+ num_qubits);
+ else
+ psi_apply_single_qubit_gate_simd(state->data, gate, kernel.targets[0], num_qubits);
+ }
+ else
+ psi_apply_kernel(state, kernel, num_qubits);
+ }
}
struct PsiVector psi_compute_runtime_config(struct PsiRuntimeConfig config, size_t num_qubits,
const struct PsiGateOp* operations, size_t op_count)
{
- struct PsiVector state = new_zero_state(num_qubits);
+ struct PsiVector state = new_zero_state(num_qubits);
- if (config.structure_aware)
- {
- struct PsiStructureAwareBatch batch = psi_new_structure_aware_batch(num_qubits);
- for (size_t i = 0; i < op_count; i++)
- {
- struct PsiKernel kernel;
- if (op_to_kernel(operations[i], &kernel))
- psi_add_structure_aware_kernel(&batch, kernel);
- }
+ if (config.structure_aware)
+ {
+ struct PsiStructureAwareBatch batch = psi_new_structure_aware_batch(num_qubits);
+ for (size_t i = 0; i < op_count; i++)
+ {
+ struct PsiKernel kernel;
+ if (op_to_kernel(operations[i], &kernel))
+ psi_add_structure_aware_kernel(&batch, kernel);
+ }
- psi_optimize_structure_aware_batch(&batch);
- execute_kernels(&state, batch.kernels, batch.count, num_qubits, config);
- psi_free_structure_aware_batch(&batch);
+ psi_optimize_structure_aware_batch(&batch);
+ execute_kernels(&state, batch.kernels, batch.count, num_qubits, config);
+ psi_free_structure_aware_batch(&batch);
- return state;
- }
+ return state;
+ }
- struct PsiKernelBatch batch = psi_new_kernel_batch(num_qubits);
- for (size_t i = 0; i < op_count; i++)
- {
- struct PsiKernel kernel;
- if (op_to_kernel(operations[i], &kernel))
- psi_add_kernel(&batch, kernel);
- }
+ struct PsiKernelBatch batch = psi_new_kernel_batch(num_qubits);
+ for (size_t i = 0; i < op_count; i++)
+ {
+ struct PsiKernel kernel;
+ if (op_to_kernel(operations[i], &kernel))
+ psi_add_kernel(&batch, kernel);
+ }
- if (config.batched)
- psi_optimize_kernel_batch(&batch);
+ if (config.batched)
+ psi_optimize_kernel_batch(&batch);
- execute_kernels(&state, batch.kernels, batch.count, num_qubits, config);
- psi_free_kernel_batch(&batch);
+ execute_kernels(&state, batch.kernels, batch.count, num_qubits, config);
+ psi_free_kernel_batch(&batch);
- return state;
+ return state;
}
struct PsiVector psi_compute_runtime(enum PsiRuntime runtime, size_t num_qubits,
const struct PsiGateOp* operations, size_t op_count)
{
- return psi_compute_runtime_config(psi_runtime_to_config(runtime), num_qubits, operations,
- op_count);
+ return psi_compute_runtime_config(psi_runtime_to_config(runtime), num_qubits, operations,
+ op_count);
}
const struct PsiVector* psi_compute_circuit_with_config(struct PsiQuantumCircuit* circuit,
struct PsiRuntimeConfig config)
{
- if (!circuit->is_computed)
- {
- psi_free_vector(&circuit->computed_state);
- circuit->computed_state = psi_compute_runtime_config(
- config, circuit->num_qubits, circuit->operations, circuit->operation_count);
- circuit->is_computed = true;
- }
+ if (!circuit->is_computed)
+ {
+ psi_free_vector(&circuit->computed_state);
+ circuit->computed_state = psi_compute_runtime_config(
+ config, circuit->num_qubits, circuit->operations, circuit->operation_count);
+ circuit->is_computed = true;
+ }
- return &circuit->computed_state;
+ return &circuit->computed_state;
}
const struct PsiVector* psi_compute_circuit_with(struct PsiQuantumCircuit* circuit,
enum PsiRuntime runtime)
{
- return psi_compute_circuit_with_config(circuit, psi_runtime_to_config(runtime));
+ return psi_compute_circuit_with_config(circuit, psi_runtime_to_config(runtime));
}
const struct PsiVector* psi_compute_circuit(struct PsiQuantumCircuit* circuit)
{
- return psi_compute_circuit_with(circuit, PSI_RUNTIME_BASIC);
+ return psi_compute_circuit_with(circuit, PSI_RUNTIME_BASIC);
}
double psi_circuit_probability(struct PsiQuantumCircuit* circuit, size_t state_index)
{
- const struct PsiVector* state = psi_compute_circuit(circuit);
- return psi_norm2_complex(state->data[state_index]);
+ const struct PsiVector* state = psi_compute_circuit(circuit);
+ return psi_norm2_complex(state->data[state_index]);
}
void psi_circuit_probabilities(struct PsiQuantumCircuit* circuit, double* out)
{
- const struct PsiVector* state = psi_compute_circuit(circuit);
- size_t dim = (size_t)1 << circuit->num_qubits;
- for (size_t i = 0; i < dim; i++)
- out[i] = psi_norm2_complex(state->data[i]);
+ const struct PsiVector* state = psi_compute_circuit(circuit);
+ size_t dim = (size_t)1 << circuit->num_qubits;
+ for (size_t i = 0; i < dim; i++)
+ out[i] = psi_norm2_complex(state->data[i]);
}
diff --git a/src/maths/complex.c b/src/maths/complex.c
index 44e255f..419d0b0 100644
--- a/src/maths/complex.c
+++ b/src/maths/complex.c
@@ -4,126 +4,126 @@
struct PsiComplex psi_new_complex(double real, double imaginary)
{
- return (struct PsiComplex){
- real,
- imaginary,
- };
+ return (struct PsiComplex){
+ real,
+ imaginary,
+ };
}
struct PsiComplex psi_new_complex_from_real(double real)
{
- return (struct PsiComplex){
- real,
- 0.0,
- };
+ return (struct PsiComplex){
+ real,
+ 0.0,
+ };
}
struct PsiComplex psi_conjugate_complex(struct PsiComplex z)
{
- return (struct PsiComplex){
- z.real,
- -z.imaginary,
- };
+ return (struct PsiComplex){
+ z.real,
+ -z.imaginary,
+ };
}
struct PsiComplex psi_neg_complex(struct PsiComplex z)
{
- return (struct PsiComplex){
- -z.real,
- -z.imaginary,
- };
+ return (struct PsiComplex){
+ -z.real,
+ -z.imaginary,
+ };
}
double psi_phase_complex(struct PsiComplex z)
{
- return atan2(z.imaginary, z.real);
+ return atan2(z.imaginary, z.real);
}
double psi_norm2_complex(struct PsiComplex z)
{
- return z.real * z.real + z.imaginary * z.imaginary;
+ return z.real * z.real + z.imaginary * z.imaginary;
}
double psi_abs_complex(struct PsiComplex z)
{
- return sqrt(psi_norm2_complex(z));
+ return sqrt(psi_norm2_complex(z));
}
struct PsiComplex psi_sqrt_complex(struct PsiComplex z)
{
- double r = psi_abs_complex(z);
- double half_theta = psi_phase_complex(z) / 2.0;
- double sqrt_r = sqrt(r);
+ double r = psi_abs_complex(z);
+ double half_theta = psi_phase_complex(z) / 2.0;
+ double sqrt_r = sqrt(r);
- return (struct PsiComplex){
- sqrt_r * cos(half_theta),
- sqrt_r * sin(half_theta),
- };
+ return (struct PsiComplex){
+ sqrt_r * cos(half_theta),
+ sqrt_r * sin(half_theta),
+ };
}
struct PsiComplex psi_add_complex(struct PsiComplex a, struct PsiComplex b)
{
- return (struct PsiComplex){
- a.real + b.real,
- a.imaginary + b.imaginary,
- };
+ return (struct PsiComplex){
+ a.real + b.real,
+ a.imaginary + b.imaginary,
+ };
}
struct PsiComplex psi_sub_complex(struct PsiComplex a, struct PsiComplex b)
{
- return (struct PsiComplex){
- a.real - b.real,
- a.imaginary - b.imaginary,
- };
+ return (struct PsiComplex){
+ a.real - b.real,
+ a.imaginary - b.imaginary,
+ };
}
struct PsiComplex psi_mul_complex(struct PsiComplex a, struct PsiComplex b)
{
- // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
- return (struct PsiComplex){
- a.real * b.real - a.imaginary * b.imaginary,
- a.real * b.imaginary + a.imaginary * b.real,
- };
+ // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
+ return (struct PsiComplex){
+ a.real * b.real - a.imaginary * b.imaginary,
+ a.real * b.imaginary + a.imaginary * b.real,
+ };
}
struct PsiComplex psi_div_complex(struct PsiComplex a, struct PsiComplex b)
{
- // (a + bi) / (c + di) = ((ac + bd) + (bc - ad)i) / (c² + d²)
- double denom = b.real * b.real + b.imaginary * b.imaginary;
- return (struct PsiComplex){
- (a.real * b.real + a.imaginary * b.imaginary) / denom,
- (a.imaginary * b.real - a.real * b.imaginary) / denom,
- };
+ // (a + bi) / (c + di) = ((ac + bd) + (bc - ad)i) / (c² + d²)
+ double denom = b.real * b.real + b.imaginary * b.imaginary;
+ return (struct PsiComplex){
+ (a.real * b.real + a.imaginary * b.imaginary) / denom,
+ (a.imaginary * b.real - a.real * b.imaginary) / denom,
+ };
}
struct PsiComplex psi_add_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real + b,
- a.imaginary,
- };
+ return (struct PsiComplex){
+ a.real + b,
+ a.imaginary,
+ };
}
struct PsiComplex psi_sub_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real - b,
- a.imaginary,
- };
+ return (struct PsiComplex){
+ a.real - b,
+ a.imaginary,
+ };
}
struct PsiComplex psi_mul_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real * b,
- a.imaginary * b,
- };
+ return (struct PsiComplex){
+ a.real * b,
+ a.imaginary * b,
+ };
}
struct PsiComplex psi_div_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real / b,
- a.imaginary / b,
- };
+ return (struct PsiComplex){
+ a.real / b,
+ a.imaginary / b,
+ };
}
diff --git a/src/maths/format.c b/src/maths/format.c
index f3db83d..52b2b5a 100644
--- a/src/maths/format.c
+++ b/src/maths/format.c
@@ -12,136 +12,189 @@ static const double INV_SQRT_32 = 0.1767766952966369;
static bool approx_eq(double a, double b)
{
- return fabs(a - b) < EPSILON;
+ return fabs(a - b) < EPSILON;
}
static bool real_symbolic(double v, char* out, size_t cap)
{
- double abs_v = fabs(v);
- const char* sign = v < 0.0 ? "-" : "";
+ double abs_v = fabs(v);
+ const char* sign = v < 0.0 ? "-" : "";
- if (approx_eq(abs_v, 0.0))
- {
- snprintf(out, cap, "%s", "0");
- return true;
- }
+ if (approx_eq(abs_v, 0.0))
+ {
+ snprintf(out, cap, "%s", "0");
+ return true;
+ }
- const char* sym = NULL;
- if (approx_eq(abs_v, 1.0))
- sym = "1";
- else if (approx_eq(abs_v, 0.5))
- sym = "½";
- else if (approx_eq(abs_v, 0.25))
- sym = "¼";
- else if (approx_eq(abs_v, 0.75))
- sym = "¾";
- else if (approx_eq(abs_v, 0.125))
- sym = "⅛";
- else if (approx_eq(abs_v, SQRT_2))
- sym = "√2";
- else if (approx_eq(abs_v, INV_SQRT_2))
- sym = "¹⁄√2";
- else if (approx_eq(abs_v, INV_SQRT_8))
- sym = "¹⁄√8";
- else if (approx_eq(abs_v, INV_SQRT_32))
- sym = "¹⁄√32";
- else if (approx_eq(abs_v, 2.0))
- sym = "2";
- else if (approx_eq(abs_v, 1.0 / 3.0))
- sym = "⅓";
- else if (approx_eq(abs_v, 2.0 / 3.0))
- sym = "⅔";
- else
- return false;
+ const char* sym = NULL;
+ if (approx_eq(abs_v, 1.0))
+ sym = "1";
+ else if (approx_eq(abs_v, 0.5))
+ sym = "½";
+ else if (approx_eq(abs_v, 0.25))
+ sym = "¼";
+ else if (approx_eq(abs_v, 0.75))
+ sym = "¾";
+ else if (approx_eq(abs_v, 0.125))
+ sym = "⅛";
+ else if (approx_eq(abs_v, SQRT_2))
+ sym = "√2";
+ else if (approx_eq(abs_v, INV_SQRT_2))
+ sym = "¹⁄√2";
+ else if (approx_eq(abs_v, INV_SQRT_8))
+ sym = "¹⁄√8";
+ else if (approx_eq(abs_v, INV_SQRT_32))
+ sym = "¹⁄√32";
+ else if (approx_eq(abs_v, 2.0))
+ sym = "2";
+ else if (approx_eq(abs_v, 1.0 / 3.0))
+ sym = "⅓";
+ else if (approx_eq(abs_v, 2.0 / 3.0))
+ sym = "⅔";
+ else
+ return false;
- snprintf(out, cap, "%s%s", sign, sym);
- return true;
+ snprintf(out, cap, "%s%s", sign, sym);
+ return true;
}
char* psi_format_amplitude(struct PsiComplex c, char* out, size_t cap)
{
- double re = c.real;
- double im = c.imaginary;
+ double re = c.real;
+ double im = c.imaginary;
- bool re_zero = approx_eq(fabs(re), 0.0);
- bool im_zero = approx_eq(fabs(im), 0.0);
+ bool re_zero = approx_eq(fabs(re), 0.0);
+ bool im_zero = approx_eq(fabs(im), 0.0);
- if (re_zero && im_zero)
- {
- snprintf(out, cap, "%s", "0");
- return out;
- }
+ if (re_zero && im_zero)
+ {
+ snprintf(out, cap, "%s", "0");
+ return out;
+ }
- if (im_zero)
- {
- if (!real_symbolic(re, out, cap))
- snprintf(out, cap, "%.4f", re);
+ if (im_zero)
+ {
+ if (!real_symbolic(re, out, cap))
+ snprintf(out, cap, "%.4f", re);
- return out;
- }
+ return out;
+ }
- if (re_zero)
- {
- if (approx_eq(fabs(im), 1.0))
- {
- snprintf(out, cap, "%s", im > 0.0 ? "i" : "-i");
- return out;
- }
+ if (re_zero)
+ {
+ if (approx_eq(fabs(im), 1.0))
+ {
+ snprintf(out, cap, "%s", im > 0.0 ? "i" : "-i");
+ return out;
+ }
- char sym[32];
- if (real_symbolic(im, sym, sizeof sym))
- snprintf(out, cap, "%si", sym);
- else
- snprintf(out, cap, "%.4fi", im);
+ char sym[32];
+ if (real_symbolic(im, sym, sizeof sym))
+ snprintf(out, cap, "%si", sym);
+ else
+ snprintf(out, cap, "%.4fi", im);
- return out;
- }
+ return out;
+ }
- char re_str[32];
- if (!real_symbolic(re, re_str, sizeof re_str))
- snprintf(re_str, sizeof re_str, "%.4f", re);
+ char re_str[32];
+ if (!real_symbolic(re, re_str, sizeof re_str))
+ snprintf(re_str, sizeof re_str, "%.4f", re);
- char im_str[32];
- if (approx_eq(fabs(im), 1.0))
- {
- snprintf(im_str, sizeof im_str, "%s", im > 0.0 ? "+i" : "-i");
- }
- else
- {
- const char* sign = im > 0.0 ? "+" : "-";
- char sym[32];
- if (real_symbolic(fabs(im), sym, sizeof sym))
- snprintf(im_str, sizeof im_str, "%s%si", sign, sym);
- else
- snprintf(im_str, sizeof im_str, "%s%.4fi", sign, fabs(im));
- }
+ char im_str[32];
+ if (approx_eq(fabs(im), 1.0))
+ {
+ snprintf(im_str, sizeof im_str, "%s", im > 0.0 ? "+i" : "-i");
+ }
+ else
+ {
+ const char* sign = im > 0.0 ? "+" : "-";
+ char sym[32];
+ if (real_symbolic(fabs(im), sym, sizeof sym))
+ snprintf(im_str, sizeof im_str, "%s%si", sign, sym);
+ else
+ snprintf(im_str, sizeof im_str, "%s%.4fi", sign, fabs(im));
+ }
- snprintf(out, cap, "%s%s", re_str, im_str);
- return out;
+ snprintf(out, cap, "%s%s", re_str, im_str);
+ return out;
}
char* psi_format_probability(double p, char* out, size_t cap)
{
- if (approx_eq(p, 0.0))
- snprintf(out, cap, "%s", "0");
- else if (approx_eq(p, 1.0))
- snprintf(out, cap, "%s", "1");
- else if (approx_eq(p, 0.5))
- snprintf(out, cap, "%s", "½");
- else if (approx_eq(p, 0.25))
- snprintf(out, cap, "%s", "¼");
- else if (approx_eq(p, 0.75))
- snprintf(out, cap, "%s", "¾");
- else if (approx_eq(p, 0.125))
- snprintf(out, cap, "%s", "⅛");
- else if (approx_eq(p, 0.0625))
- snprintf(out, cap, "%s", "¹⁄₁₆");
- else if (approx_eq(p, 1.0 / 3.0))
- snprintf(out, cap, "%s", "⅓");
- else if (approx_eq(p, 2.0 / 3.0))
- snprintf(out, cap, "%s", "⅔");
- else
- snprintf(out, cap, "%.4f", p);
+ if (approx_eq(p, 0.0))
+ snprintf(out, cap, "%s", "0");
+ else if (approx_eq(p, 1.0))
+ snprintf(out, cap, "%s", "1");
+ else if (approx_eq(p, 0.5))
+ snprintf(out, cap, "%s", "½");
+ else if (approx_eq(p, 0.25))
+ snprintf(out, cap, "%s", "¼");
+ else if (approx_eq(p, 0.75))
+ snprintf(out, cap, "%s", "¾");
+ else if (approx_eq(p, 0.125))
+ snprintf(out, cap, "%s", "⅛");
+ else if (approx_eq(p, 0.0625))
+ snprintf(out, cap, "%s", "¹⁄₁₆");
+ else if (approx_eq(p, 1.0 / 3.0))
+ snprintf(out, cap, "%s", "⅓");
+ else if (approx_eq(p, 2.0 / 3.0))
+ snprintf(out, cap, "%s", "⅔");
+ else
+ snprintf(out, cap, "%.4f", p);
- return out;
+ return out;
+}
+
+void psi_print_matrix(struct PsiMatrix m, FILE* out)
+{
+ int re_width = 0;
+ int im_width = 0;
+ for (size_t k = 0; k < m.rows * m.cols; k++)
+ {
+ int rl = snprintf(NULL, 0, "%.2f", m.data[k].real);
+ int il = snprintf(NULL, 0, "%.2f", fabs(m.data[k].imaginary));
+ if (rl > re_width)
+ re_width = rl;
+ if (il > im_width)
+ im_width = il;
+ }
+
+ for (size_t i = 0; i < m.rows; i++)
+ {
+ fputs(i == 0 ? "┌" : (i == m.rows - 1 ? "└" : "│"), out);
+
+ for (size_t j = 0; j < m.cols; j++)
+ {
+ struct PsiComplex e = m.data[i * m.cols + j];
+ const char* sign = e.imaginary > 0.0 ? "+" : "-";
+ fprintf(out, "%*.2f %s %*.2fi", re_width, e.real, sign, im_width, fabs(e.imaginary));
+ if (j != m.cols - 1)
+ fputs(", ", out);
+ }
+
+ fputs(i == 0 ? "┐" : (i == m.rows - 1 ? "┘" : "│"), out);
+ if (i != m.rows - 1)
+ fputc('\n', out);
+ }
+}
+
+void psi_print_vector(struct PsiVector v, FILE* out)
+{
+ if (v.kind == PSI_COLUMN_VECTOR)
+ {
+ struct PsiMatrix m = psi_matrix_from_vector(v);
+ psi_print_matrix(m, out);
+ psi_free_matrix(&m);
+ return;
+ }
+
+ fputc('[', out);
+ for (size_t i = 0; i < v.size; i++)
+ {
+ fprintf(out, "%g + %gi", v.data[i].real, v.data[i].imaginary);
+ if (i != v.size - 1)
+ fputs(", ", out);
+ }
+ fputc(']', out);
}
diff --git a/src/maths/matrix.c b/src/maths/matrix.c
index 2415395..8b41065 100644
--- a/src/maths/matrix.c
+++ b/src/maths/matrix.c
@@ -6,181 +6,181 @@
struct PsiMatrix psi_new_matrix(size_t rows, size_t cols)
{
- struct PsiComplex* data = calloc(rows * cols, sizeof(struct PsiComplex));
- assert(data != NULL || rows * cols == 0);
+ struct PsiComplex* data = calloc(rows * cols, sizeof(struct PsiComplex));
+ assert(data != NULL || rows * cols == 0);
- return (struct PsiMatrix){
- data,
- rows,
- cols,
- };
+ return (struct PsiMatrix){
+ data,
+ rows,
+ cols,
+ };
}
struct PsiMatrix psi_new_matrix_from(const struct PsiComplex* data, size_t rows, size_t cols)
{
- struct PsiMatrix m = psi_new_matrix(rows, cols);
- memcpy(m.data, data, rows * cols * sizeof(struct PsiComplex));
+ struct PsiMatrix m = psi_new_matrix(rows, cols);
+ memcpy(m.data, data, rows * cols * sizeof(struct PsiComplex));
- return m;
+ return m;
}
struct PsiMatrix psi_clone_matrix(struct PsiMatrix m)
{
- return psi_new_matrix_from(m.data, m.rows, m.cols);
+ return psi_new_matrix_from(m.data, m.rows, m.cols);
}
struct PsiMatrix psi_identity_matrix(size_t size)
{
- struct PsiMatrix m = psi_new_matrix(size, size);
- for (size_t i = 0; i < size; i++)
- m.data[i * size + i] = psi_new_complex(1.0, 0.0);
+ struct PsiMatrix m = psi_new_matrix(size, size);
+ for (size_t i = 0; i < size; i++)
+ m.data[i * size + i] = psi_new_complex(1.0, 0.0);
- return m;
+ return m;
}
void psi_free_matrix(struct PsiMatrix* m)
{
- free(m->data);
- m->data = NULL;
- m->rows = 0;
- m->cols = 0;
+ free(m->data);
+ m->data = NULL;
+ m->rows = 0;
+ m->cols = 0;
}
struct PsiComplex psi_get_matrix(struct PsiMatrix m, size_t row, size_t col)
{
- assert(row < m.rows && col < m.cols);
- return m.data[row * m.cols + col];
+ assert(row < m.rows && col < m.cols);
+ return m.data[row * m.cols + col];
}
void psi_set_matrix(struct PsiMatrix* m, size_t row, size_t col, struct PsiComplex value)
{
- assert(row < m->rows && col < m->cols);
- m->data[row * m->cols + col] = value;
+ assert(row < m->rows && col < m->cols);
+ m->data[row * m->cols + col] = value;
}
struct PsiMatrix psi_dot_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- assert(a.cols == b.rows);
+ assert(a.cols == b.rows);
- struct PsiMatrix result = psi_new_matrix(a.rows, b.cols);
- for (size_t i = 0; i < a.rows; i++)
- for (size_t j = 0; j < b.cols; j++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t k = 0; k < a.cols; k++)
- sum = psi_add_complex(
- sum, psi_mul_complex(a.data[i * a.cols + k], b.data[k * b.cols + j]));
+ struct PsiMatrix result = psi_new_matrix(a.rows, b.cols);
+ for (size_t i = 0; i < a.rows; i++)
+ for (size_t j = 0; j < b.cols; j++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t k = 0; k < a.cols; k++)
+ sum = psi_add_complex(
+ sum, psi_mul_complex(a.data[i * a.cols + k], b.data[k * b.cols + j]));
- result.data[i * result.cols + j] = sum;
- }
+ result.data[i * result.cols + j] = sum;
+ }
- return result;
+ return result;
}
struct PsiMatrix psi_kronecker_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- struct PsiMatrix result = psi_new_matrix(a.rows * b.rows, a.cols * b.cols);
- for (size_t i = 0; i < a.rows; i++)
- for (size_t j = 0; j < a.cols; j++)
- {
- struct PsiComplex a_val = a.data[i * a.cols + j];
- for (size_t k = 0; k < b.rows; k++)
- for (size_t l = 0; l < b.cols; l++)
- {
- size_t row = i * b.rows + k;
- size_t col = j * b.cols + l;
- result.data[row * result.cols + col] =
- psi_mul_complex(a_val, b.data[k * b.cols + l]);
- }
- }
+ struct PsiMatrix result = psi_new_matrix(a.rows * b.rows, a.cols * b.cols);
+ for (size_t i = 0; i < a.rows; i++)
+ for (size_t j = 0; j < a.cols; j++)
+ {
+ struct PsiComplex a_val = a.data[i * a.cols + j];
+ for (size_t k = 0; k < b.rows; k++)
+ for (size_t l = 0; l < b.cols; l++)
+ {
+ size_t row = i * b.rows + k;
+ size_t col = j * b.cols + l;
+ result.data[row * result.cols + col] =
+ psi_mul_complex(a_val, b.data[k * b.cols + l]);
+ }
+ }
- return result;
+ return result;
}
struct PsiMatrix psi_transpose_matrix(struct PsiMatrix m)
{
- struct PsiMatrix result = psi_new_matrix(m.cols, m.rows);
- for (size_t i = 0; i < m.rows; i++)
- for (size_t j = 0; j < m.cols; j++)
- result.data[j * result.cols + i] = m.data[i * m.cols + j];
+ struct PsiMatrix result = psi_new_matrix(m.cols, m.rows);
+ for (size_t i = 0; i < m.rows; i++)
+ for (size_t j = 0; j < m.cols; j++)
+ result.data[j * result.cols + i] = m.data[i * m.cols + j];
- return result;
+ return result;
}
struct PsiMatrix psi_add_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- assert(a.rows == b.rows && a.cols == b.cols);
+ assert(a.rows == b.rows && a.cols == b.cols);
- struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
- for (size_t i = 0; i < a.rows * a.cols; i++)
- result.data[i] = psi_add_complex(a.data[i], b.data[i]);
+ struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
+ for (size_t i = 0; i < a.rows * a.cols; i++)
+ result.data[i] = psi_add_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiMatrix psi_sub_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- assert(a.rows == b.rows && a.cols == b.cols);
+ assert(a.rows == b.rows && a.cols == b.cols);
- struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
- for (size_t i = 0; i < a.rows * a.cols; i++)
- result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
+ struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
+ for (size_t i = 0; i < a.rows * a.cols; i++)
+ result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiMatrix psi_scale_matrix(struct PsiMatrix m, struct PsiComplex scalar)
{
- struct PsiMatrix result = psi_new_matrix(m.rows, m.cols);
- for (size_t i = 0; i < m.rows * m.cols; i++)
- result.data[i] = psi_mul_complex(m.data[i], scalar);
+ struct PsiMatrix result = psi_new_matrix(m.rows, m.cols);
+ for (size_t i = 0; i < m.rows * m.cols; i++)
+ result.data[i] = psi_mul_complex(m.data[i], scalar);
- return result;
+ return result;
}
struct PsiMatrix psi_matrix_from_vector(struct PsiVector v)
{
- if (v.kind == PSI_ROW_VECTOR)
- return psi_new_matrix_from(v.data, 1, v.size);
+ if (v.kind == PSI_ROW_VECTOR)
+ return psi_new_matrix_from(v.data, 1, v.size);
- return psi_new_matrix_from(v.data, v.size, 1);
+ return psi_new_matrix_from(v.data, v.size, 1);
}
struct PsiVector psi_vector_from_matrix(struct PsiMatrix m, enum PsiVectorKind kind)
{
- return psi_new_vector_from(m.data, m.rows * m.cols, kind);
+ return psi_new_vector_from(m.data, m.rows * m.cols, kind);
}
struct PsiVector psi_mul_vector_matrix(struct PsiVector v, struct PsiMatrix m)
{
- if (v.kind == PSI_COLUMN_VECTOR)
- {
- assert(m.cols == v.size);
+ if (v.kind == PSI_COLUMN_VECTOR)
+ {
+ assert(m.cols == v.size);
- struct PsiVector result = psi_new_vector(m.rows, PSI_COLUMN_VECTOR);
- for (size_t i = 0; i < m.rows; i++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t j = 0; j < m.cols; j++)
- sum = psi_add_complex(sum, psi_mul_complex(m.data[i * m.cols + j], v.data[j]));
+ struct PsiVector result = psi_new_vector(m.rows, PSI_COLUMN_VECTOR);
+ for (size_t i = 0; i < m.rows; i++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t j = 0; j < m.cols; j++)
+ sum = psi_add_complex(sum, psi_mul_complex(m.data[i * m.cols + j], v.data[j]));
- result.data[i] = sum;
- }
+ result.data[i] = sum;
+ }
- return result;
- }
+ return result;
+ }
- assert(v.size == m.rows);
+ assert(v.size == m.rows);
- struct PsiVector result = psi_new_vector(m.cols, PSI_ROW_VECTOR);
- for (size_t j = 0; j < m.cols; j++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < m.rows; i++)
- sum = psi_add_complex(sum, psi_mul_complex(v.data[i], m.data[i * m.cols + j]));
+ struct PsiVector result = psi_new_vector(m.cols, PSI_ROW_VECTOR);
+ for (size_t j = 0; j < m.cols; j++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < m.rows; i++)
+ sum = psi_add_complex(sum, psi_mul_complex(v.data[i], m.data[i * m.cols + j]));
- result.data[j] = sum;
- }
+ result.data[j] = sum;
+ }
- return result;
+ return result;
}
diff --git a/src/maths/matrix.rs b/src/maths/matrix.rs
deleted file mode 100644
index c9d96a4..0000000
--- a/src/maths/matrix.rs
+++ /dev/null
@@ -1,310 +0,0 @@
-use super::Float;
-use core::{fmt, ops};
-
-#[macro_export]
-macro_rules! matrix {
- ( $( $( $x:expr ),* );* ) => {{
- let mut data = Vec::new();
- let mut rows = 0;
- let mut cols = 0;
-
- $(
- let row_data = $( $x )*;
- if cols == 0 {
- cols = row_data.len();
- }
- assert_eq!(cols, row_data.len(), "All rows must have the same number of columns.");
- data.extend(row_data);
- rows += 1;
- )*
-
- $crate::Matrix::new(rows, cols, data)
- }};
-}
-
-macro_rules! impl_matrix_ops {
- ($($trait:ident, $method:ident, $other:ty, $output:ty, $scale_fn:ident),* $(,)?) => {
- $(
- impl<T: Float> core::ops::$trait<$other> for Matrix<T> {
- type Output = $output;
-
- fn $method(self, other: $other) -> Self::Output {
- self.$scale_fn(other)
- }
- }
- )*
- };
- ($($trait:ident, $method:ident, $other:ty, $scale_fn:ident),* $(,)?) => {
- $(
- impl<T: Float> core::ops::$trait<$other> for Matrix<T> {
- fn $method(&mut self, other: $other) {
- *self = self.$scale_fn(other);
- }
- }
- )*
- };
-}
-
-#[derive(Clone)]
-pub struct Matrix<T: Float> {
- pub data: Vec<T>,
- pub rows: usize,
- pub cols: usize,
-}
-
-impl<T: Float> Matrix<T> {
- pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Self {
- Matrix { data, rows, cols }
- }
-
- pub fn get(&self, row: usize, col: usize) -> T {
- self.data[row * self.cols + col]
- }
-
- pub fn set(&mut self, row: usize, col: usize, value: T) {
- self.data[row * self.cols + col] = value;
- }
-
- pub fn dot(&self, other: &Self) -> Option<Matrix<T>> {
- if self.cols != other.rows {
- return None;
- }
-
- let mut result = Matrix::new(
- self.rows,
- other.cols,
- vec![T::zero(); self.rows * other.cols],
- );
- for i in 0..self.rows {
- for j in 0..other.cols {
- let mut sum = T::zero();
- for k in 0..self.cols {
- sum += self.get(i, k) * other.get(k, j) ;
- }
- result.set(i, j, sum);
- }
- }
- Some(result)
- }
-
- pub fn kronecker(&self, other: &Self) -> Matrix<T> {
- let new_rows = self.rows * other.rows;
- let new_cols = self.cols * other.cols;
-
- let mut result = Matrix::new(new_rows, new_cols, vec![T::zero(); new_rows * new_cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let self_val = self.get(i, j);
- for k in 0..other.rows {
- for l in 0..other.cols {
- let result_row = i * other.rows + k;
- let result_col = j * other.cols + l;
- result.set(result_row, result_col, self_val * other.get(k, l));
- }
- }
- }
- }
-
- result
- }
-
- pub fn transpose(&self) -> Matrix<T> {
- let mut result = Matrix::new(self.cols, self.rows, vec![T::zero(); self.cols * self.rows]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let value = self.get(i, j);
- result.set(j, i, value);
- }
- }
-
- result
- }
-
- pub fn add_to(&self, other: &Self) -> Option<Matrix<T>> {
- if self.rows != other.rows || self.cols != other.cols {
- return None;
- }
-
- let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let sum = self.get(i, j) + other.get(i, j);
- result.set(i, j, sum);
- }
- }
- Some(result)
- }
-
- pub fn subtract(&self, other: &Self) -> Option<Matrix<T>> {
- if self.rows != other.rows || self.cols != other.cols {
- return None;
- }
-
- let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let diff = self.get(i, j) - other.get(i, j);
- result.set(i, j, diff);
- }
- }
- Some(result)
- }
-
- pub fn scale(&self, scalar: T) -> Matrix<T> {
- let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let scaled_value = self.get(i, j) * scalar;
- result.set(i, j, scaled_value);
- }
- }
- result
- }
-}
-
-impl<T: Float> ops::Index<(usize, usize)> for Matrix<T> {
- type Output = T;
-
- fn index(&self, index: (usize, usize)) -> &Self::Output {
- &self.data[index.0 * self.cols + index.1]
- }
-}
-
-impl<T: Float> ops::IndexMut<(usize, usize)> for Matrix<T> {
- fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
- &mut self.data[index.0 * self.cols + index.1]
- }
-}
-
-impl<T: Float> ops::AddAssign<&Matrix<T>> for Matrix<T> {
- fn add_assign(&mut self, other: &Matrix<T>) {
- if let Some(result) = self.add_to(other) {
- *self = result;
- }
- }
-}
-
-impl<T: Float> ops::SubAssign<&Matrix<T>> for Matrix<T> {
- fn sub_assign(&mut self, other: &Matrix<T>) {
- if let Some(result) = self.subtract(other) {
- *self = result;
- }
- }
-}
-
-impl_matrix_ops! {
- Add, add, &Matrix<T>, Option<Matrix<T>>, add_to,
- Sub, sub, &Matrix<T>, Option<Matrix<T>>, subtract,
- Mul, mul, T, Matrix<T>, scale,
- Div, div, T, Matrix<T>, scale,
-}
-
-impl_matrix_ops! {
- MulAssign, mul_assign, T, scale,
- DivAssign, div_assign, T, scale,
-}
-
-impl<T: Float + fmt::Debug> fmt::Debug for Matrix<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for i in 0..self.rows {
- for j in 0..self.cols {
- write!(f, "{:?} ", self.get(i, j))?;
- }
- writeln!(f)?;
- }
- Ok(())
- }
-}
-
-impl<T: Float + fmt::Display> fmt::Display for Matrix<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let elements: Vec<String> = self.data.iter().map(ToString::to_string).collect();
- let is_complex = elements.iter().any(|element| element.contains("i"));
-
- let normalized: Vec<(f64, f64)> = self
- .data
- .iter()
- .map(|element| {
- let element_string = element.to_string();
-
- if is_complex {
- let element_string = element_string.trim_end_matches('i').trim();
- let element_split: Vec<&str> = element_string.split_whitespace().collect();
- let real = element_split[0].parse::<f64>().unwrap();
- let imaginary = element_split
- .get(2)
- .map_or(0.0, |&s| s.parse::<f64>().unwrap());
- (real, imaginary)
- } else {
- (element_string.parse::<f64>().unwrap(), 0.0)
- }
- })
- .collect();
-
- let max_widths = normalized
- .iter()
- .fold((0, 0), |(max_0, max_1), &(real, imag)| {
- let new_max_0 = max_0.max(format!("{:.2}", real).len());
- let new_max_1 = if is_complex {
- max_1.max(format!("{:.2}", imag.abs()).len())
- } else {
- max_1
- };
- (new_max_0, new_max_1)
- });
-
- let aligned: Vec<String> = normalized
- .iter()
- .map(|&(real, imag)| {
- if is_complex {
- format!(
- "{:>rewidth$.2} {} {:>imwidth$.2}i",
- real,
- if imag > 0.0 { "+" } else { "-" },
- imag.abs(),
- rewidth = max_widths.0,
- imwidth = max_widths.1,
- )
- } else {
- format!("{:>width$.2}", real, width = max_widths.0)
- }
- })
- .collect();
-
- for i in 0..self.rows {
- if i == 0 {
- write!(f, "┌")?;
- } else if i == self.rows - 1 {
- write!(f, "└")?;
- } else {
- write!(f, "│")?;
- }
-
- for j in 0..self.cols {
- write!(f, "{}", aligned[i + j * self.rows])?;
- if j != self.cols - 1 {
- write!(f, ", ")?;
- }
- }
-
- if i == 0 {
- write!(f, "┐")?;
- } else if i == self.rows - 1 {
- write!(f, "┘")?;
- } else {
- write!(f, "│")?;
- }
-
- if i != self.rows - 1 {
- writeln!(f)?;
- }
- }
-
- Ok(())
- }
-}
diff --git a/src/maths/simd.c b/src/maths/simd.c
index 9e83dcc..fc25de8 100644
--- a/src/maths/simd.c
+++ b/src/maths/simd.c
@@ -12,144 +12,144 @@
enum PsiSimdCapability psi_detect_simd(void)
{
#if defined(__x86_64__) || defined(__i386__)
- if (__builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq"))
- return PSI_SIMD_AVX512;
- if (__builtin_cpu_supports("avx2") && __builtin_cpu_supports("fma"))
- return PSI_SIMD_AVX2;
+ if (__builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq"))
+ return PSI_SIMD_AVX512;
+ if (__builtin_cpu_supports("avx2") && __builtin_cpu_supports("fma"))
+ return PSI_SIMD_AVX2;
- return PSI_SIMD_NONE;
+ return PSI_SIMD_NONE;
#elif defined(__aarch64__)
- return PSI_SIMD_NEON;
+ return PSI_SIMD_NEON;
#else
- return PSI_SIMD_NONE;
+ return PSI_SIMD_NONE;
#endif
}
const char* psi_simd_name(enum PsiSimdCapability cap)
{
- switch (cap)
- {
- case PSI_SIMD_NONE: return "Scalar";
- case PSI_SIMD_AVX2: return "AVX2+FMA";
- case PSI_SIMD_AVX512: return "AVX-512";
- case PSI_SIMD_NEON: return "NEON";
- }
+ switch (cap)
+ {
+ case PSI_SIMD_NONE: return "Scalar";
+ case PSI_SIMD_AVX2: return "AVX2+FMA";
+ case PSI_SIMD_AVX512: return "AVX-512";
+ case PSI_SIMD_NEON: return "NEON";
+ }
- return "Scalar";
+ return "Scalar";
}
static void apply_pair(struct PsiComplex* state, size_t i, size_t j, struct PsiComplex g00,
struct PsiComplex g01, struct PsiComplex g10, struct PsiComplex g11)
{
- struct PsiComplex s0 = state[i];
- struct PsiComplex s1 = state[j];
+ struct PsiComplex s0 = state[i];
+ struct PsiComplex s1 = state[j];
- state[i] = psi_new_complex(s0.real * g00.real - s0.imaginary * g00.imaginary +
- s1.real * g01.real - s1.imaginary * g01.imaginary,
- s0.real * g00.imaginary + s0.imaginary * g00.real +
- s1.real * g01.imaginary + s1.imaginary * g01.real);
- state[j] = psi_new_complex(s0.real * g10.real - s0.imaginary * g10.imaginary +
- s1.real * g11.real - s1.imaginary * g11.imaginary,
- s0.real * g10.imaginary + s0.imaginary * g10.real +
- s1.real * g11.imaginary + s1.imaginary * g11.real);
+ state[i] = psi_new_complex(s0.real * g00.real - s0.imaginary * g00.imaginary +
+ s1.real * g01.real - s1.imaginary * g01.imaginary,
+ s0.real * g00.imaginary + s0.imaginary * g00.real +
+ s1.real * g01.imaginary + s1.imaginary * g01.real);
+ state[j] = psi_new_complex(s0.real * g10.real - s0.imaginary * g10.imaginary +
+ s1.real * g11.real - s1.imaginary * g11.imaginary,
+ s0.real * g10.imaginary + s0.imaginary * g10.real +
+ s1.real * g11.imaginary + s1.imaginary * g11.real);
}
static void apply_scalar(struct PsiComplex* state, const struct PsiComplex gate[2][2],
size_t target, size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- for (size_t i = 0; i < dim; i++)
- {
- if ((i >> target_bit) & 1)
- continue;
+ for (size_t i = 0; i < dim; i++)
+ {
+ if ((i >> target_bit) & 1)
+ continue;
- apply_pair(state, i, i | step, gate[0][0], gate[0][1], gate[1][0], gate[1][1]);
- }
+ apply_pair(state, i, i | step, gate[0][0], gate[0][1], gate[1][0], gate[1][1]);
+ }
}
static size_t (*build_pairs(size_t dim, size_t target_bit, size_t step, size_t* out_count))[2]
{
- size_t (*pairs)[2] = malloc((dim / 2) * sizeof(*pairs));
- assert(pairs != NULL || dim == 0);
+ size_t (*pairs)[2] = malloc((dim / 2) * sizeof(*pairs));
+ assert(pairs != NULL || dim == 0);
- size_t n = 0;
- for (size_t i = 0; i < dim; i++)
- if (((i >> target_bit) & 1) == 0)
- {
- pairs[n][0] = i;
- pairs[n][1] = i | step;
- n++;
- }
+ size_t n = 0;
+ for (size_t i = 0; i < dim; i++)
+ if (((i >> target_bit) & 1) == 0)
+ {
+ pairs[n][0] = i;
+ pairs[n][1] = i | step;
+ n++;
+ }
- *out_count = n;
- return pairs;
+ *out_count = n;
+ return pairs;
}
#if defined(__aarch64__)
static void apply_neon(struct PsiComplex* state, const struct PsiComplex gate[2][2], size_t target,
size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex g00 = gate[0][0];
- struct PsiComplex g01 = gate[0][1];
- struct PsiComplex g10 = gate[1][0];
- struct PsiComplex g11 = gate[1][1];
+ struct PsiComplex g00 = gate[0][0];
+ struct PsiComplex g01 = gate[0][1];
+ struct PsiComplex g10 = gate[1][0];
+ struct PsiComplex g11 = gate[1][1];
- size_t np;
- size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
- size_t chunks = np / 2;
+ size_t np;
+ size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
+ size_t chunks = np / 2;
- float64x2_t g00_re = vdupq_n_f64(g00.real);
- float64x2_t g00_im = vdupq_n_f64(g00.imaginary);
- float64x2_t g01_re = vdupq_n_f64(g01.real);
- float64x2_t g01_im = vdupq_n_f64(g01.imaginary);
- float64x2_t g10_re = vdupq_n_f64(g10.real);
- float64x2_t g10_im = vdupq_n_f64(g10.imaginary);
- float64x2_t g11_re = vdupq_n_f64(g11.real);
- float64x2_t g11_im = vdupq_n_f64(g11.imaginary);
+ float64x2_t g00_re = vdupq_n_f64(g00.real);
+ float64x2_t g00_im = vdupq_n_f64(g00.imaginary);
+ float64x2_t g01_re = vdupq_n_f64(g01.real);
+ float64x2_t g01_im = vdupq_n_f64(g01.imaginary);
+ float64x2_t g10_re = vdupq_n_f64(g10.real);
+ float64x2_t g10_im = vdupq_n_f64(g10.imaginary);
+ float64x2_t g11_re = vdupq_n_f64(g11.real);
+ float64x2_t g11_im = vdupq_n_f64(g11.imaginary);
- for (size_t chunk = 0; chunk < chunks; chunk++)
- {
- size_t i0 = pairs[chunk * 2][0];
- size_t j0 = pairs[chunk * 2][1];
- size_t i1 = pairs[chunk * 2 + 1][0];
- size_t j1 = pairs[chunk * 2 + 1][1];
+ for (size_t chunk = 0; chunk < chunks; chunk++)
+ {
+ size_t i0 = pairs[chunk * 2][0];
+ size_t j0 = pairs[chunk * 2][1];
+ size_t i1 = pairs[chunk * 2 + 1][0];
+ size_t j1 = pairs[chunk * 2 + 1][1];
- double s0r[2] = { state[i0].real, state[i1].real };
- double s0i[2] = { state[i0].imaginary, state[i1].imaginary };
- double s1r[2] = { state[j0].real, state[j1].real };
- double s1i[2] = { state[j0].imaginary, state[j1].imaginary };
+ double s0r[2] = { state[i0].real, state[i1].real };
+ double s0i[2] = { state[i0].imaginary, state[i1].imaginary };
+ double s1r[2] = { state[j0].real, state[j1].real };
+ double s1i[2] = { state[j0].imaginary, state[j1].imaginary };
- float64x2_t s0_re = vld1q_f64(s0r);
- float64x2_t s0_im = vld1q_f64(s0i);
- float64x2_t s1_re = vld1q_f64(s1r);
- float64x2_t s1_im = vld1q_f64(s1i);
+ float64x2_t s0_re = vld1q_f64(s0r);
+ float64x2_t s0_im = vld1q_f64(s0i);
+ float64x2_t s1_re = vld1q_f64(s1r);
+ float64x2_t s1_im = vld1q_f64(s1i);
- float64x2_t new0_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g00_re), s0_im, g00_im),
- vfmsq_f64(vmulq_f64(s1_re, g01_re), s1_im, g01_im));
- float64x2_t new0_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g00_im), s0_im, g00_re),
- vfmaq_f64(vmulq_f64(s1_re, g01_im), s1_im, g01_re));
- float64x2_t new1_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g10_re), s0_im, g10_im),
- vfmsq_f64(vmulq_f64(s1_re, g11_re), s1_im, g11_im));
- float64x2_t new1_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g10_im), s0_im, g10_re),
- vfmaq_f64(vmulq_f64(s1_re, g11_im), s1_im, g11_re));
+ float64x2_t new0_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g00_re), s0_im, g00_im),
+ vfmsq_f64(vmulq_f64(s1_re, g01_re), s1_im, g01_im));
+ float64x2_t new0_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g00_im), s0_im, g00_re),
+ vfmaq_f64(vmulq_f64(s1_re, g01_im), s1_im, g01_re));
+ float64x2_t new1_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g10_re), s0_im, g10_im),
+ vfmsq_f64(vmulq_f64(s1_re, g11_re), s1_im, g11_im));
+ float64x2_t new1_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g10_im), s0_im, g10_re),
+ vfmaq_f64(vmulq_f64(s1_re, g11_im), s1_im, g11_re));
- state[i0] = psi_new_complex(vgetq_lane_f64(new0_re, 0), vgetq_lane_f64(new0_im, 0));
- state[j0] = psi_new_complex(vgetq_lane_f64(new1_re, 0), vgetq_lane_f64(new1_im, 0));
- state[i1] = psi_new_complex(vgetq_lane_f64(new0_re, 1), vgetq_lane_f64(new0_im, 1));
- state[j1] = psi_new_complex(vgetq_lane_f64(new1_re, 1), vgetq_lane_f64(new1_im, 1));
- }
+ state[i0] = psi_new_complex(vgetq_lane_f64(new0_re, 0), vgetq_lane_f64(new0_im, 0));
+ state[j0] = psi_new_complex(vgetq_lane_f64(new1_re, 0), vgetq_lane_f64(new1_im, 0));
+ state[i1] = psi_new_complex(vgetq_lane_f64(new0_re, 1), vgetq_lane_f64(new0_im, 1));
+ state[j1] = psi_new_complex(vgetq_lane_f64(new1_re, 1), vgetq_lane_f64(new1_im, 1));
+ }
- for (size_t p = chunks * 2; p < np; p++)
- apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
+ for (size_t p = chunks * 2; p < np; p++)
+ apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
- free(pairs);
+ free(pairs);
}
#endif
@@ -158,167 +158,167 @@ __attribute__((target("avx2,fma"))) static void apply_avx2(struct PsiComplex* st
const struct PsiComplex gate[2][2],
size_t target, size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex g00 = gate[0][0];
- struct PsiComplex g01 = gate[0][1];
- struct PsiComplex g10 = gate[1][0];
- struct PsiComplex g11 = gate[1][1];
+ struct PsiComplex g00 = gate[0][0];
+ struct PsiComplex g01 = gate[0][1];
+ struct PsiComplex g10 = gate[1][0];
+ struct PsiComplex g11 = gate[1][1];
- size_t np;
- size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
- size_t chunks = np / 2;
+ size_t np;
+ size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
+ size_t chunks = np / 2;
- for (size_t chunk = 0; chunk < chunks; chunk++)
- {
- size_t i0 = pairs[chunk * 2][0];
- size_t j0 = pairs[chunk * 2][1];
- size_t i1 = pairs[chunk * 2 + 1][0];
- size_t j1 = pairs[chunk * 2 + 1][1];
+ for (size_t chunk = 0; chunk < chunks; chunk++)
+ {
+ size_t i0 = pairs[chunk * 2][0];
+ size_t j0 = pairs[chunk * 2][1];
+ size_t i1 = pairs[chunk * 2 + 1][0];
+ size_t j1 = pairs[chunk * 2 + 1][1];
- __m256d s0_re =
- _mm256_set_pd(state[j1].real, state[i1].real, state[j0].real, state[i0].real);
- __m256d s0_im = _mm256_set_pd(state[j1].imaginary, state[i1].imaginary, state[j0].imaginary,
- state[i0].imaginary);
+ __m256d s0_re =
+ _mm256_set_pd(state[j1].real, state[i1].real, state[j0].real, state[i0].real);
+ __m256d s0_im = _mm256_set_pd(state[j1].imaginary, state[i1].imaginary, state[j0].imaginary,
+ state[i0].imaginary);
- __m256d g_re_0 = _mm256_set_pd(g01.real, g00.real, g01.real, g00.real);
- __m256d g_im_0 = _mm256_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
- __m256d g_re_1 = _mm256_set_pd(g11.real, g10.real, g11.real, g10.real);
- __m256d g_im_1 = _mm256_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
+ __m256d g_re_0 = _mm256_set_pd(g01.real, g00.real, g01.real, g00.real);
+ __m256d g_im_0 = _mm256_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
+ __m256d g_re_1 = _mm256_set_pd(g11.real, g10.real, g11.real, g10.real);
+ __m256d g_im_1 = _mm256_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
- __m256d prod0_re = _mm256_fmsub_pd(s0_re, g_re_0, _mm256_mul_pd(s0_im, g_im_0));
- __m256d prod0_im = _mm256_fmadd_pd(s0_re, g_im_0, _mm256_mul_pd(s0_im, g_re_0));
- __m256d prod1_re = _mm256_fmsub_pd(s0_re, g_re_1, _mm256_mul_pd(s0_im, g_im_1));
- __m256d prod1_im = _mm256_fmadd_pd(s0_re, g_im_1, _mm256_mul_pd(s0_im, g_re_1));
+ __m256d prod0_re = _mm256_fmsub_pd(s0_re, g_re_0, _mm256_mul_pd(s0_im, g_im_0));
+ __m256d prod0_im = _mm256_fmadd_pd(s0_re, g_im_0, _mm256_mul_pd(s0_im, g_re_0));
+ __m256d prod1_re = _mm256_fmsub_pd(s0_re, g_re_1, _mm256_mul_pd(s0_im, g_im_1));
+ __m256d prod1_im = _mm256_fmadd_pd(s0_re, g_im_1, _mm256_mul_pd(s0_im, g_re_1));
- double res0_re[4];
- double res0_im[4];
- double res1_re[4];
- double res1_im[4];
+ double res0_re[4];
+ double res0_im[4];
+ double res1_re[4];
+ double res1_im[4];
- _mm256_storeu_pd(res0_re, prod0_re);
- _mm256_storeu_pd(res0_im, prod0_im);
- _mm256_storeu_pd(res1_re, prod1_re);
- _mm256_storeu_pd(res1_im, prod1_im);
+ _mm256_storeu_pd(res0_re, prod0_re);
+ _mm256_storeu_pd(res0_im, prod0_im);
+ _mm256_storeu_pd(res1_re, prod1_re);
+ _mm256_storeu_pd(res1_im, prod1_im);
- state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
- state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
- state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
- state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
- }
+ state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
+ state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
+ state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
+ state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
+ }
- for (size_t p = chunks * 2; p < np; p++)
- apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
+ for (size_t p = chunks * 2; p < np; p++)
+ apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
- free(pairs);
+ free(pairs);
}
__attribute__((target("avx512f,avx512dq"))) static void
apply_avx512(struct PsiComplex* state, const struct PsiComplex gate[2][2], size_t target,
size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex g00 = gate[0][0];
- struct PsiComplex g01 = gate[0][1];
- struct PsiComplex g10 = gate[1][0];
- struct PsiComplex g11 = gate[1][1];
+ struct PsiComplex g00 = gate[0][0];
+ struct PsiComplex g01 = gate[0][1];
+ struct PsiComplex g10 = gate[1][0];
+ struct PsiComplex g11 = gate[1][1];
- size_t np;
- size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
- size_t chunks = np / 4;
+ size_t np;
+ size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
+ size_t chunks = np / 4;
- for (size_t chunk = 0; chunk < chunks; chunk++)
- {
- size_t base = chunk * 4;
- size_t i0 = pairs[base][0], j0 = pairs[base][1];
- size_t i1 = pairs[base + 1][0], j1 = pairs[base + 1][1];
- size_t i2 = pairs[base + 2][0], j2 = pairs[base + 2][1];
- size_t i3 = pairs[base + 3][0], j3 = pairs[base + 3][1];
+ for (size_t chunk = 0; chunk < chunks; chunk++)
+ {
+ size_t base = chunk * 4;
+ size_t i0 = pairs[base][0], j0 = pairs[base][1];
+ size_t i1 = pairs[base + 1][0], j1 = pairs[base + 1][1];
+ size_t i2 = pairs[base + 2][0], j2 = pairs[base + 2][1];
+ size_t i3 = pairs[base + 3][0], j3 = pairs[base + 3][1];
- __m512d s0_re =
- _mm512_set_pd(state[j3].real, state[i3].real, state[j2].real, state[i2].real,
- state[j1].real, state[i1].real, state[j0].real, state[i0].real);
- __m512d s0_im = _mm512_set_pd(state[j3].imaginary, state[i3].imaginary, state[j2].imaginary,
- state[i2].imaginary, state[j1].imaginary, state[i1].imaginary,
- state[j0].imaginary, state[i0].imaginary);
+ __m512d s0_re =
+ _mm512_set_pd(state[j3].real, state[i3].real, state[j2].real, state[i2].real,
+ state[j1].real, state[i1].real, state[j0].real, state[i0].real);
+ __m512d s0_im = _mm512_set_pd(state[j3].imaginary, state[i3].imaginary, state[j2].imaginary,
+ state[i2].imaginary, state[j1].imaginary, state[i1].imaginary,
+ state[j0].imaginary, state[i0].imaginary);
- __m512d g_re_0 = _mm512_set_pd(g01.real, g00.real, g01.real, g00.real, g01.real, g00.real,
- g01.real, g00.real);
- __m512d g_im_0 = _mm512_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary,
- g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
- __m512d g_re_1 = _mm512_set_pd(g11.real, g10.real, g11.real, g10.real, g11.real, g10.real,
- g11.real, g10.real);
- __m512d g_im_1 = _mm512_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary,
- g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
+ __m512d g_re_0 = _mm512_set_pd(g01.real, g00.real, g01.real, g00.real, g01.real, g00.real,
+ g01.real, g00.real);
+ __m512d g_im_0 = _mm512_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary,
+ g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
+ __m512d g_re_1 = _mm512_set_pd(g11.real, g10.real, g11.real, g10.real, g11.real, g10.real,
+ g11.real, g10.real);
+ __m512d g_im_1 = _mm512_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary,
+ g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
- __m512d prod0_re = _mm512_fmsub_pd(s0_re, g_re_0, _mm512_mul_pd(s0_im, g_im_0));
- __m512d prod0_im = _mm512_fmadd_pd(s0_re, g_im_0, _mm512_mul_pd(s0_im, g_re_0));
- __m512d prod1_re = _mm512_fmsub_pd(s0_re, g_re_1, _mm512_mul_pd(s0_im, g_im_1));
- __m512d prod1_im = _mm512_fmadd_pd(s0_re, g_im_1, _mm512_mul_pd(s0_im, g_re_1));
+ __m512d prod0_re = _mm512_fmsub_pd(s0_re, g_re_0, _mm512_mul_pd(s0_im, g_im_0));
+ __m512d prod0_im = _mm512_fmadd_pd(s0_re, g_im_0, _mm512_mul_pd(s0_im, g_re_0));
+ __m512d prod1_re = _mm512_fmsub_pd(s0_re, g_re_1, _mm512_mul_pd(s0_im, g_im_1));
+ __m512d prod1_im = _mm512_fmadd_pd(s0_re, g_im_1, _mm512_mul_pd(s0_im, g_re_1));
- double res0_re[8];
- double res0_im[8];
- double res1_re[8];
- double res1_im[8];
+ double res0_re[8];
+ double res0_im[8];
+ double res1_re[8];
+ double res1_im[8];
- _mm512_storeu_pd(res0_re, prod0_re);
- _mm512_storeu_pd(res0_im, prod0_im);
- _mm512_storeu_pd(res1_re, prod1_re);
- _mm512_storeu_pd(res1_im, prod1_im);
+ _mm512_storeu_pd(res0_re, prod0_re);
+ _mm512_storeu_pd(res0_im, prod0_im);
+ _mm512_storeu_pd(res1_re, prod1_re);
+ _mm512_storeu_pd(res1_im, prod1_im);
- state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
- state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
- state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
- state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
- state[i2] = psi_new_complex(res0_re[4] + res0_re[5], res0_im[4] + res0_im[5]);
- state[j2] = psi_new_complex(res1_re[4] + res1_re[5], res1_im[4] + res1_im[5]);
- state[i3] = psi_new_complex(res0_re[6] + res0_re[7], res0_im[6] + res0_im[7]);
- state[j3] = psi_new_complex(res1_re[6] + res1_re[7], res1_im[6] + res1_im[7]);
- }
+ state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
+ state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
+ state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
+ state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
+ state[i2] = psi_new_complex(res0_re[4] + res0_re[5], res0_im[4] + res0_im[5]);
+ state[j2] = psi_new_complex(res1_re[4] + res1_re[5], res1_im[4] + res1_im[5]);
+ state[i3] = psi_new_complex(res0_re[6] + res0_re[7], res0_im[6] + res0_im[7]);
+ state[j3] = psi_new_complex(res1_re[6] + res1_re[7], res1_im[6] + res1_im[7]);
+ }
- for (size_t p = chunks * 4; p < np; p++)
- apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
+ for (size_t p = chunks * 4; p < np; p++)
+ apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
- free(pairs);
+ free(pairs);
}
#endif
void psi_apply_single_qubit_gate_simd(struct PsiComplex* state, const struct PsiComplex gate[2][2],
size_t target, size_t num_qubits)
{
- enum PsiSimdCapability cap = psi_detect_simd();
+ enum PsiSimdCapability cap = psi_detect_simd();
#if defined(__x86_64__) || defined(__i386__)
- if (cap == PSI_SIMD_AVX512)
- {
- apply_avx512(state, gate, target, num_qubits);
- return;
- }
- if (cap == PSI_SIMD_AVX2)
- {
- apply_avx2(state, gate, target, num_qubits);
- return;
- }
+ if (cap == PSI_SIMD_AVX512)
+ {
+ apply_avx512(state, gate, target, num_qubits);
+ return;
+ }
+ if (cap == PSI_SIMD_AVX2)
+ {
+ apply_avx2(state, gate, target, num_qubits);
+ return;
+ }
#elif defined(__aarch64__)
- if (cap == PSI_SIMD_NEON)
- {
- apply_neon(state, gate, target, num_qubits);
- return;
- }
+ if (cap == PSI_SIMD_NEON)
+ {
+ apply_neon(state, gate, target, num_qubits);
+ return;
+ }
#endif
- (void)cap;
- apply_scalar(state, gate, target, num_qubits);
+ (void)cap;
+ apply_scalar(state, gate, target, num_qubits);
}
void psi_apply_single_qubit_gate_simd_parallel(struct PsiComplex* state,
const struct PsiComplex gate[2][2], size_t target,
size_t num_qubits)
{
- apply_scalar(state, gate, target, num_qubits);
+ apply_scalar(state, gate, target, num_qubits);
}
diff --git a/src/maths/vector.c b/src/maths/vector.c
index 1c5c4f9..5cd49e0 100644
--- a/src/maths/vector.c
+++ b/src/maths/vector.c
@@ -6,155 +6,155 @@
static enum PsiVectorKind flip_kind(enum PsiVectorKind kind)
{
- if (kind == PSI_ROW_VECTOR)
- return PSI_COLUMN_VECTOR;
+ if (kind == PSI_ROW_VECTOR)
+ return PSI_COLUMN_VECTOR;
- return PSI_ROW_VECTOR;
+ return PSI_ROW_VECTOR;
}
struct PsiVector psi_new_vector(size_t size, enum PsiVectorKind kind)
{
- struct PsiComplex* data = calloc(size, sizeof(struct PsiComplex));
- assert(data != NULL || size == 0);
+ struct PsiComplex* data = calloc(size, sizeof(struct PsiComplex));
+ assert(data != NULL || size == 0);
- return (struct PsiVector){
- data,
- size,
- kind,
- };
+ return (struct PsiVector){
+ data,
+ size,
+ kind,
+ };
}
struct PsiVector psi_new_vector_from(const struct PsiComplex* data, size_t size,
enum PsiVectorKind kind)
{
- struct PsiVector v = psi_new_vector(size, kind);
- memcpy(v.data, data, size * sizeof(struct PsiComplex));
+ struct PsiVector v = psi_new_vector(size, kind);
+ memcpy(v.data, data, size * sizeof(struct PsiComplex));
- return v;
+ return v;
}
struct PsiVector psi_clone_vector(struct PsiVector v)
{
- return psi_new_vector_from(v.data, v.size, v.kind);
+ return psi_new_vector_from(v.data, v.size, v.kind);
}
void psi_free_vector(struct PsiVector* v)
{
- free(v->data);
- v->data = NULL;
- v->size = 0;
+ free(v->data);
+ v->data = NULL;
+ v->size = 0;
}
struct PsiComplex psi_get_vector(struct PsiVector v, size_t index)
{
- assert(index < v.size);
- return v.data[index];
+ assert(index < v.size);
+ return v.data[index];
}
void psi_set_vector(struct PsiVector* v, size_t index, struct PsiComplex value)
{
- assert(index < v->size);
- v->data[index] = value;
+ assert(index < v->size);
+ v->data[index] = value;
}
struct PsiComplex psi_dot_vector(struct PsiVector a, struct PsiVector b)
{
- assert(a.size == b.size);
+ assert(a.size == b.size);
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < a.size; i++)
- sum = psi_add_complex(sum, psi_mul_complex(a.data[i], b.data[i]));
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < a.size; i++)
+ sum = psi_add_complex(sum, psi_mul_complex(a.data[i], b.data[i]));
- return sum;
+ return sum;
}
struct PsiComplex psi_norm_vector(struct PsiVector v)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < v.size; i++)
- sum = psi_add_complex(sum, psi_mul_complex(v.data[i], v.data[i]));
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < v.size; i++)
+ sum = psi_add_complex(sum, psi_mul_complex(v.data[i], v.data[i]));
- return psi_sqrt_complex(sum);
+ return psi_sqrt_complex(sum);
}
struct PsiComplex psi_sum_vector(struct PsiVector v)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < v.size; i++)
- sum = psi_add_complex(sum, v.data[i]);
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < v.size; i++)
+ sum = psi_add_complex(sum, v.data[i]);
- return sum;
+ return sum;
}
static int less_than(struct PsiComplex a, struct PsiComplex b)
{
- if (a.real != b.real)
- return a.real < b.real;
+ if (a.real != b.real)
+ return a.real < b.real;
- return a.imaginary < b.imaginary;
+ return a.imaginary < b.imaginary;
}
struct PsiComplex psi_max_vector(struct PsiVector v)
{
- if (v.size == 0)
- return psi_new_complex(0.0, 0.0);
+ if (v.size == 0)
+ return psi_new_complex(0.0, 0.0);
- struct PsiComplex best = v.data[0];
- for (size_t i = 1; i < v.size; i++)
- if (less_than(best, v.data[i]))
- best = v.data[i];
+ struct PsiComplex best = v.data[0];
+ for (size_t i = 1; i < v.size; i++)
+ if (less_than(best, v.data[i]))
+ best = v.data[i];
- return best;
+ return best;
}
struct PsiComplex psi_min_vector(struct PsiVector v)
{
- if (v.size == 0)
- return psi_new_complex(0.0, 0.0);
+ if (v.size == 0)
+ return psi_new_complex(0.0, 0.0);
- struct PsiComplex best = v.data[0];
- for (size_t i = 1; i < v.size; i++)
- if (less_than(v.data[i], best))
- best = v.data[i];
+ struct PsiComplex best = v.data[0];
+ for (size_t i = 1; i < v.size; i++)
+ if (less_than(v.data[i], best))
+ best = v.data[i];
- return best;
+ return best;
}
struct PsiVector psi_add_vector(struct PsiVector a, struct PsiVector b)
{
- assert(a.size == b.size);
+ assert(a.size == b.size);
- struct PsiVector result = psi_new_vector(a.size, a.kind);
- for (size_t i = 0; i < a.size; i++)
- result.data[i] = psi_add_complex(a.data[i], b.data[i]);
+ struct PsiVector result = psi_new_vector(a.size, a.kind);
+ for (size_t i = 0; i < a.size; i++)
+ result.data[i] = psi_add_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiVector psi_sub_vector(struct PsiVector a, struct PsiVector b)
{
- assert(a.size == b.size);
+ assert(a.size == b.size);
- struct PsiVector result = psi_new_vector(a.size, a.kind);
- for (size_t i = 0; i < a.size; i++)
- result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
+ struct PsiVector result = psi_new_vector(a.size, a.kind);
+ for (size_t i = 0; i < a.size; i++)
+ result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiVector psi_scale_vector(struct PsiVector v, struct PsiComplex scalar)
{
- struct PsiVector result = psi_new_vector(v.size, v.kind);
- for (size_t i = 0; i < v.size; i++)
- result.data[i] = psi_mul_complex(v.data[i], scalar);
+ struct PsiVector result = psi_new_vector(v.size, v.kind);
+ for (size_t i = 0; i < v.size; i++)
+ result.data[i] = psi_mul_complex(v.data[i], scalar);
- return result;
+ return result;
}
struct PsiVector psi_transpose_vector(struct PsiVector v)
{
- struct PsiVector result = psi_clone_vector(v);
- result.kind = flip_kind(v.kind);
+ struct PsiVector result = psi_clone_vector(v);
+ result.kind = flip_kind(v.kind);
- return result;
+ return result;
}
diff --git a/src/maths/vector.rs b/src/maths/vector.rs
deleted file mode 100644
index 11f3d29..0000000
--- a/src/maths/vector.rs
+++ /dev/null
@@ -1,258 +0,0 @@
-use super::{Float, Matrix};
-use core::{fmt, ops};
-
-#[macro_export]
-macro_rules! row_vector {
- ($($x:expr),*) => {
- RowVector::new(vec![$($x),*])
- };
- ($($x:expr,)*) => {
- RowVector::new(vec![$($x),*])
- };
-}
-
-#[macro_export]
-macro_rules! column_vector {
- ($($x:expr),*) => {
- ColumnVector::new(vec![$($x),*])
- };
- ($($x:expr,)*) => {
- ColumnVector::new(vec![$($x),*])
- };
-}
-
-pub trait Vector<T: Float> {
- fn new(data: Vec<T>) -> Self;
- fn get(&self, index: usize) -> T;
- fn set(&mut self, index: usize, value: T);
- fn size(&self) -> usize;
-
- fn dot(&self, other: &Self) -> T;
- fn norm(&self) -> T;
-
- fn max(&self) -> T;
- fn min(&self) -> T;
- fn sum(&self) -> T;
-
- fn from_matrix(matrix: &Matrix<T>) -> Self;
-}
-
-pub trait VectorMatrix<T: Float> {
- fn to_matrix(&self) -> Matrix<T>;
-}
-
-#[derive(Clone)]
-pub struct VectorImpl<T: Float, const ROWS: usize, const COLS: usize>(Vec<T>);
-pub type RowVector<T> = VectorImpl<T, 1, 0>;
-pub type ColumnVector<T> = VectorImpl<T, 0, 1>;
-
-impl<T: Float> ColumnVector<T> {
- pub fn mul_matrix(&self, matrix: &Matrix<T>) -> Option<ColumnVector<T>> {
- if matrix.cols != self.size() {
- return None;
- }
-
- let mut result = ColumnVector::new(vec![T::zero(); matrix.rows]);
-
- for i in 0..matrix.rows {
- let mut sum = T::zero();
- for j in 0..matrix.cols {
- sum += matrix.get(i, j) * self.get(j) ;
- }
- result.set(i, sum);
- }
-
- Some(result)
- }
-
- pub fn transpose(&self) -> RowVector<T> {
- RowVector::new(self.0.clone())
- }
-}
-
-impl<T: Float> RowVector<T> {
- pub fn mul_matrix(&self, matrix: &Matrix<T>) -> Option<RowVector<T>> {
- if self.size() != matrix.rows {
- return None;
- }
-
- let mut result = RowVector::new(vec![T::zero(); matrix.cols]);
-
- for j in 0..matrix.cols {
- let mut sum = T::zero();
- for i in 0..matrix.rows {
- sum += self.get(i) * matrix.get(i, j) ;
- }
- result.set(j, sum);
- }
-
- Some(result)
- }
-
- pub fn transpose(&self) -> ColumnVector<T> {
- ColumnVector::new(self.0.clone())
- }
-}
-
-impl<T: Float> VectorMatrix<T> for RowVector<T> {
- fn to_matrix(&self) -> Matrix<T> {
- Matrix::new(1, self.size(), self.0.clone())
- }
-}
-
-impl<T: Float> VectorMatrix<T> for ColumnVector<T> {
- fn to_matrix(&self) -> Matrix<T> {
- Matrix::new(self.size(), 1, self.0.clone())
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> Vector<T> for VectorImpl<T, ROWS, COLS> {
- fn from_matrix(matrix: &Matrix<T>) -> Self {
- Self::new(matrix.data.clone())
- }
-
- fn new(data: Vec<T>) -> Self {
- Self(data)
- }
-
- fn get(&self, index: usize) -> T {
- self.0[index]
- }
-
- fn set(&mut self, index: usize, value: T) {
- self.0[index] = value;
- }
-
- fn size(&self) -> usize {
- self.0.len()
- }
-
- fn dot(&self, other: &Self) -> T {
- self.0
- .iter()
- .zip(other.0.iter())
- .map(|(a, b)| *a * *b)
- .fold(T::zero(), |acc, x| acc + x)
- }
-
- fn norm(&self) -> T {
- self.0
- .iter()
- .map(|x| *x * *x)
- .fold(T::zero(), |acc, x| acc + x)
- .sqrt()
- }
-
- fn max(&self) -> T {
- *self
- .0
- .iter()
- .max_by(|a, b| a.partial_cmp(b).unwrap())
- .unwrap_or(&T::zero())
- }
-
- fn min(&self) -> T {
- *self
- .0
- .iter()
- .min_by(|a, b| a.partial_cmp(b).unwrap())
- .unwrap_or(&T::zero())
- }
-
- fn sum(&self) -> T {
- self.0.iter().fold(T::zero(), |acc, x| acc + *x)
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> VectorImpl<T, ROWS, COLS> {
- pub fn add_to(&self, other: &Self) -> Option<VectorImpl<T, ROWS, COLS>> {
- if self.size() != other.size() {
- return None;
- }
-
- let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]);
-
- for i in 0..self.size() {
- let sum = self.get(i) + other.get(i);
- result.set(i, sum);
- }
-
- Some(result)
- }
-
- pub fn subtract(&self, other: &Self) -> Option<VectorImpl<T, ROWS, COLS>> {
- if self.size() != other.size() {
- return None;
- }
-
- let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]);
-
- for i in 0..self.size() {
- let sum = self.get(i) - other.get(i);
- result.set(i, sum);
- }
-
- Some(result)
- }
-
- pub fn scale(&self, scalar: T) -> VectorImpl<T, ROWS, COLS> {
- let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]);
-
- for i in 0..self.size() {
- let product = self.get(i) * scalar;
- result.set(i, product);
- }
-
- result
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> ops::Index<usize>
- for VectorImpl<T, ROWS, COLS>
-{
- type Output = T;
-
- fn index(&self, index: usize) -> &Self::Output {
- &self.0[index]
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> ops::IndexMut<usize>
- for VectorImpl<T, ROWS, COLS>
-{
- fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- &mut self.0[index]
- }
-}
-
-impl<T: Float + fmt::Debug> fmt::Debug for RowVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "RowVector({:?})", self.0)
- }
-}
-
-impl<T: Float + fmt::Debug> fmt::Debug for ColumnVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "ColumnVector({:?})", self.0)
- }
-}
-
-impl<T: Float + fmt::Display> fmt::Display for RowVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "[{}]",
- self.0
- .iter()
- .map(|x| x.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- )
- }
-}
-
-impl<T: Float + fmt::Display> fmt::Display for ColumnVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.to_matrix())
- }
-}
diff --git a/src/psi.c b/src/psi.c
index 34940fe..f8a659a 100644
--- a/src/psi.c
+++ b/src/psi.c
@@ -2,5 +2,5 @@
const char* psi_version(void)
{
- return "0.1.0";
+ return "0.1.0";
}
diff --git a/src/visualizer/grid.c b/src/visualizer/grid.c
index 32ade1b..29d1981 100644
--- a/src/visualizer/grid.c
+++ b/src/visualizer/grid.c
@@ -6,129 +6,129 @@
static size_t glyph_bytes(unsigned char lead)
{
- if (lead < 0x80)
- return 1;
- if ((lead >> 5) == 0x6)
- return 2;
- if ((lead >> 4) == 0xE)
- return 3;
- if ((lead >> 3) == 0x1E)
- return 4;
+ if (lead < 0x80)
+ return 1;
+ if ((lead >> 5) == 0x6)
+ return 2;
+ if ((lead >> 4) == 0xE)
+ return 3;
+ if ((lead >> 3) == 0x1E)
+ return 4;
- return 1;
+ return 1;
}
size_t psi_utf8_count(const char* s)
{
- size_t count = 0;
- while (*s)
- {
- s += glyph_bytes((unsigned char)*s);
- count++;
- }
+ size_t count = 0;
+ while (*s)
+ {
+ s += glyph_bytes((unsigned char)*s);
+ count++;
+ }
- return count;
+ return count;
}
struct PsiStringBuilder psi_new_string_builder(void)
{
- return (struct PsiStringBuilder){
- NULL,
- 0,
- 0,
- };
+ return (struct PsiStringBuilder){
+ NULL,
+ 0,
+ 0,
+ };
}
void psi_string_builder_append(struct PsiStringBuilder* sb, const char* s)
{
- size_t n = strlen(s);
- if (sb->len + n + 1 > sb->cap)
- {
- size_t new_cap = sb->cap == 0 ? 256 : sb->cap * 2;
- while (new_cap < sb->len + n + 1)
- new_cap *= 2;
+ size_t n = strlen(s);
+ if (sb->len + n + 1 > sb->cap)
+ {
+ size_t new_cap = sb->cap == 0 ? 256 : sb->cap * 2;
+ while (new_cap < sb->len + n + 1)
+ new_cap *= 2;
- sb->data = realloc(sb->data, new_cap);
- assert(sb->data != NULL);
- sb->cap = new_cap;
- }
+ sb->data = realloc(sb->data, new_cap);
+ assert(sb->data != NULL);
+ sb->cap = new_cap;
+ }
- memcpy(sb->data + sb->len, s, n + 1);
- sb->len += n;
+ memcpy(sb->data + sb->len, s, n + 1);
+ sb->len += n;
}
char* psi_string_builder_finish(struct PsiStringBuilder* sb)
{
- if (sb->data == NULL)
- psi_string_builder_append(sb, "");
+ if (sb->data == NULL)
+ psi_string_builder_append(sb, "");
- return sb->data;
+ return sb->data;
}
struct PsiGlyphRow psi_new_glyph_row(size_t width)
{
- char (*cells)[5] = malloc(width * sizeof(*cells));
- assert(cells != NULL || width == 0);
+ char (*cells)[5] = malloc(width * sizeof(*cells));
+ assert(cells != NULL || width == 0);
- for (size_t i = 0; i < width; i++)
- memcpy(cells[i], " ", 2);
+ for (size_t i = 0; i < width; i++)
+ memcpy(cells[i], " ", 2);
- return (struct PsiGlyphRow){
- cells,
- width,
- };
+ return (struct PsiGlyphRow){
+ cells,
+ width,
+ };
}
void psi_free_glyph_row(struct PsiGlyphRow* row)
{
- free(row->cells);
- row->cells = NULL;
- row->width = 0;
+ free(row->cells);
+ row->cells = NULL;
+ row->width = 0;
}
void psi_glyph_row_set(struct PsiGlyphRow* row, size_t index, const char* glyph)
{
- if (index >= row->width)
- return;
+ if (index >= row->width)
+ return;
- size_t n = glyph_bytes((unsigned char)glyph[0]);
- memcpy(row->cells[index], glyph, n);
- row->cells[index][n] = '\0';
+ size_t n = glyph_bytes((unsigned char)glyph[0]);
+ memcpy(row->cells[index], glyph, n);
+ row->cells[index][n] = '\0';
}
size_t psi_glyph_row_place(struct PsiGlyphRow* row, size_t start, const char* utf8)
{
- size_t count = 0;
- const char* p = utf8;
+ size_t count = 0;
+ const char* p = utf8;
- while (*p)
- {
- size_t n = glyph_bytes((unsigned char)*p);
- size_t index = start + count;
- if (index < row->width)
- {
- memcpy(row->cells[index], p, n);
- row->cells[index][n] = '\0';
- }
+ while (*p)
+ {
+ size_t n = glyph_bytes((unsigned char)*p);
+ size_t index = start + count;
+ if (index < row->width)
+ {
+ memcpy(row->cells[index], p, n);
+ row->cells[index][n] = '\0';
+ }
- p += n;
- count++;
- }
+ p += n;
+ count++;
+ }
- return count;
+ return count;
}
void psi_glyph_row_fill_space(struct PsiGlyphRow* row, size_t from, size_t to, const char* glyph)
{
- for (size_t i = from; i < to && i < row->width; i++)
- if (strcmp(row->cells[i], " ") == 0)
- psi_glyph_row_set(row, i, glyph);
+ for (size_t i = from; i < to && i < row->width; i++)
+ if (strcmp(row->cells[i], " ") == 0)
+ psi_glyph_row_set(row, i, glyph);
}
void psi_glyph_row_render(struct PsiGlyphRow row, struct PsiStringBuilder* sb)
{
- for (size_t i = 0; i < row.width; i++)
- psi_string_builder_append(sb, row.cells[i]);
+ for (size_t i = 0; i < row.width; i++)
+ psi_string_builder_append(sb, row.cells[i]);
- psi_string_builder_append(sb, "\n");
+ psi_string_builder_append(sb, "\n");
}
diff --git a/src/visualizer/grid.h b/src/visualizer/grid.h
index 9353433..f02941a 100644
--- a/src/visualizer/grid.h
+++ b/src/visualizer/grid.h
@@ -4,9 +4,9 @@
struct PsiStringBuilder
{
- char* data;
- size_t len;
- size_t cap;
+ char* data;
+ size_t len;
+ size_t cap;
};
struct PsiStringBuilder psi_new_string_builder(void);
@@ -15,8 +15,8 @@ char* psi_string_builder_finish(struct PsiStringBuilder* sb);
struct PsiGlyphRow
{
- char (*cells)[5];
- size_t width;
+ char (*cells)[5];
+ size_t width;
};
struct PsiGlyphRow psi_new_glyph_row(size_t width);
diff --git a/src/visualizer/horizontal_cli.c b/src/visualizer/horizontal_cli.c
index 56a2e00..9f7620e 100644
--- a/src/visualizer/horizontal_cli.c
+++ b/src/visualizer/horizontal_cli.c
@@ -10,344 +10,344 @@
static void append_repeat(struct PsiStringBuilder* sb, const char* glyph, size_t n)
{
- for (size_t i = 0; i < n; i++)
- psi_string_builder_append(sb, glyph);
+ for (size_t i = 0; i < n; i++)
+ psi_string_builder_append(sb, glyph);
}
static bool is_single_target(enum PsiGateKind kind)
{
- switch (kind)
- {
- case PSI_GATE_H:
- case PSI_GATE_X:
- case PSI_GATE_Y:
- case PSI_GATE_Z:
- case PSI_GATE_S:
- case PSI_GATE_T:
- case PSI_GATE_SDG:
- 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: return true;
- default: return false;
- }
+ switch (kind)
+ {
+ case PSI_GATE_H:
+ case PSI_GATE_X:
+ case PSI_GATE_Y:
+ case PSI_GATE_Z:
+ case PSI_GATE_S:
+ case PSI_GATE_T:
+ case PSI_GATE_SDG:
+ 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: return true;
+ default: return false;
+ }
}
static void single_label(struct PsiGateOp op, char* out, size_t cap)
{
- switch (op.kind)
- {
- case PSI_GATE_H: snprintf(out, cap, "[H]"); break;
- case PSI_GATE_X: snprintf(out, cap, "[X]"); break;
- case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break;
- case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break;
- case PSI_GATE_S: snprintf(out, cap, "[S]"); break;
- case PSI_GATE_T: snprintf(out, cap, "[T]"); break;
- case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break;
- case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break;
- case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break;
- case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break;
- case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break;
- case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break;
- case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break;
- case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break;
- case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break;
- case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break;
- case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break;
- default: snprintf(out, cap, "[?]"); break;
- }
+ switch (op.kind)
+ {
+ case PSI_GATE_H: snprintf(out, cap, "[H]"); break;
+ case PSI_GATE_X: snprintf(out, cap, "[X]"); break;
+ case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break;
+ case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break;
+ case PSI_GATE_S: snprintf(out, cap, "[S]"); break;
+ case PSI_GATE_T: snprintf(out, cap, "[T]"); break;
+ case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break;
+ case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break;
+ case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break;
+ case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break;
+ case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break;
+ case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break;
+ case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break;
+ case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break;
+ case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break;
+ case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break;
+ case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break;
+ default: snprintf(out, cap, "[?]"); break;
+ }
}
static void controlled_label(struct PsiGateOp op, char* out, size_t cap)
{
- switch (op.kind)
- {
- case PSI_GATE_CRX: snprintf(out, cap, "[CRx(%.2f)]", op.params[0]); break;
- case PSI_GATE_CRY: snprintf(out, cap, "[CRy(%.2f)]", op.params[0]); break;
- case PSI_GATE_CRZ: snprintf(out, cap, "[CRz(%.2f)]", op.params[0]); break;
- case PSI_GATE_CP: snprintf(out, cap, "[CP(%.2f)]", op.params[0]); break;
- default: snprintf(out, cap, "[?]"); break;
- }
+ switch (op.kind)
+ {
+ case PSI_GATE_CRX: snprintf(out, cap, "[CRx(%.2f)]", op.params[0]); break;
+ case PSI_GATE_CRY: snprintf(out, cap, "[CRy(%.2f)]", op.params[0]); break;
+ case PSI_GATE_CRZ: snprintf(out, cap, "[CRz(%.2f)]", op.params[0]); break;
+ case PSI_GATE_CP: snprintf(out, cap, "[CP(%.2f)]", op.params[0]); break;
+ default: snprintf(out, cap, "[?]"); break;
+ }
}
static bool is_param_controlled(enum PsiGateKind kind)
{
- switch (kind)
- {
- case PSI_GATE_CRX:
- case PSI_GATE_CRY:
- case PSI_GATE_CRZ:
- case PSI_GATE_CP: return true;
- default: return false;
- }
+ switch (kind)
+ {
+ case PSI_GATE_CRX:
+ case PSI_GATE_CRY:
+ case PSI_GATE_CRZ:
+ case PSI_GATE_CP: return true;
+ default: return false;
+ }
}
char* psi_render_circuit_horizontal(const struct PsiQuantumCircuit* circuit)
{
- size_t nq = circuit->num_qubits;
- size_t nc = circuit->num_classical;
+ size_t nq = circuit->num_qubits;
+ size_t nc = circuit->num_classical;
- struct PsiStringBuilder* q = nq > 0 ? malloc(nq * sizeof(struct PsiStringBuilder)) : NULL;
- struct PsiStringBuilder* c = nc > 0 ? malloc(nc * sizeof(struct PsiStringBuilder)) : NULL;
- assert(q != NULL || nq == 0);
- assert(c != NULL || nc == 0);
+ struct PsiStringBuilder* q = nq > 0 ? malloc(nq * sizeof(struct PsiStringBuilder)) : NULL;
+ struct PsiStringBuilder* c = nc > 0 ? malloc(nc * sizeof(struct PsiStringBuilder)) : NULL;
+ assert(q != NULL || nq == 0);
+ assert(c != NULL || nc == 0);
- size_t max_label = 3;
- for (size_t i = 0; i < nq; i++)
- {
- char lbl[16];
- snprintf(lbl, sizeof lbl, "q%zu: ", i);
- if (strlen(lbl) > max_label)
- max_label = strlen(lbl);
- }
- for (size_t i = 0; i < nc; i++)
- {
- char lbl[16];
- snprintf(lbl, sizeof lbl, "c%zu: ", i);
- if (strlen(lbl) > max_label)
- max_label = strlen(lbl);
- }
+ size_t max_label = 3;
+ for (size_t i = 0; i < nq; i++)
+ {
+ char lbl[16];
+ snprintf(lbl, sizeof lbl, "q%zu: ", i);
+ if (strlen(lbl) > max_label)
+ max_label = strlen(lbl);
+ }
+ for (size_t i = 0; i < nc; i++)
+ {
+ char lbl[16];
+ snprintf(lbl, sizeof lbl, "c%zu: ", i);
+ if (strlen(lbl) > max_label)
+ max_label = strlen(lbl);
+ }
- for (size_t i = 0; i < nq; i++)
- {
- q[i] = psi_new_string_builder();
- char lbl[16];
- snprintf(lbl, sizeof lbl, "q%zu: ", i);
- append_repeat(&q[i], " ", max_label - strlen(lbl));
- psi_string_builder_append(&q[i], lbl);
- }
- for (size_t i = 0; i < nc; i++)
- {
- c[i] = psi_new_string_builder();
- char lbl[16];
- snprintf(lbl, sizeof lbl, "c%zu: ", i);
- append_repeat(&c[i], " ", max_label - strlen(lbl));
- psi_string_builder_append(&c[i], lbl);
- }
+ for (size_t i = 0; i < nq; i++)
+ {
+ q[i] = psi_new_string_builder();
+ char lbl[16];
+ snprintf(lbl, sizeof lbl, "q%zu: ", i);
+ append_repeat(&q[i], " ", max_label - strlen(lbl));
+ psi_string_builder_append(&q[i], lbl);
+ }
+ for (size_t i = 0; i < nc; i++)
+ {
+ c[i] = psi_new_string_builder();
+ char lbl[16];
+ snprintf(lbl, sizeof lbl, "c%zu: ", i);
+ append_repeat(&c[i], " ", max_label - strlen(lbl));
+ psi_string_builder_append(&c[i], lbl);
+ }
- struct PsiStringBuilder gap = psi_new_string_builder();
- append_repeat(&gap, " ", max_label);
+ struct PsiStringBuilder gap = psi_new_string_builder();
+ append_repeat(&gap, " ", max_label);
- if (circuit->operation_count == 0)
- {
- for (size_t i = 0; i < nq; i++)
- psi_string_builder_append(&q[i], "───");
- for (size_t i = 0; i < nc; i++)
- psi_string_builder_append(&c[i], "═══");
- psi_string_builder_append(&gap, " ");
- }
+ if (circuit->operation_count == 0)
+ {
+ for (size_t i = 0; i < nq; i++)
+ psi_string_builder_append(&q[i], "───");
+ for (size_t i = 0; i < nc; i++)
+ psi_string_builder_append(&c[i], "═══");
+ psi_string_builder_append(&gap, " ");
+ }
- for (size_t oi = 0; oi < circuit->operation_count; oi++)
- {
- struct PsiGateOp op = circuit->operations[oi];
+ for (size_t oi = 0; oi < circuit->operation_count; oi++)
+ {
+ struct PsiGateOp op = circuit->operations[oi];
- size_t tc;
- const size_t* targets = psi_gate_op_quantum_targets(&op, &tc);
- size_t min_q = targets[0];
- size_t max_q = targets[0];
- for (size_t k = 1; k < tc; k++)
- {
- if (targets[k] < min_q)
- min_q = targets[k];
- if (targets[k] > max_q)
- max_q = targets[k];
- }
+ size_t tc;
+ const size_t* targets = psi_gate_op_quantum_targets(&op, &tc);
+ size_t min_q = targets[0];
+ size_t max_q = targets[0];
+ for (size_t k = 1; k < tc; k++)
+ {
+ if (targets[k] < min_q)
+ min_q = targets[k];
+ if (targets[k] > max_q)
+ max_q = targets[k];
+ }
- if (is_single_target(op.kind))
- {
- char label[64];
- single_label(op, label, sizeof label);
- size_t w = psi_utf8_count(label);
- size_t t = op.qubits[0];
+ if (is_single_target(op.kind))
+ {
+ char label[64];
+ single_label(op, label, sizeof label);
+ size_t w = psi_utf8_count(label);
+ size_t t = op.qubits[0];
- for (size_t i = 0; i < nq; i++)
- {
- if (i == t)
- {
- psi_string_builder_append(&q[i], "─");
- psi_string_builder_append(&q[i], label);
- psi_string_builder_append(&q[i], "─");
- }
- else
- append_repeat(&q[i], "─", w + 2);
- }
- for (size_t i = 0; i < nc; i++)
- append_repeat(&c[i], "═", w + 2);
- append_repeat(&gap, " ", w + 2);
- }
- else if (is_param_controlled(op.kind))
- {
- char label[64];
- controlled_label(op, label, sizeof label);
- size_t w = psi_utf8_count(label);
- size_t control = op.qubits[0];
- size_t target = op.qubits[1];
+ for (size_t i = 0; i < nq; i++)
+ {
+ if (i == t)
+ {
+ psi_string_builder_append(&q[i], "─");
+ psi_string_builder_append(&q[i], label);
+ psi_string_builder_append(&q[i], "─");
+ }
+ else
+ append_repeat(&q[i], "─", w + 2);
+ }
+ for (size_t i = 0; i < nc; i++)
+ append_repeat(&c[i], "═", w + 2);
+ append_repeat(&gap, " ", w + 2);
+ }
+ else if (is_param_controlled(op.kind))
+ {
+ char label[64];
+ controlled_label(op, label, sizeof label);
+ size_t w = psi_utf8_count(label);
+ size_t control = op.qubits[0];
+ size_t target = op.qubits[1];
- for (size_t i = 0; i < nq; i++)
- {
- psi_string_builder_append(&q[i], "─");
- if (i == control)
- {
- psi_string_builder_append(&q[i], "●");
- append_repeat(&q[i], "─", w - 1);
- }
- else if (i == target)
- psi_string_builder_append(&q[i], label);
- else if (i > min_q && i < max_q)
- {
- psi_string_builder_append(&q[i], "│");
- append_repeat(&q[i], "─", w - 1);
- }
- else
- append_repeat(&q[i], "─", w);
- psi_string_builder_append(&q[i], "─");
- }
- for (size_t i = 0; i < nc; i++)
- append_repeat(&c[i], "═", w + 2);
- append_repeat(&gap, " ", w + 2);
- }
- else if (op.kind == PSI_GATE_CNOT || op.kind == PSI_GATE_CZ || op.kind == PSI_GATE_SWAP ||
- op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP)
- {
- for (size_t i = 0; i < nq; i++)
- {
- const char* seg = "─────";
+ for (size_t i = 0; i < nq; i++)
+ {
+ psi_string_builder_append(&q[i], "─");
+ if (i == control)
+ {
+ psi_string_builder_append(&q[i], "●");
+ append_repeat(&q[i], "─", w - 1);
+ }
+ else if (i == target)
+ psi_string_builder_append(&q[i], label);
+ else if (i > min_q && i < max_q)
+ {
+ psi_string_builder_append(&q[i], "│");
+ append_repeat(&q[i], "─", w - 1);
+ }
+ else
+ append_repeat(&q[i], "─", w);
+ psi_string_builder_append(&q[i], "─");
+ }
+ for (size_t i = 0; i < nc; i++)
+ append_repeat(&c[i], "═", w + 2);
+ append_repeat(&gap, " ", w + 2);
+ }
+ else if (op.kind == PSI_GATE_CNOT || op.kind == PSI_GATE_CZ || op.kind == PSI_GATE_SWAP ||
+ op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP)
+ {
+ for (size_t i = 0; i < nq; i++)
+ {
+ const char* seg = "─────";
- switch (op.kind)
- {
- case PSI_GATE_CNOT:
- if (i == op.qubits[0])
- seg = "──●──";
- else if (i == op.qubits[1])
- seg = "──⊕──";
- else if (i > min_q && i < max_q)
- seg = "──│──";
- break;
- case PSI_GATE_CZ:
- if (i == op.qubits[0] || i == op.qubits[1])
- seg = "──●──";
- else if (i > min_q && i < max_q)
- seg = "──│──";
- break;
- case PSI_GATE_SWAP:
- if (i == op.qubits[0] || i == op.qubits[1])
- seg = "──╳──";
- else if (i > min_q && i < max_q)
- seg = "──│──";
- break;
- case PSI_GATE_CCNOT:
- if (i == op.qubits[0] || i == op.qubits[1])
- seg = "──●──";
- else if (i == op.qubits[2])
- seg = "──⊕──";
- else if (i > min_q && i < max_q)
- seg = "──│──";
- break;
- case PSI_GATE_CSWAP:
- if (i == op.qubits[0])
- seg = "──●──";
- else if (i == op.qubits[1] || i == op.qubits[2])
- seg = "──╳──";
- else if (i > min_q && i < max_q)
- seg = "──│──";
- break;
- default: break;
- }
+ switch (op.kind)
+ {
+ case PSI_GATE_CNOT:
+ if (i == op.qubits[0])
+ seg = "──●──";
+ else if (i == op.qubits[1])
+ seg = "──⊕──";
+ else if (i > min_q && i < max_q)
+ seg = "──│──";
+ break;
+ case PSI_GATE_CZ:
+ if (i == op.qubits[0] || i == op.qubits[1])
+ seg = "──●──";
+ else if (i > min_q && i < max_q)
+ seg = "──│──";
+ break;
+ case PSI_GATE_SWAP:
+ if (i == op.qubits[0] || i == op.qubits[1])
+ seg = "──╳──";
+ else if (i > min_q && i < max_q)
+ seg = "──│──";
+ break;
+ case PSI_GATE_CCNOT:
+ if (i == op.qubits[0] || i == op.qubits[1])
+ seg = "──●──";
+ else if (i == op.qubits[2])
+ seg = "──⊕──";
+ else if (i > min_q && i < max_q)
+ seg = "──│──";
+ break;
+ case PSI_GATE_CSWAP:
+ if (i == op.qubits[0])
+ seg = "──●──";
+ else if (i == op.qubits[1] || i == op.qubits[2])
+ seg = "──╳──";
+ else if (i > min_q && i < max_q)
+ seg = "──│──";
+ break;
+ default: break;
+ }
- psi_string_builder_append(&q[i], seg);
- }
- for (size_t i = 0; i < nc; i++)
- psi_string_builder_append(&c[i], "═════");
- psi_string_builder_append(&gap, " ");
- }
- else if (op.kind == PSI_GATE_MEASURE)
- {
- size_t mq = op.qubits[0];
- size_t mc = op.classical;
+ psi_string_builder_append(&q[i], seg);
+ }
+ for (size_t i = 0; i < nc; i++)
+ psi_string_builder_append(&c[i], "═════");
+ psi_string_builder_append(&gap, " ");
+ }
+ else if (op.kind == PSI_GATE_MEASURE)
+ {
+ size_t mq = op.qubits[0];
+ size_t mc = op.classical;
- for (size_t i = 0; i < nq; i++)
- {
- if (i == mq)
- psi_string_builder_append(&q[i], "─[M]─");
- else if (i > mq)
- psi_string_builder_append(&q[i], "──║──");
- else
- psi_string_builder_append(&q[i], "─────");
- }
- for (size_t i = 0; i < nc; i++)
- {
- if (i == mc)
- psi_string_builder_append(&c[i], "══╩══");
- else if (i < mc)
- psi_string_builder_append(&c[i], "══║══");
- else
- psi_string_builder_append(&c[i], "═════");
- }
- psi_string_builder_append(&gap, " ║ ");
- }
- else
- {
- char label[64];
- snprintf(label, sizeof label, "[%s]", op.custom->name);
- size_t w = psi_utf8_count(label);
+ for (size_t i = 0; i < nq; i++)
+ {
+ if (i == mq)
+ psi_string_builder_append(&q[i], "─[M]─");
+ else if (i > mq)
+ psi_string_builder_append(&q[i], "──║──");
+ else
+ psi_string_builder_append(&q[i], "─────");
+ }
+ for (size_t i = 0; i < nc; i++)
+ {
+ if (i == mc)
+ psi_string_builder_append(&c[i], "══╩══");
+ else if (i < mc)
+ psi_string_builder_append(&c[i], "══║══");
+ else
+ psi_string_builder_append(&c[i], "═════");
+ }
+ psi_string_builder_append(&gap, " ║ ");
+ }
+ else
+ {
+ char label[64];
+ snprintf(label, sizeof label, "[%s]", op.custom->name);
+ size_t w = psi_utf8_count(label);
- for (size_t i = 0; i < nq; i++)
- {
- bool is_target = false;
- for (size_t k = 0; k < tc; k++)
- if (targets[k] == i)
- is_target = true;
+ for (size_t i = 0; i < nq; i++)
+ {
+ bool is_target = false;
+ for (size_t k = 0; k < tc; k++)
+ if (targets[k] == i)
+ is_target = true;
- psi_string_builder_append(&q[i], "─");
- if (is_target && i == targets[0])
- psi_string_builder_append(&q[i], label);
- else if (is_target)
- append_repeat(&q[i], "─", w);
- else if (i > min_q && i < max_q)
- {
- psi_string_builder_append(&q[i], "│");
- append_repeat(&q[i], "─", w - 1);
- }
- else
- append_repeat(&q[i], "─", w);
- psi_string_builder_append(&q[i], "─");
- }
- for (size_t i = 0; i < nc; i++)
- append_repeat(&c[i], "═", w + 2);
- append_repeat(&gap, " ", w + 2);
- }
- }
+ psi_string_builder_append(&q[i], "─");
+ if (is_target && i == targets[0])
+ psi_string_builder_append(&q[i], label);
+ else if (is_target)
+ append_repeat(&q[i], "─", w);
+ else if (i > min_q && i < max_q)
+ {
+ psi_string_builder_append(&q[i], "│");
+ append_repeat(&q[i], "─", w - 1);
+ }
+ else
+ append_repeat(&q[i], "─", w);
+ psi_string_builder_append(&q[i], "─");
+ }
+ for (size_t i = 0; i < nc; i++)
+ append_repeat(&c[i], "═", w + 2);
+ append_repeat(&gap, " ", w + 2);
+ }
+ }
- struct PsiStringBuilder out = psi_new_string_builder();
+ struct PsiStringBuilder out = psi_new_string_builder();
- for (size_t i = 0; i < nq; i++)
- {
- psi_string_builder_append(&out, psi_string_builder_finish(&q[i]));
- psi_string_builder_append(&out, "░\n");
- free(q[i].data);
- }
+ for (size_t i = 0; i < nq; i++)
+ {
+ psi_string_builder_append(&out, psi_string_builder_finish(&q[i]));
+ psi_string_builder_append(&out, "░\n");
+ free(q[i].data);
+ }
- if (nc > 0)
- {
- psi_string_builder_append(&out, psi_string_builder_finish(&gap));
- psi_string_builder_append(&out, "░\n");
- for (size_t i = 0; i < nc; i++)
- {
- psi_string_builder_append(&out, psi_string_builder_finish(&c[i]));
- psi_string_builder_append(&out, "░\n");
- free(c[i].data);
- }
- }
+ if (nc > 0)
+ {
+ psi_string_builder_append(&out, psi_string_builder_finish(&gap));
+ psi_string_builder_append(&out, "░\n");
+ for (size_t i = 0; i < nc; i++)
+ {
+ psi_string_builder_append(&out, psi_string_builder_finish(&c[i]));
+ psi_string_builder_append(&out, "░\n");
+ free(c[i].data);
+ }
+ }
- free(gap.data);
- free(q);
- free(c);
+ free(gap.data);
+ free(q);
+ free(c);
- return psi_string_builder_finish(&out);
+ return psi_string_builder_finish(&out);
}
diff --git a/src/visualizer/vertical_cli.c b/src/visualizer/vertical_cli.c
index 4f21e49..340a2a5 100644
--- a/src/visualizer/vertical_cli.c
+++ b/src/visualizer/vertical_cli.c
@@ -7,317 +7,317 @@
static void gate_label(struct PsiGateOp op, char* out, size_t cap)
{
- switch (op.kind)
- {
- case PSI_GATE_H: snprintf(out, cap, "[H]"); break;
- case PSI_GATE_X: snprintf(out, cap, "[X]"); break;
- case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break;
- case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break;
- case PSI_GATE_S: snprintf(out, cap, "[S]"); break;
- case PSI_GATE_T: snprintf(out, cap, "[T]"); break;
- case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break;
- case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break;
- case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break;
- case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break;
- case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break;
- case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break;
- case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break;
- case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break;
- case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break;
- case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break;
- case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break;
- case PSI_GATE_CRX: snprintf(out, cap, "[CRx]"); break;
- case PSI_GATE_CRY: snprintf(out, cap, "[CRy]"); break;
- case PSI_GATE_CRZ: snprintf(out, cap, "[CRz]"); break;
- case PSI_GATE_CP: snprintf(out, cap, "[CP]"); break;
- case PSI_GATE_CNOT: snprintf(out, cap, "●"); break;
- case PSI_GATE_CZ: snprintf(out, cap, "●"); break;
- case PSI_GATE_SWAP: snprintf(out, cap, "╳"); break;
- case PSI_GATE_CCNOT: snprintf(out, cap, "●"); break;
- case PSI_GATE_CSWAP: snprintf(out, cap, "●"); break;
- case PSI_GATE_MEASURE: snprintf(out, cap, "[M]"); break;
- case PSI_GATE_CUSTOM: snprintf(out, cap, "[%s]", op.custom->name); break;
- }
+ switch (op.kind)
+ {
+ case PSI_GATE_H: snprintf(out, cap, "[H]"); break;
+ case PSI_GATE_X: snprintf(out, cap, "[X]"); break;
+ case PSI_GATE_Y: snprintf(out, cap, "[Y]"); break;
+ case PSI_GATE_Z: snprintf(out, cap, "[Z]"); break;
+ case PSI_GATE_S: snprintf(out, cap, "[S]"); break;
+ case PSI_GATE_T: snprintf(out, cap, "[T]"); break;
+ case PSI_GATE_SDG: snprintf(out, cap, "[S†]"); break;
+ case PSI_GATE_TDG: snprintf(out, cap, "[T†]"); break;
+ case PSI_GATE_SX: snprintf(out, cap, "[√X]"); break;
+ case PSI_GATE_SXDG: snprintf(out, cap, "[√X†]"); break;
+ case PSI_GATE_RX: snprintf(out, cap, "[Rx(%.2f)]", op.params[0]); break;
+ case PSI_GATE_RY: snprintf(out, cap, "[Ry(%.2f)]", op.params[0]); break;
+ case PSI_GATE_RZ: snprintf(out, cap, "[Rz(%.2f)]", op.params[0]); break;
+ case PSI_GATE_P: snprintf(out, cap, "[P(%.2f)]", op.params[0]); break;
+ case PSI_GATE_U1: snprintf(out, cap, "[U1(%.2f)]", op.params[0]); break;
+ case PSI_GATE_U2: snprintf(out, cap, "[U2]"); break;
+ case PSI_GATE_U3: snprintf(out, cap, "[U3]"); break;
+ case PSI_GATE_CRX: snprintf(out, cap, "[CRx]"); break;
+ case PSI_GATE_CRY: snprintf(out, cap, "[CRy]"); break;
+ case PSI_GATE_CRZ: snprintf(out, cap, "[CRz]"); break;
+ case PSI_GATE_CP: snprintf(out, cap, "[CP]"); break;
+ case PSI_GATE_CNOT: snprintf(out, cap, "●"); break;
+ case PSI_GATE_CZ: snprintf(out, cap, "●"); break;
+ case PSI_GATE_SWAP: snprintf(out, cap, "╳"); break;
+ case PSI_GATE_CCNOT: snprintf(out, cap, "●"); break;
+ case PSI_GATE_CSWAP: snprintf(out, cap, "●"); break;
+ case PSI_GATE_MEASURE: snprintf(out, cap, "[M]"); break;
+ case PSI_GATE_CUSTOM: snprintf(out, cap, "[%s]", op.custom->name); break;
+ }
}
static size_t calculate_col_width(const struct PsiQuantumCircuit* circuit)
{
- size_t max_label = 3;
+ size_t max_label = 3;
- for (size_t i = 0; i < circuit->operation_count; i++)
- {
- char label[64];
- gate_label(circuit->operations[i], label, sizeof label);
- size_t n = psi_utf8_count(label);
- if (n > max_label)
- max_label = n;
- }
+ for (size_t i = 0; i < circuit->operation_count; i++)
+ {
+ char label[64];
+ gate_label(circuit->operations[i], label, sizeof label);
+ size_t n = psi_utf8_count(label);
+ if (n > max_label)
+ max_label = n;
+ }
- size_t width = max_label + 2;
- if (width % 2 == 0)
- return width + 1;
+ size_t width = max_label + 2;
+ if (width % 2 == 0)
+ return width + 1;
- return width;
+ return width;
}
static bool is_single_target(enum PsiGateKind kind)
{
- switch (kind)
- {
- case PSI_GATE_H:
- case PSI_GATE_X:
- case PSI_GATE_Y:
- case PSI_GATE_Z:
- case PSI_GATE_S:
- case PSI_GATE_T:
- case PSI_GATE_SDG:
- 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: return true;
- default: return false;
- }
+ switch (kind)
+ {
+ case PSI_GATE_H:
+ case PSI_GATE_X:
+ case PSI_GATE_Y:
+ case PSI_GATE_Z:
+ case PSI_GATE_S:
+ case PSI_GATE_T:
+ case PSI_GATE_SDG:
+ 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: return true;
+ default: return false;
+ }
}
static bool is_param_controlled(enum PsiGateKind kind)
{
- switch (kind)
- {
- case PSI_GATE_CRX:
- case PSI_GATE_CRY:
- case PSI_GATE_CRZ:
- case PSI_GATE_CP: return true;
- default: return false;
- }
+ switch (kind)
+ {
+ case PSI_GATE_CRX:
+ case PSI_GATE_CRY:
+ case PSI_GATE_CRZ:
+ case PSI_GATE_CP: return true;
+ default: return false;
+ }
}
char* psi_render_circuit_vertical(const struct PsiQuantumCircuit* circuit)
{
- struct PsiStringBuilder sb = psi_new_string_builder();
+ struct PsiStringBuilder sb = psi_new_string_builder();
- size_t nq = circuit->num_qubits;
- size_t nc = circuit->num_classical;
+ size_t nq = circuit->num_qubits;
+ size_t nc = circuit->num_classical;
- if (nq == 0)
- return psi_string_builder_finish(&sb);
+ if (nq == 0)
+ return psi_string_builder_finish(&sb);
- size_t col_width = calculate_col_width(circuit);
- size_t gap_width = 3;
- size_t stride = col_width + 1;
- size_t half = col_width / 2;
+ size_t col_width = calculate_col_width(circuit);
+ size_t gap_width = 3;
+ size_t stride = col_width + 1;
+ size_t half = col_width / 2;
- size_t q_total = nq * col_width + (nq - 1);
- size_t c_total = nc > 0 ? nc * col_width + (nc - 1) : 0;
- size_t total_width = q_total + gap_width + c_total;
+ size_t q_total = nq * col_width + (nq - 1);
+ size_t c_total = nc > 0 ? nc * col_width + (nc - 1) : 0;
+ size_t total_width = q_total + gap_width + c_total;
- struct PsiGlyphRow header = psi_new_glyph_row(total_width);
- for (size_t i = 0; i < nq; i++)
- {
- char label[16];
- snprintf(label, sizeof label, "q%zu", i);
- size_t col_start = i * stride;
- psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label);
- }
- for (size_t i = 0; i < nc; i++)
- {
- char label[16];
- snprintf(label, sizeof label, "c%zu", i);
- size_t col_start = q_total + gap_width + i * stride;
- psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label);
- }
- psi_glyph_row_render(header, &sb);
- psi_free_glyph_row(&header);
+ struct PsiGlyphRow header = psi_new_glyph_row(total_width);
+ for (size_t i = 0; i < nq; i++)
+ {
+ char label[16];
+ snprintf(label, sizeof label, "q%zu", i);
+ size_t col_start = i * stride;
+ psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label);
+ }
+ for (size_t i = 0; i < nc; i++)
+ {
+ char label[16];
+ snprintf(label, sizeof label, "c%zu", i);
+ size_t col_start = q_total + gap_width + i * stride;
+ psi_glyph_row_place(&header, col_start + (col_width - psi_utf8_count(label)) / 2, label);
+ }
+ psi_glyph_row_render(header, &sb);
+ psi_free_glyph_row(&header);
- for (size_t op_index = 0; op_index <= circuit->operation_count; op_index++)
- {
- struct PsiGlyphRow wires = psi_new_glyph_row(total_width);
- for (size_t i = 0; i < nq; i++)
- psi_glyph_row_set(&wires, i * stride + half, "│");
- for (size_t i = 0; i < nc; i++)
- psi_glyph_row_set(&wires, q_total + gap_width + i * stride + half, "║");
- psi_glyph_row_render(wires, &sb);
- psi_free_glyph_row(&wires);
+ for (size_t op_index = 0; op_index <= circuit->operation_count; op_index++)
+ {
+ struct PsiGlyphRow wires = psi_new_glyph_row(total_width);
+ for (size_t i = 0; i < nq; i++)
+ psi_glyph_row_set(&wires, i * stride + half, "│");
+ for (size_t i = 0; i < nc; i++)
+ psi_glyph_row_set(&wires, q_total + gap_width + i * stride + half, "║");
+ psi_glyph_row_render(wires, &sb);
+ psi_free_glyph_row(&wires);
- if (op_index == circuit->operation_count)
- break;
+ if (op_index == circuit->operation_count)
+ break;
- struct PsiGateOp op = circuit->operations[op_index];
+ struct PsiGateOp op = circuit->operations[op_index];
- size_t target_count;
- const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count);
- size_t min_q = targets[0];
- size_t max_q = targets[0];
- for (size_t i = 1; i < target_count; i++)
- {
- if (targets[i] < min_q)
- min_q = targets[i];
- if (targets[i] > max_q)
- max_q = targets[i];
- }
+ size_t target_count;
+ const size_t* targets = psi_gate_op_quantum_targets(&op, &target_count);
+ size_t min_q = targets[0];
+ size_t max_q = targets[0];
+ for (size_t i = 1; i < target_count; i++)
+ {
+ if (targets[i] < min_q)
+ min_q = targets[i];
+ if (targets[i] > max_q)
+ max_q = targets[i];
+ }
- char label[64];
- gate_label(op, label, sizeof label);
- size_t label_len = psi_utf8_count(label);
+ char label[64];
+ gate_label(op, label, sizeof label);
+ size_t label_len = psi_utf8_count(label);
- struct PsiGlyphRow row = psi_new_glyph_row(total_width);
+ struct PsiGlyphRow row = psi_new_glyph_row(total_width);
- if (is_single_target(op.kind))
- {
- size_t target = op.qubits[0];
- for (size_t i = 0; i < nq; i++)
- {
- size_t col_start = i * stride;
- if (i == target)
- psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
- else
- psi_glyph_row_set(&row, col_start + half, "│");
- }
- for (size_t i = 0; i < nc; i++)
- psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
- }
- else if (op.kind == PSI_GATE_MEASURE)
- {
- size_t mq = op.qubits[0];
- size_t mc = op.classical;
- for (size_t i = 0; i < nq; i++)
- {
- size_t col_start = i * stride;
- if (i < mq)
- psi_glyph_row_set(&row, col_start + half, "│");
- else if (i == mq)
- psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
- }
+ if (is_single_target(op.kind))
+ {
+ size_t target = op.qubits[0];
+ for (size_t i = 0; i < nq; i++)
+ {
+ size_t col_start = i * stride;
+ if (i == target)
+ psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
+ else
+ psi_glyph_row_set(&row, col_start + half, "│");
+ }
+ for (size_t i = 0; i < nc; i++)
+ psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
+ }
+ else if (op.kind == PSI_GATE_MEASURE)
+ {
+ size_t mq = op.qubits[0];
+ size_t mc = op.classical;
+ for (size_t i = 0; i < nq; i++)
+ {
+ size_t col_start = i * stride;
+ if (i < mq)
+ psi_glyph_row_set(&row, col_start + half, "│");
+ else if (i == mq)
+ psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
+ }
- size_t mq_center = mq * stride + half;
- size_t mc_start = q_total + gap_width;
- size_t mc_center = mc_start + mc * stride + half;
+ size_t mq_center = mq * stride + half;
+ size_t mc_start = q_total + gap_width;
+ size_t mc_center = mc_start + mc * stride + half;
- psi_glyph_row_fill_space(&row, mq_center + 2, mc_center + 1, "═");
- psi_glyph_row_set(&row, mc_center, "╣");
+ psi_glyph_row_fill_space(&row, mq_center + 2, mc_center + 1, "═");
+ psi_glyph_row_set(&row, mc_center, "╣");
- for (size_t i = 0; i < nc; i++)
- if (i > mc)
- psi_glyph_row_set(&row, mc_start + i * stride + half, "║");
- }
- else if (op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP)
- {
- bool is_cswap = op.kind == PSI_GATE_CSWAP;
- const char* sym_c = "●";
- const char* sym_t = is_cswap ? "╳" : "⊕";
- size_t c1 = op.qubits[0];
- size_t c2 = op.qubits[1];
- size_t t = op.qubits[2];
+ for (size_t i = 0; i < nc; i++)
+ if (i > mc)
+ psi_glyph_row_set(&row, mc_start + i * stride + half, "║");
+ }
+ else if (op.kind == PSI_GATE_CCNOT || op.kind == PSI_GATE_CSWAP)
+ {
+ bool is_cswap = op.kind == PSI_GATE_CSWAP;
+ const char* sym_c = "●";
+ const char* sym_t = is_cswap ? "╳" : "⊕";
+ size_t c1 = op.qubits[0];
+ size_t c2 = op.qubits[1];
+ size_t t = op.qubits[2];
- for (size_t i = 0; i < nq; i++)
- {
- size_t center = i * stride + half;
- if (i < min_q || i > max_q)
- psi_glyph_row_set(&row, center, "│");
- else if (i == c1)
- psi_glyph_row_set(&row, center, sym_c);
- else if (i == c2)
- psi_glyph_row_set(&row, center, is_cswap ? sym_t : sym_c);
- else if (i == t)
- psi_glyph_row_set(&row, center, sym_t);
- }
+ for (size_t i = 0; i < nq; i++)
+ {
+ size_t center = i * stride + half;
+ if (i < min_q || i > max_q)
+ psi_glyph_row_set(&row, center, "│");
+ else if (i == c1)
+ psi_glyph_row_set(&row, center, sym_c);
+ else if (i == c2)
+ psi_glyph_row_set(&row, center, is_cswap ? sym_t : sym_c);
+ else if (i == t)
+ psi_glyph_row_set(&row, center, sym_t);
+ }
- psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─");
- for (size_t i = 0; i < nc; i++)
- psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
- }
- else if (op.kind == PSI_GATE_CUSTOM)
- {
- if (target_count == 1)
- {
- for (size_t i = 0; i < nq; i++)
- {
- size_t col_start = i * stride;
- if (i == targets[0])
- psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
- else
- psi_glyph_row_set(&row, col_start + half, "│");
- }
- }
- else
- {
- for (size_t i = 0; i < nq; i++)
- {
- size_t col_start = i * stride;
- size_t center = col_start + half;
- bool is_target = false;
- for (size_t k = 0; k < target_count; k++)
- if (targets[k] == i)
- is_target = true;
+ psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─");
+ for (size_t i = 0; i < nc; i++)
+ psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
+ }
+ else if (op.kind == PSI_GATE_CUSTOM)
+ {
+ if (target_count == 1)
+ {
+ for (size_t i = 0; i < nq; i++)
+ {
+ size_t col_start = i * stride;
+ if (i == targets[0])
+ psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
+ else
+ psi_glyph_row_set(&row, col_start + half, "│");
+ }
+ }
+ else
+ {
+ for (size_t i = 0; i < nq; i++)
+ {
+ size_t col_start = i * stride;
+ size_t center = col_start + half;
+ bool is_target = false;
+ for (size_t k = 0; k < target_count; k++)
+ if (targets[k] == i)
+ is_target = true;
- if (i < min_q || i > max_q)
- psi_glyph_row_set(&row, center, "│");
- else if (i == targets[0])
- psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
- else if (is_target)
- psi_glyph_row_set(&row, center, "□");
- }
+ if (i < min_q || i > max_q)
+ psi_glyph_row_set(&row, center, "│");
+ else if (i == targets[0])
+ psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
+ else if (is_target)
+ psi_glyph_row_set(&row, center, "□");
+ }
- psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half,
- "─");
- }
+ psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half,
+ "─");
+ }
- for (size_t i = 0; i < nc; i++)
- psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
- }
- else
- {
- const char* sym1 = "●";
- const char* sym2 = "⊕";
- if (op.kind == PSI_GATE_CZ)
- sym2 = "●";
- else if (op.kind == PSI_GATE_SWAP)
- {
- sym1 = "╳";
- sym2 = "╳";
- }
- else if (is_param_controlled(op.kind))
- sym2 = "□";
+ for (size_t i = 0; i < nc; i++)
+ psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
+ }
+ else
+ {
+ const char* sym1 = "●";
+ const char* sym2 = "⊕";
+ if (op.kind == PSI_GATE_CZ)
+ sym2 = "●";
+ else if (op.kind == PSI_GATE_SWAP)
+ {
+ sym1 = "╳";
+ sym2 = "╳";
+ }
+ else if (is_param_controlled(op.kind))
+ sym2 = "□";
- size_t control = op.qubits[0];
- size_t target = op.qubits[1];
+ size_t control = op.qubits[0];
+ size_t target = op.qubits[1];
- for (size_t i = 0; i < nq; i++)
- {
- size_t col_start = i * stride;
- size_t center = col_start + half;
- if (i < min_q || i > max_q)
- psi_glyph_row_set(&row, center, "│");
- else if (i == control)
- psi_glyph_row_set(&row, center, sym1);
- else if (i == target)
- {
- if (is_param_controlled(op.kind))
- psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
- else
- psi_glyph_row_set(&row, center, sym2);
- }
- }
+ for (size_t i = 0; i < nq; i++)
+ {
+ size_t col_start = i * stride;
+ size_t center = col_start + half;
+ if (i < min_q || i > max_q)
+ psi_glyph_row_set(&row, center, "│");
+ else if (i == control)
+ psi_glyph_row_set(&row, center, sym1);
+ else if (i == target)
+ {
+ if (is_param_controlled(op.kind))
+ psi_glyph_row_place(&row, col_start + (col_width - label_len) / 2, label);
+ else
+ psi_glyph_row_set(&row, center, sym2);
+ }
+ }
- psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─");
- for (size_t i = 0; i < nc; i++)
- psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
- }
+ psi_glyph_row_fill_space(&row, min_q * stride + half + 1, max_q * stride + half, "─");
+ for (size_t i = 0; i < nc; i++)
+ psi_glyph_row_set(&row, q_total + gap_width + i * stride + half, "║");
+ }
- psi_glyph_row_render(row, &sb);
- psi_free_glyph_row(&row);
- }
+ psi_glyph_row_render(row, &sb);
+ psi_free_glyph_row(&row);
+ }
- struct PsiGlyphRow end_row = psi_new_glyph_row(total_width);
- for (size_t i = 0; i < total_width; i++)
- psi_glyph_row_set(&end_row, i, "░");
- psi_glyph_row_render(end_row, &sb);
- psi_free_glyph_row(&end_row);
+ struct PsiGlyphRow end_row = psi_new_glyph_row(total_width);
+ for (size_t i = 0; i < total_width; i++)
+ psi_glyph_row_set(&end_row, i, "░");
+ psi_glyph_row_render(end_row, &sb);
+ psi_free_glyph_row(&end_row);
- return psi_string_builder_finish(&sb);
+ return psi_string_builder_finish(&sb);
}