diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/circuit.c | 454 | ||||
| -rw-r--r-- | src/core/circuit.rs | 477 | ||||
| -rw-r--r-- | src/core/classical_components.c | 32 | ||||
| -rw-r--r-- | src/core/custom_gate.c | 202 | ||||
| -rw-r--r-- | src/core/gates.c | 244 | ||||
| -rw-r--r-- | src/core/kernel.c | 772 | ||||
| -rw-r--r-- | src/core/noise.c | 532 | ||||
| -rw-r--r-- | src/core/quantum_components.c | 318 | ||||
| -rw-r--r-- | src/core/runtime.c | 456 |
9 files changed, 1535 insertions, 1952 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(&))?; - } - } - } 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(®->state_vector); + psi_free_vector(®->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(®); - return reg; + update_register(®); + 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(®); - return reg; + update_register(®); + return reg; } void psi_free_quantum_register(struct PsiQuantumRegister* reg) { - for (size_t i = 0; i < reg->num_qubits; i++) - psi_free_quantum_bit(®->qubits[i]); + for (size_t i = 0; i < reg->num_qubits; i++) + psi_free_quantum_bit(®->qubits[i]); - free(reg->qubits); - reg->qubits = NULL; - reg->num_qubits = 0; - psi_free_vector(®->state_vector); + free(reg->qubits); + reg->qubits = NULL; + reg->num_qubits = 0; + psi_free_vector(®->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(®->state_vector); - psi_free_matrix(&full_operator); - reg->state_vector = new_state; + psi_free_vector(®->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]); } |
