package bob_quantum // BOB Quantum Civilization Engine - Odin Bindings // VR-optimized quantum simulation for game engines // High-performance lattice visualization and real-time evolution import "core:c" import "core:math" import "core:mem" import "core:slice" // ========================================================================= // Constants // ========================================================================= ERROR_NONE :: 0 ERROR_MEMORY_ALLOCATION_FAILED :: 1 ERROR_INVALID_PARAMETER :: 2 ERROR_INTERNAL_ERROR :: 3 ERROR_NOT_IMPLEMENTED :: 4 ERROR_FILE_IO_ERROR :: 5 ERROR_UNKNOWN_ERROR :: 6 // Gate type codes GATE_H :: 0 GATE_X :: 1 GATE_Y :: 2 GATE_Z :: 3 GATE_S :: 4 GATE_T :: 5 GATE_RX :: 6 GATE_RY :: 7 GATE_RZ :: 8 GATE_CX :: 9 GATE_CY :: 10 GATE_CZ :: 11 // Initial state codes INITIAL_ZERO :: 0 INITIAL_PLUS :: 1 INITIAL_RANDOM :: 2 // Hamiltonian type codes HAM_SPARSE :: 0 HAM_DENSE :: 1 HAM_MPO :: 2 // ========================================================================= // FFI Types // ========================================================================= RNG_Handle :: distinct rawptr Lattice_Handle :: distinct rawptr State_Handle :: distinct rawptr Hamiltonian_Handle :: distinct rawptr Quantum_Error :: enum { None, MemoryAllocationFailed, InvalidParameter, InternalError, NotImplemented, FileIOError, UnknownError, } // ========================================================================= // FFI Foreign Declarations // ========================================================================= @(default_calling_convention="c") foreign "libbob_quantum" { // RNG functions bob_rng_create :: proc(rng: ^RNG_Handle) -> c.int --- bob_rng_destroy :: proc(rng: RNG_Handle) -> c.int --- bob_rng_seed :: proc(rng: RNG_Handle, seed: c.uint64_t) -> c.int --- bob_rng_uniform :: proc(rng: RNG_Handle, value: ^f64) -> c.int --- bob_rng_normal :: proc(rng: RNG_Handle, value: ^f64) -> c.int --- bob_rng_integer :: proc(rng: RNG_Handle, min: c.int64_t, max: c.int64_t, value: ^c.int64_t) -> c.int --- // Lattice functions bob_lattice_create :: proc(nx: c.int, ny: c.int, nz: c.int, coupling: f64, seed: c.uint64_t, lat: ^Lattice_Handle) -> c.int --- bob_lattice_destroy :: proc(lat: Lattice_Handle) -> c.int --- bob_lattice_evolve :: proc(lat: Lattice_Handle, steps: c.int, energy: ^f64) -> c.int --- bob_lattice_energy :: proc(lat: Lattice_Handle, energy: ^f64) -> c.int --- bob_lattice_entropy :: proc(lat: Lattice_Handle, entropy: ^f64) -> c.int --- bob_lattice_correlation :: proc(lat: Lattice_Handle, distance: c.int, corr: ^f64) -> c.int --- bob_lattice_magnetization :: proc(lat: Lattice_Handle, x: c.int, y: c.int, z: c.int, mag: ^f64) -> c.int --- bob_lattice_apply_field :: proc(lat: Lattice_Handle, min_x: c.int, min_y: c.int, min_z: c.int, max_x: c.int, max_y: c.int, max_z: c.int, strength: f64) -> c.int --- // State functions bob_state_create :: proc(n_qubits: c.int, initial: c.int, state: ^State_Handle) -> c.int --- bob_state_destroy :: proc(state: State_Handle) -> c.int --- bob_state_measure :: proc(state: State_Handle, qubit: c.int, outcome: ^c.int, prob: ^f64) -> c.int --- bob_state_measure_multi :: proc(state: State_Handle, qubits: [^]c.int, n_qubits: c.int, outcomes: ^c.int, prob: ^f64) -> c.int --- bob_state_apply_gate :: proc(state: State_Handle, gate: c.int, qubit: c.int, params: [^]f64, n_params: c.int) -> c.int --- bob_state_apply_controlled :: proc(state: State_Handle, gate: c.int, control: c.int, target: c.int, params: [^]f64, n_params: c.int) -> c.int --- bob_state_normalize :: proc(state: State_Handle) -> c.int --- bob_state_expectation :: proc(state: State_Handle, operator: cstring, value: ^f64) -> c.int --- bob_state_amplitudes :: proc(state: State_Handle, n: ^c.int, amps: ^rawptr) -> c.int --- bob_state_clone :: proc(state: State_Handle, cloned: ^State_Handle) -> c.int --- bob_state_fidelity :: proc(state1: State_Handle, state2: State_Handle, fidelity: ^f64) -> c.int --- // Hamiltonian functions bob_hamiltonian_create :: proc(n_qubits: c.int, ham_type: c.int, ham: ^Hamiltonian_Handle) -> c.int --- bob_hamiltonian_destroy :: proc(ham: Hamiltonian_Handle) -> c.int --- bob_hamiltonian_add_term :: proc(ham: Hamiltonian_Handle, coeff_re: f64, coeff_im: f64, qubits: [^]c.int, n_qubits: c.int) -> c.int --- bob_hamiltonian_expectation :: proc(ham: Hamiltonian_Handle, state: State_Handle, exp_re: ^f64, exp_im: ^f64) -> c.int --- bob_hamiltonian_eigenvalues :: proc(ham: Hamiltonian_Handle, n_vals: c.int, vals: ^rawptr) -> c.int --- bob_hamiltonian_time_evolve :: proc(ham: Hamiltonian_Handle, state: State_Handle, time: f64, evolved: ^State_Handle) -> c.int --- } // ========================================================================= // Error Handling // ========================================================================= error_to_odin :: proc(code: c.int) -> Quantum_Error { switch code { case 0: return .None case 1: return .MemoryAllocationFailed case 2: return .InvalidParameter case 3: return .InternalError case 4: return .NotImplemented case 5: return .FileIOError case: return .UnknownError } } // ========================================================================= // RNG Context // ========================================================================= RNG :: struct { handle: RNG_Handle, } rng_create :: proc(seed: u64 = 42) -> (RNG, Quantum_Error) { handle: RNG_Handle err := bob_rng_create(&handle) if err != ERROR_NONE { return {}, error_to_odin(err) } if seed > 0 { seed_err := bob_rng_seed(handle, seed) if seed_err != ERROR_NONE { return {}, error_to_odin(seed_err) } } return {handle}, .None } rng_destroy :: proc(rng: ^RNG) -> Quantum_Error { if rng.handle != nil { err := bob_rng_destroy(rng.handle) if err != ERROR_NONE { return error_to_odin(err) } } return .None } rng_seed :: proc(rng: ^RNG, seed: u64) -> Quantum_Error { err := bob_rng_seed(rng.handle, seed) return error_to_odin(err) if err != ERROR_NONE else .None } rng_uniform :: proc(rng: ^RNG) -> (f64, Quantum_Error) { value: f64 err := bob_rng_uniform(rng.handle, &value) return value, error_to_odin(err) if err != ERROR_NONE else .None } rng_normal :: proc(rng: ^RNG) -> (f64, Quantum_Error) { value: f64 err := bob_rng_normal(rng.handle, &value) return value, error_to_odin(err) if err != ERROR_NONE else .None } rng_integer :: proc(rng: ^RNG, min: i64, max: i64) -> (i64, Quantum_Error) { value: c.int64_t err := bob_rng_integer(rng.handle, min, max, &value) return i64(value), error_to_odin(err) if err != ERROR_NONE else .None } rng_uniform_batch :: proc(rng: ^RNG, count: int, allocator := context.allocator) -> ([]f64, Quantum_Error) { values := make([]f64, count, allocator) for i in 0.. (Lattice, Quantum_Error) { handle: Lattice_Handle err := bob_lattice_create(c.int(nx), c.int(ny), c.int(nz), coupling, seed, &handle) if err != ERROR_NONE { return {}, error_to_odin(err) } return {handle, nx, ny, nz, coupling}, .None } lattice_destroy :: proc(lat: ^Lattice) -> Quantum_Error { if lat.handle != nil { err := bob_lattice_destroy(lat.handle) if err != ERROR_NONE { return error_to_odin(err) } } return .None } lattice_evolve :: proc(lat: ^Lattice, steps: int) -> (f64, Quantum_Error) { energy: f64 err := bob_lattice_evolve(lat.handle, c.int(steps), &energy) return energy, error_to_odin(err) if err != ERROR_NONE else .None } lattice_energy :: proc(lat: ^Lattice) -> (f64, Quantum_Error) { energy: f64 err := bob_lattice_energy(lat.handle, &energy) return energy, error_to_odin(err) if err != ERROR_NONE else .None } lattice_entropy :: proc(lat: ^Lattice) -> (f64, Quantum_Error) { entropy: f64 err := bob_lattice_entropy(lat.handle, &entropy) return entropy, error_to_odin(err) if err != ERROR_NONE else .None } lattice_correlation :: proc(lat: ^Lattice, distance: int) -> (f64, Quantum_Error) { corr: f64 err := bob_lattice_correlation(lat.handle, c.int(distance), &corr) return corr, error_to_odin(err) if err != ERROR_NONE else .None } lattice_magnetization :: proc(lat: ^Lattice, x: int, y: int, z: int) -> (f64, Quantum_Error) { mag: f64 err := bob_lattice_magnetization(lat.handle, c.int(x), c.int(y), c.int(z), &mag) return mag, error_to_odin(err) if err != ERROR_NONE else .None } lattice_apply_field :: proc( lat: ^Lattice, min_x: int, min_y: int, min_z: int, max_x: int, max_y: int, max_z: int, strength: f64, ) -> Quantum_Error { err := bob_lattice_apply_field( lat.handle, c.int(min_x), c.int(min_y), c.int(min_z), c.int(max_x), c.int(max_y), c.int(max_z), strength, ) return error_to_odin(err) if err != ERROR_NONE else .None } // ========================================================================= // Quantum State Context // ========================================================================= Quantum_State :: struct { handle: State_Handle, n_qubits: int, } state_create :: proc(n_qubits: int, initial: int = INITIAL_ZERO) -> (Quantum_State, Quantum_Error) { handle: State_Handle err := bob_state_create(c.int(n_qubits), c.int(initial), &handle) if err != ERROR_NONE { return {}, error_to_odin(err) } return {handle, n_qubits}, .None } state_destroy :: proc(state: ^Quantum_State) -> Quantum_Error { if state.handle != nil { err := bob_state_destroy(state.handle) if err != ERROR_NONE { return error_to_odin(err) } } return .None } Measurement :: struct { outcome: int, probability: f64, } state_measure :: proc(state: ^Quantum_State, qubit: int) -> (Measurement, Quantum_Error) { outcome: c.int prob: f64 err := bob_state_measure(state.handle, c.int(qubit), &outcome, &prob) if err != ERROR_NONE { return {}, error_to_odin(err) } return {int(outcome), prob}, .None } state_apply_gate :: proc(state: ^Quantum_State, gate: int, qubit: int, params: []f64 = {}) -> Quantum_Error { params_ptr := raw_data(params) if len(params) > 0 else nil err := bob_state_apply_gate(state.handle, c.int(gate), c.int(qubit), params_ptr, c.int(len(params))) return error_to_odin(err) if err != ERROR_NONE else .None } state_apply_controlled :: proc(state: ^Quantum_State, gate: int, control: int, target: int, params: []f64 = {}) -> Quantum_Error { params_ptr := raw_data(params) if len(params) > 0 else nil err := bob_state_apply_controlled(state.handle, c.int(gate), c.int(control), c.int(target), params_ptr, c.int(len(params))) return error_to_odin(err) if err != ERROR_NONE else .None } state_normalize :: proc(state: ^Quantum_State) -> Quantum_Error { err := bob_state_normalize(state.handle) return error_to_odin(err) if err != ERROR_NONE else .None } state_expectation :: proc(state: ^Quantum_State, operator: cstring) -> (f64, Quantum_Error) { value: f64 err := bob_state_expectation(state.handle, operator, &value) return value, error_to_odin(err) if err != ERROR_NONE else .None } Amplitude :: struct { re: f64, im: f64, } state_amplitudes :: proc(state: ^Quantum_State, allocator := context.allocator) -> ([]Amplitude, Quantum_Error) { n: c.int amps_ptr: rawptr err := bob_state_amplitudes(state.handle, &n, &s_ptr) if err != ERROR_NONE { return nil, error_to_odin(err) } if n <= 0 { return make([]Amplitude, 0, allocator), .None } amps := make([]Amplitude, int(n), allocator) doubles := cast([^]f64)amps_ptr for i in 0.. (Quantum_State, Quantum_Error) { handle: State_Handle err := bob_state_clone(state.handle, &handle) if err != ERROR_NONE { return {}, error_to_odin(err) } return {handle, state.n_qubits}, .None } state_fidelity :: proc(state1: ^Quantum_State, state2: ^Quantum_State) -> (f64, Quantum_Error) { fidelity: f64 err := bob_state_fidelity(state1.handle, state2.handle, &fidelity) return fidelity, error_to_odin(err) if err != ERROR_NONE else .None } // ========================================================================= // Hamiltonian Context // ========================================================================= Hamiltonian :: struct { handle: Hamiltonian_Handle, n_qubits: int, } hamiltonian_create :: proc(n_qubits: int, ham_type: int = HAM_SPARSE) -> (Hamiltonian, Quantum_Error) { handle: Hamiltonian_Handle err := bob_hamiltonian_create(c.int(n_qubits), c.int(ham_type), &handle) if err != ERROR_NONE { return {}, error_to_odin(err) } return {handle, n_qubits}, .None } hamiltonian_destroy :: proc(ham: ^Hamiltonian) -> Quantum_Error { if ham.handle != nil { err := bob_hamiltonian_destroy(ham.handle) if err != ERROR_NONE { return error_to_odin(err) } } return .None } hamiltonian_add_term :: proc(ham: ^Hamiltonian, coeff_re: f64, coeff_im: f64, qubits: []int) -> Quantum_Error { qubits_c := make([]c.int, len(qubits), context.allocator) defer delete(qubits_c, context.allocator) for i, q in qubits { qubits_c[i] = c.int(q) } err := bob_hamiltonian_add_term(ham.handle, coeff_re, coeff_im, raw_data(qubits_c), c.int(len(qubits_c))) return error_to_odin(err) if err != ERROR_NONE else .None } Complex :: struct { re: f64, im: f64, } hamiltonian_expectation :: proc(ham: ^Hamiltonian, state: ^Quantum_State) -> (Complex, Quantum_Error) { exp_re: f64 exp_im: f64 err := bob_hamiltonian_expectation(ham.handle, state.handle, &exp_re, &exp_im) return {exp_re, exp_im}, error_to_odin(err) if err != ERROR_NONE else .None } hamiltonian_eigenvalues :: proc(ham: ^Hamiltonian, n_vals: int, allocator := context.allocator) -> ([]f64, Quantum_Error) { vals_ptr: rawptr err := bob_hamiltonian_eigenvalues(ham.handle, c.int(n_vals), &vals_ptr) if err != ERROR_NONE { return nil, error_to_odin(err) } if n_vals <= 0 { return make([]f64, 0, allocator), .None } vals := make([]f64, n_vals, allocator) doubles := cast([^]f64)vals_ptr for i in 0.. (Quantum_State, Quantum_Error) { handle: State_Handle err := bob_hamiltonian_time_evolve(ham.handle, state.handle, time, &handle) if err != ERROR_NONE { return {}, error_to_odin(err) } return {handle, state.n_qubits}, .None } // ========================================================================= // Examples // ========================================================================= example_simple_rng :: proc() { rng, err := rng_create(12345) if err != .None { return } defer rng_destroy(&rng) u, _ := rng_uniform(&rng) n, _ := rng_normal(&rng) i, _ := rng_integer(&rng, 0, 100) fmt.printf("Uniform: %v\n", u) fmt.printf("Normal: %v\n", n) fmt.printf("Integer: %v\n", i) } example_quantum_circuit :: proc() { state, err := state_create(2) if err != .None { return } defer state_destroy(&state) state_apply_gate(&state, GATE_H, 0) result, _ := state_measure(&state, 0) fmt.printf("Measurement: %d with prob %v\n", result.outcome, result.probability) } example_lattice_evolution :: proc() { lattice, err := lattice_create(4, 4, 4, 1.0) if err != .None { return } defer lattice_destroy(&lattice) for i in 0..<10 { energy, _ := lattice_energy(&lattice) entropy, _ := lattice_entropy(&lattice) lattice_evolve(&lattice, 1) fmt.printf("Step %d: E=%v S=%v\n", i, energy, entropy) } } example_vqe :: proc() { ham, err := hamiltonian_create(2) if err != .None { return } defer hamiltonian_destroy(&ham) state, err := state_create(2) if err != .None { return } defer state_destroy(&state) state_apply_gate(&state, GATE_RY, 0, {1.5}) state_apply_gate(&state, GATE_RZ, 0, {0.7}) hamiltonian_add_term(&ham, 1.0, 0.0, {0}) hamiltonian_add_term(&ham, 1.0, 0.0, {1}) exp, _ := hamiltonian_expectation(&ham, &state) fmt.printf("Expectation: %v + %vi\n", exp.re, exp.im) }