1pub mod accumulator;
14pub mod complex;
15pub mod dispatch;
16pub mod f16;
17pub mod quantized;
18
19pub mod builtins;
21
22pub mod buffer;
24pub mod tensor;
25pub mod scratchpad;
26pub mod aligned_pool;
27mod kernel_bridge;
28pub use kernel_bridge::kernel;
29pub mod paged_kv;
30pub mod binned_alloc;
31pub mod frame_arena;
32pub mod object_slab;
33pub mod gc;
34pub mod sparse;
35pub mod sparse_solvers;
36pub mod tensor_tiled;
37pub mod tensor_simd;
38pub mod tensor_pool;
39pub mod det_map;
40pub mod linalg;
41pub mod value;
42pub mod error;
43pub mod lib_registry;
44pub mod json;
45pub mod datetime;
46pub mod window;
47pub mod stats;
48pub mod distributions;
49pub mod hypothesis;
50pub mod ml;
51pub mod fft;
52pub mod stationarity;
53pub mod ode;
54pub mod sparse_eigen;
55pub mod interpolate;
56pub mod optimize;
57pub mod clustering;
58pub mod tensor_dtype;
59pub mod timeseries;
60pub mod integrate;
61pub mod differentiate;
62
63pub use buffer::Buffer;
66pub use tensor::Tensor;
67pub use scratchpad::Scratchpad;
68pub use aligned_pool::{AlignedPool, AlignedByteSlice};
69pub use paged_kv::{KvBlock, PagedKvCache};
70pub use gc::{GcRef, GcHeap};
71pub use binned_alloc::BinnedAllocator;
72pub use frame_arena::{FrameArena, ArenaStore};
73pub use object_slab::{ObjectSlab, SlabRef};
74pub use sparse::{SparseCsr, SparseCoo};
75pub use tensor_tiled::TiledMatmul;
76pub use det_map::{DetMap, murmurhash3, murmurhash3_finalize, value_hash, values_equal_static};
77pub use value::{Value, Bf16, FnValue};
78pub use error::RuntimeError;
79pub use tensor_dtype::{DType, TypedStorage};
80
81#[cfg(test)]
86mod tests {
87 use super::*;
88 use std::rc::Rc;
89 use cjc_repro::Rng;
90
91 #[test]
94 fn test_buffer_alloc_get_set() {
95 let mut buf = Buffer::alloc(5, 0.0f64);
96 assert_eq!(buf.len(), 5);
97 assert_eq!(buf.get(0), Some(0.0));
98 assert_eq!(buf.get(4), Some(0.0));
99 assert_eq!(buf.get(5), None);
100
101 buf.set(2, 42.0).unwrap();
102 assert_eq!(buf.get(2), Some(42.0));
103
104 assert!(buf.set(10, 1.0).is_err());
105 }
106
107 #[test]
108 fn test_buffer_from_vec() {
109 let buf = Buffer::from_vec(vec![1, 2, 3, 4, 5]);
110 assert_eq!(buf.len(), 5);
111 assert_eq!(buf.get(0), Some(1));
112 assert_eq!(buf.get(4), Some(5));
113 assert_eq!(buf.as_slice(), vec![1, 2, 3, 4, 5]);
114 }
115
116 #[test]
117 fn test_buffer_cow_behavior() {
118 let buf_a = Buffer::from_vec(vec![10, 20, 30]);
119 let mut buf_b = buf_a.clone();
120
121 assert_eq!(buf_a.refcount(), 2);
122 assert_eq!(buf_b.refcount(), 2);
123
124 buf_b.set(0, 99).unwrap();
125
126 assert_eq!(buf_a.refcount(), 1);
127 assert_eq!(buf_b.refcount(), 1);
128 assert_eq!(buf_a.get(0), Some(10));
129 assert_eq!(buf_b.get(0), Some(99));
130 }
131
132 #[test]
133 fn test_buffer_clone_buffer_forces_deep_copy() {
134 let buf_a = Buffer::from_vec(vec![1, 2, 3]);
135 let buf_b = buf_a.clone_buffer();
136
137 assert_eq!(buf_a.refcount(), 1);
138 assert_eq!(buf_b.refcount(), 1);
139 assert_eq!(buf_a.as_slice(), buf_b.as_slice());
140 }
141
142 #[test]
145 fn test_tensor_creation_and_indexing() {
146 let t = Tensor::zeros(&[2, 3]);
147 assert_eq!(t.shape(), &[2, 3]);
148 assert_eq!(t.ndim(), 2);
149 assert_eq!(t.len(), 6);
150 assert_eq!(t.get(&[0, 0]).unwrap(), 0.0);
151 assert_eq!(t.get(&[1, 2]).unwrap(), 0.0);
152
153 assert!(t.get(&[2, 0]).is_err());
154 assert!(t.get(&[0]).is_err());
155 }
156
157 #[test]
158 fn test_tensor_from_vec_and_set() {
159 let mut t = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]).unwrap();
160 assert_eq!(t.get(&[0, 0]).unwrap(), 1.0);
161 assert_eq!(t.get(&[0, 2]).unwrap(), 3.0);
162 assert_eq!(t.get(&[1, 0]).unwrap(), 4.0);
163 assert_eq!(t.get(&[1, 2]).unwrap(), 6.0);
164
165 t.set(&[1, 1], 99.0).unwrap();
166 assert_eq!(t.get(&[1, 1]).unwrap(), 99.0);
167 }
168
169 #[test]
170 fn test_tensor_elementwise_ops() {
171 let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]).unwrap();
172 let b = Tensor::from_vec(vec![5.0, 6.0, 7.0, 8.0], &[2, 2]).unwrap();
173
174 let sum = a.add(&b).unwrap();
175 assert_eq!(sum.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
176
177 let diff = a.sub(&b).unwrap();
178 assert_eq!(diff.to_vec(), vec![-4.0, -4.0, -4.0, -4.0]);
179
180 let prod = a.mul_elem(&b).unwrap();
181 assert_eq!(prod.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
182
183 let quot = b.div_elem(&a).unwrap();
184 assert_eq!(quot.to_vec(), vec![5.0, 3.0, 7.0 / 3.0, 2.0]);
185 }
186
187 #[test]
188 fn test_tensor_matmul_correctness() {
189 let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[2, 2]).unwrap();
190 let b = Tensor::from_vec(vec![5.0, 6.0, 7.0, 8.0], &[2, 2]).unwrap();
191
192 let c = a.matmul(&b).unwrap();
193 assert_eq!(c.shape(), &[2, 2]);
194 assert_eq!(c.get(&[0, 0]).unwrap(), 19.0);
195 assert_eq!(c.get(&[0, 1]).unwrap(), 22.0);
196 assert_eq!(c.get(&[1, 0]).unwrap(), 43.0);
197 assert_eq!(c.get(&[1, 1]).unwrap(), 50.0);
198 }
199
200 #[test]
201 fn test_tensor_matmul_nonsquare() {
202 let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]).unwrap();
203 let b = Tensor::from_vec(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0], &[3, 2]).unwrap();
204
205 let c = a.matmul(&b).unwrap();
206 assert_eq!(c.shape(), &[2, 2]);
207 assert_eq!(c.get(&[0, 0]).unwrap(), 58.0);
208 assert_eq!(c.get(&[0, 1]).unwrap(), 64.0);
209 assert_eq!(c.get(&[1, 0]).unwrap(), 139.0);
210 assert_eq!(c.get(&[1, 1]).unwrap(), 154.0);
211 }
212
213 #[test]
214 fn test_tensor_reshape_shares_buffer() {
215 let t = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3]).unwrap();
216 let r = t.reshape(&[3, 2]).unwrap();
217
218 assert_eq!(r.shape(), &[3, 2]);
219 assert_eq!(r.get(&[0, 0]).unwrap(), 1.0);
220 assert_eq!(r.get(&[2, 1]).unwrap(), 6.0);
221
222 assert_eq!(t.buffer.refcount(), 2);
223
224 assert!(t.reshape(&[4, 2]).is_err());
225 }
226
227 #[test]
228 fn test_tensor_sum_and_mean() {
229 let t = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], &[4]).unwrap();
230 assert!((t.sum() - 10.0).abs() < 1e-12);
231 assert!((t.mean() - 2.5).abs() < 1e-12);
232 }
233
234 #[test]
237 fn test_gc_alloc_and_read() {
238 let mut heap = GcHeap::new(100);
239 let r1 = heap.alloc(42i64);
240 let r2 = heap.alloc("hello".to_string());
241
242 assert_eq!(heap.live_count(), 2);
243 assert_eq!(*heap.get::<i64>(r1).unwrap(), 42);
244 assert_eq!(heap.get::<String>(r2).unwrap().as_str(), "hello");
245
246 assert!(heap.get::<f64>(r1).is_none());
247 }
248
249 #[test]
250 fn test_gc_collect_is_noop_rc_backed() {
251 let mut heap = GcHeap::new(100);
254 let r1 = heap.alloc(1i64);
255 let r2 = heap.alloc(2i64);
256 let r3 = heap.alloc(3i64);
257
258 assert_eq!(heap.live_count(), 3);
259
260 heap.collect(&[r1, r2]);
262
263 assert_eq!(heap.live_count(), 3, "RC keeps all objects alive");
264 assert_eq!(*heap.get::<i64>(r1).unwrap(), 1);
265 assert_eq!(*heap.get::<i64>(r2).unwrap(), 2);
266 assert_eq!(*heap.get::<i64>(r3).unwrap(), 3);
267 }
268
269 #[test]
270 fn test_gc_explicit_free_and_slot_reuse() {
271 let mut heap = GcHeap::new(100);
273 let r1 = heap.alloc(1i64);
274 let r2 = heap.alloc(2i64);
275 let r3 = heap.alloc(3i64);
276
277 heap.free(r1);
279 heap.free(r2);
280 heap.free(r3);
281 assert_eq!(heap.live_count(), 0);
282 assert_eq!(heap.free_list().len(), 3);
283
284 let r4 = heap.alloc(99i64);
286 assert!(r4.index < 3, "should reuse a freed slot");
287 assert_eq!(*heap.get::<i64>(r4).unwrap(), 99);
288 }
289
290 #[test]
293 fn test_stable_summation_via_tensor() {
294 let n = 100_000;
295 let data: Vec<f64> = (0..n).map(|_| 0.00001).collect();
296 let t = Tensor::from_vec(data, &[n]).unwrap();
297 let result = t.sum();
298 let expected = 0.00001 * n as f64;
299 assert!(
300 (result - expected).abs() < 1e-10,
301 "Kahan sum drift: expected {expected}, got {result}"
302 );
303 }
304
305 #[test]
308 fn test_tensor_randn_deterministic() {
309 let mut rng1 = Rng::seeded(42);
310 let mut rng2 = Rng::seeded(42);
311
312 let t1 = Tensor::randn(&[3, 4], &mut rng1);
313 let t2 = Tensor::randn(&[3, 4], &mut rng2);
314
315 assert_eq!(t1.to_vec(), t2.to_vec());
316 }
317
318 #[test]
321 fn test_value_display() {
322 assert_eq!(format!("{}", Value::Int(42)), "42");
323 assert_eq!(format!("{}", Value::Bool(true)), "true");
324 assert_eq!(format!("{}", Value::Void), "void");
325 assert_eq!(format!("{}", Value::String(Rc::new("hi".into()))), "hi");
326 }
327
328 #[test]
329 fn test_cow_string_clone_shares() {
330 let s = Value::String(Rc::new("hello".into()));
331 let s2 = s.clone();
332 if let (Value::String(a), Value::String(b)) = (&s, &s2) {
333 assert!(Rc::ptr_eq(a, b));
334 } else {
335 panic!("expected String values");
336 }
337 }
338
339 #[test]
340 fn test_cow_string_display() {
341 let s = Value::String(Rc::new("world".into()));
342 assert_eq!(format!("{}", s), "world");
343 }
344
345 #[test]
348 fn test_byteslice_value_display_utf8() {
349 let bs = Value::ByteSlice(Rc::new(b"hello".to_vec()));
350 assert_eq!(format!("{}", bs), r#"b"hello""#);
351 }
352
353 #[test]
354 fn test_byteslice_value_display_hex() {
355 let bs = Value::ByteSlice(Rc::new(vec![0xff, 0x00, 0x41]));
356 assert_eq!(format!("{}", bs), r#"b"\xff\x00A""#);
357 }
358
359 #[test]
360 fn test_strview_value_display() {
361 let sv = Value::StrView(Rc::new(b"world".to_vec()));
362 assert_eq!(format!("{}", sv), "world");
363 }
364
365 #[test]
366 fn test_u8_value_display() {
367 assert_eq!(format!("{}", Value::U8(65)), "65");
368 }
369
370 #[test]
371 fn test_byteslice_hash_deterministic() {
372 let a = Value::ByteSlice(Rc::new(b"hello".to_vec()));
373 let b = Value::ByteSlice(Rc::new(b"hello".to_vec()));
374 assert_eq!(value_hash(&a), value_hash(&b));
375 }
376
377 #[test]
378 fn test_byteslice_hash_different_content() {
379 let a = Value::ByteSlice(Rc::new(b"hello".to_vec()));
380 let b = Value::ByteSlice(Rc::new(b"world".to_vec()));
381 assert_ne!(value_hash(&a), value_hash(&b));
382 }
383
384 #[test]
385 fn test_byteslice_equality() {
386 let a = Value::ByteSlice(Rc::new(b"abc".to_vec()));
387 let b = Value::ByteSlice(Rc::new(b"abc".to_vec()));
388 let c = Value::ByteSlice(Rc::new(b"def".to_vec()));
389 assert!(values_equal_static(&a, &b));
390 assert!(!values_equal_static(&a, &c));
391 }
392
393 #[test]
394 fn test_strview_equality() {
395 let a = Value::StrView(Rc::new(b"test".to_vec()));
396 let b = Value::StrView(Rc::new(b"test".to_vec()));
397 assert!(values_equal_static(&a, &b));
398 }
399
400 #[test]
401 fn test_u8_hash_and_equality() {
402 let a = Value::U8(42);
403 let b = Value::U8(42);
404 let c = Value::U8(99);
405 assert_eq!(value_hash(&a), value_hash(&b));
406 assert_ne!(value_hash(&a), value_hash(&c));
407 assert!(values_equal_static(&a, &b));
408 assert!(!values_equal_static(&a, &c));
409 }
410
411 #[test]
412 fn test_byteslice_clone_shares_rc() {
413 let bs = Value::ByteSlice(Rc::new(b"data".to_vec()));
414 let bs2 = bs.clone();
415 if let (Value::ByteSlice(a), Value::ByteSlice(b)) = (&bs, &bs2) {
416 assert!(Rc::ptr_eq(a, b));
417 } else {
418 panic!("expected ByteSlice values");
419 }
420 }
421
422 #[test]
423 fn test_byteslice_in_detmap() {
424 let mut map = DetMap::new();
425 let key = Value::ByteSlice(Rc::new(b"token".to_vec()));
426 map.insert(key.clone(), Value::Int(1));
427
428 let lookup = Value::ByteSlice(Rc::new(b"token".to_vec()));
429 assert!(map.contains_key(&lookup));
430 match map.get(&lookup) {
431 Some(Value::Int(1)) => {},
432 _ => panic!("expected Int(1)"),
433 }
434 }
435
436 #[test]
437 fn test_murmurhash3_byteslice_stability() {
438 let h1 = murmurhash3(b"hello");
439 let h2 = murmurhash3(b"hello");
440 assert_eq!(h1, h2);
441
442 let h3 = murmurhash3(b"");
443 let h4 = murmurhash3(b"");
444 assert_eq!(h3, h4);
445
446 assert_ne!(murmurhash3(b"hello"), murmurhash3(b"world"));
447 }
448}