diff options
| -rw-r--r-- | include/core/custom_gate.h | 56 | ||||
| -rw-r--r-- | src/core/custom_gate.c | 160 | ||||
| -rw-r--r-- | tester/main.c | 20 |
3 files changed, 236 insertions, 0 deletions
diff --git a/include/core/custom_gate.h b/include/core/custom_gate.h new file mode 100644 index 0000000..bc22956 --- /dev/null +++ b/include/core/custom_gate.h @@ -0,0 +1,56 @@ +#pragma once + +#include <stddef.h> + +#include "core/quantum_components.h" +#include "maths/matrix.h" + +enum PsiCompositeOp +{ + PSI_OP_H, + PSI_OP_X, + PSI_OP_Y, + PSI_OP_Z, + PSI_OP_S, + PSI_OP_T, + PSI_OP_CNOT, + PSI_OP_CZ, + PSI_OP_SWAP, + PSI_OP_CCNOT, + PSI_OP_CSWAP, +}; + +struct PsiCompositeGateOp +{ + enum PsiCompositeOp op; + size_t targets[3]; + size_t target_count; +}; + +enum PsiCustomGateKind +{ + PSI_CUSTOM_GATE_MATRIX, + PSI_CUSTOM_GATE_COMPOSITE, +}; + +struct PsiCustomGate +{ + const char *name; + size_t num_qubits; + enum PsiCustomGateKind kind; + union + { + struct PsiMatrix matrix; + struct + { + struct PsiCompositeGateOp *ops; + size_t count; + } composite; + } definition; +}; + +struct PsiCustomGate psi_new_custom_gate_from_matrix(const char *name, struct PsiMatrix matrix); +struct PsiCustomGate psi_new_custom_gate_from_composite(const char *name, size_t num_qubits, const struct PsiCompositeGateOp *ops, size_t op_count); +void psi_free_custom_gate(struct PsiCustomGate *gate); + +struct PsiQuantumGate psi_to_quantum_gate(struct PsiCustomGate gate); diff --git a/src/core/custom_gate.c b/src/core/custom_gate.c new file mode 100644 index 0000000..3b3a7e2 --- /dev/null +++ b/src/core/custom_gate.c @@ -0,0 +1,160 @@ +#include "core/custom_gate.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include "core/gates.h" + +struct PsiCustomGate psi_new_custom_gate_from_matrix(const char *name, struct PsiMatrix matrix) +{ + assert(matrix.rows == matrix.cols); + + 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++; + + struct PsiCustomGate gate; + gate.name = name; + gate.num_qubits = num_qubits; + gate.kind = PSI_CUSTOM_GATE_MATRIX; + gate.definition.matrix = matrix; + + 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); + + 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; + + return gate; +} + +void psi_free_custom_gate(struct PsiCustomGate *gate) +{ + 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; +} + +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(); + } + + 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; + } + + 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; + + 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 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; + } + } + + if (match_non_targets) + result.data[i * dim + j] = gate_matrix.data[gate_i * gate_dim + gate_j]; + } + + 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); + + 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); + + psi_free_matrix(&full); + psi_free_matrix(&result); + psi_free_quantum_gate(&g); + result = next; + } + + 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); + + return psi_new_quantum_gate(gate.name, compute_composite_matrix(gate), gate.num_qubits); +} diff --git a/tester/main.c b/tester/main.c index cc32de1..e401288 100644 --- a/tester/main.c +++ b/tester/main.c @@ -1,5 +1,6 @@ #include <stdio.h> +#include "core/custom_gate.h" #include "core/gates.h" #include "core/quantum_components.h" #include "maths/complex.h" @@ -97,5 +98,24 @@ int main(void) psi_free_quantum_gate(&cnot); psi_free_quantum_register(®); + struct PsiCompositeGateOp bell_ops[] = { + { PSI_OP_H, { 0 }, 1 }, + { PSI_OP_CNOT, { 0, 1 }, 2 }, + }; + struct PsiCustomGate bell = psi_new_custom_gate_from_composite("BELL", 2, bell_ops, 2); + struct PsiQuantumGate bell_gate = psi_to_quantum_gate(bell); + + struct PsiQuantumRegister reg2 = psi_new_quantum_register("bell2", names, 2); + size_t t01b[] = { 0, 1 }; + psi_apply_gate(®2, bell_gate, t01b, 2); + + printf("custom = %s -> [%g, %g, %g, %g]\n", bell_gate.name, + reg2.state_vector.data[0].real, reg2.state_vector.data[1].real, + reg2.state_vector.data[2].real, reg2.state_vector.data[3].real); + + psi_free_custom_gate(&bell); + psi_free_quantum_gate(&bell_gate); + psi_free_quantum_register(®2); + return 0; } |
