1#![allow(unsafe_code)]
11
12use std::os::raw::c_int;
13
14extern "C" {
15 fn fq_encode_vector_block(
16 vec: *const f32,
17 dim: usize,
18 codebook: *const f32,
19 codebook_size: usize,
20 block_dim: usize,
21 out_indices: *mut u16,
22 ) -> usize;
23
24 fn fq_decode_vector_block(
25 indices: *const u16,
26 block_count: usize,
27 codebook: *const f32,
28 codebook_size: usize,
29 block_dim: usize,
30 out_vec: *mut f32,
31 );
32
33 fn fq_compressed_attention_logits(
34 key_indices: *const u16,
35 n_keys: usize,
36 key_norms: *const f32,
37 gram_table: *const f32,
38 gram_size: usize,
39 query_indices: *const u16,
40 query_count: usize,
41 query_norm: f32,
42 scale: f32,
43 out_logits: *mut f32,
44 );
45
46 fn fq_softmax(logits: *mut f32, n: usize) -> c_int;
47}
48
49pub fn c_encode_vector_block(
58 vec: &[f32],
59 codebook: &[f32],
60 codebook_size: usize,
61 block_dim: usize,
62) -> Vec<u16> {
63 let dim = vec.len();
64 let block_count = dim / block_dim;
65 let mut indices = vec![0u16; block_count];
66 unsafe {
70 fq_encode_vector_block(
71 vec.as_ptr(),
72 dim,
73 codebook.as_ptr(),
74 codebook_size,
75 block_dim,
76 indices.as_mut_ptr(),
77 );
78 }
79 indices
80}
81
82pub fn c_decode_vector_block(
87 indices: &[u16],
88 codebook: &[f32],
89 codebook_size: usize,
90 block_dim: usize,
91) -> Vec<f32> {
92 let block_count = indices.len();
93 let mut out = vec![0.0f32; block_count * block_dim];
94 unsafe {
96 fq_decode_vector_block(
97 indices.as_ptr(),
98 block_count,
99 codebook.as_ptr(),
100 codebook_size,
101 block_dim,
102 out.as_mut_ptr(),
103 );
104 }
105 out
106}
107
108#[allow(clippy::too_many_arguments)]
113pub fn c_compressed_attention_logits(
114 key_indices: &[u16],
115 n_keys: usize,
116 key_norms: &[f32],
117 gram_table: &[f32],
118 gram_size: usize,
119 query_indices: &[u16],
120 query_count: usize,
121 query_norm: f32,
122 scale: f32,
123) -> Vec<f32> {
124 let mut logits = vec![0.0f32; n_keys];
125 unsafe {
127 fq_compressed_attention_logits(
128 key_indices.as_ptr(),
129 n_keys,
130 key_norms.as_ptr(),
131 gram_table.as_ptr(),
132 gram_size,
133 query_indices.as_ptr(),
134 query_count,
135 query_norm,
136 scale,
137 logits.as_mut_ptr(),
138 );
139 }
140 logits
141}
142
143#[allow(clippy::result_unit_err)]
147pub fn c_softmax(logits: &mut [f32]) -> Result<(), ()> {
148 if logits.is_empty() {
149 return Err(());
150 }
151 let ret = unsafe { fq_softmax(logits.as_mut_ptr(), logits.len()) };
153 if ret == 0 {
154 Ok(())
155 } else {
156 Err(())
157 }
158}