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