### Minimal Installation Source: https://docs.rs/crate/numkong/7.1.1 Add the `numkong` crate with version '7' to your `Cargo.toml` for a minimal setup. ```toml [dependencies] numkong = "7" ``` -------------------------------- ### Installation with Parallel Helpers Source: https://docs.rs/crate/numkong/7.1.1 To enable host-side parallel helpers, include the `parallel` and `std` features when adding `numkong` to your `Cargo.toml`. ```toml [dependencies] numkong = { version = "7", features = ["parallel", "std"] } ``` -------------------------------- ### Install NumKong Dependency Source: https://docs.rs/crate/numkong Configuration options for adding NumKong to a Cargo.toml file. ```toml [dependencies] numkong = "7" ``` ```toml [dependencies] numkong = { version = "7", features = ["parallel", "std"] } ``` -------------------------------- ### Umeyama Algorithm for Scaled Mesh Alignment Source: https://docs.rs/crate/numkong Apply the `umeyama` function for geometric mesh alignment, which handles scaling. This example aligns a source set to a scaled target set, verifying the calculated RMSD and scale factor. ```rust use numkong::MeshAlignment; let source = [[0.0_f32, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]; let scaled = [[0.0_f32, 0.0, 0.0], [2.0, 0.0, 0.0], [0.0, 2.0, 0.0]]; let result = f32::umeyama(&source, &scaled).unwrap(); assert!(result.rmsd < 1e-6); assert!((result.scale - 2.0).abs() < 0.01); ``` -------------------------------- ### Kabsch Algorithm for Mesh Alignment Source: https://docs.rs/crate/numkong Use the `kabsch` function for geometric mesh alignment, which returns transforms, scales, and RMSD values. This example demonstrates aligning two identical point sets, resulting in near-zero RMSD and a scale of 1.0. ```rust use numkong::MeshAlignment; let source = [[0.0_f32, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]; let target = [[0.0_f32, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]; let result = f32::kabsch(&source, &target).unwrap(); assert!(result.rmsd < 1e-6); assert!((result.scale - 1.0).abs() < 1e-6); ``` -------------------------------- ### Build NumKong with Dynamic Dispatch Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Configures the build process for the numkong library, enabling dynamic dispatch and setting various compilation flags. Use this to build numkong with support for multiple SIMD instruction sets. ```rust use std::collections::HashMap; use std::env; fn main() { build_numkong().expect("Failed to build NumKong"); } /// Build NumKong with dynamic SIMD dispatching. /// Returns a HashMap of enabled compilation flags for potential reuse. fn build_numkong() -> Result, String> { let mut flags = HashMap::::new(); let mut build = cc::Build::new(); build // Prefer portable flags to support MSVC and older toolchains .std("c99") // Enforce C99 standard when supported .file("c/numkong.c") // Complex float dispatch files .file("c/dispatch_f64c.c") .file("c/dispatch_f32c.c") .file("c/dispatch_bf16c.c") .file("c/dispatch_f16c.c") // Real float dispatch files .file("c/dispatch_f64.c") .file("c/dispatch_f32.c") .file("c/dispatch_bf16.c") .file("c/dispatch_f16.c") // Exotic float dispatch files .file("c/dispatch_e5m2.c") .file("c/dispatch_e4m3.c") .file("c/dispatch_e3m2.c") .file("c/dispatch_e2m3.c") // Signed integer dispatch files .file("c/dispatch_i64.c") .file("c/dispatch_i32.c") .file("c/dispatch_i16.c") .file("c/dispatch_i8.c") .file("c/dispatch_i4.c") // Unsigned integer dispatch files .file("c/dispatch_u64.c") .file("c/dispatch_u32.c") .file("c/dispatch_u16.c") .file("c/dispatch_u8.c") .file("c/dispatch_u4.c") .file("c/dispatch_u1.c") // Special dispatch files .file("c/dispatch_other.c") .include("include") .define("NK_NATIVE_F16", "0") .define("NK_NATIVE_BF16", "0") .define("NK_DYNAMIC_DISPATCH", "1") .opt_level(3) .flag_if_supported("-pedantic") // Strict compliance when supported .flag_if_supported("-Wno-psabi") // Suppress GCC ABI note for 32-byte aligned params .warnings(false); // On 32-bit x86, ensure proper stack alignment for floating-point operations // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38534 let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); if target_arch == "x86" { build.flag_if_supported("-mstackrealign"); build.flag_if_supported("-mpreferred-stack-boundary=4"); } // Set architecture-specific macros explicitly let target_bits = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap_or_default(); if target_arch == "x86_64" && target_bits == "64" { build.define("NK_IS_64BIT_X86", "1"); build.define("NK_IS_64BIT_ARM", "0"); build.define("NK_IS_64BIT_RISCV", "0"); flags.insert("NK_IS_64BIT_X86".to_string(), true); flags.insert("NK_IS_64BIT_ARM".to_string(), false); flags.insert("NK_IS_64BIT_RISCV".to_string(), false); } else if target_arch == "aarch64" && target_bits == "64" { ``` -------------------------------- ### Perform a Dot Product Source: https://docs.rs/crate/numkong Demonstrates basic usage of the NumKong library to perform a dot product operation on two arrays. ```rust use numkong::{configure_thread, Dot}; fn main() { configure_thread(); let a = [1.0_f32, 2.0, 3.0]; let b = [4.0_f32, 5.0, 6.0]; let dot = f32::dot(&a, &b).unwrap(); println!("dot={dot}"); } ``` -------------------------------- ### Calculate Dot Product, Jaccard, and Jensen-Shannon Divergence Source: https://docs.rs/crate/numkong/7.1.1 Demonstrates the usage of `Dot`, `Jaccard`, and `JensenShannon` traits for calculating different metrics. Ensure the correct types and data are used for each metric. ```rust use numkong::{Dot, JensenShannon, Jaccard, u1x8}; let a = [1.0_f32, 2.0, 3.0]; let b = [4.0_f32, 5.0, 6.0]; let dot = f32::dot(&a, &b).unwrap(); let bits_a = [u1x8(0b11110000), u1x8(0b00001111)]; let bits_b = [u1x8(0b11110000), u1x8(0b11110000)]; let jaccard = u1x8::jaccard(&bits_a, &bits_b).unwrap(); let p = [0.2_f32, 0.3, 0.5]; let q = [0.1_f32, 0.3, 0.6]; let jsd = f32::jensenshannon(&p, &q).unwrap(); println!("{dot} {jaccard} {jsd}"); ``` -------------------------------- ### Enable/Disable Backends via Environment Variables Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Iterates through a list of potential target flags and enables them by default. Users can disable specific backends by setting the corresponding environment variable to '0' or 'false'. ```rust for flag in flags_to_try.iter() { let enabled = match env::var(flag) { Ok(val) => val != "0" && val.to_lowercase() != "false", Err(_) => true, // Default to enabled if not specified }; if enabled { build.define(flag, "1"); } ``` -------------------------------- ### Slicing Tensors with RangeStep and SliceRange Source: https://docs.rs/crate/numkong Demonstrates various slicing techniques for a Tensor using RangeStep and SliceRange syntax. Negative indices wrap from the end, and RangeStep allows for custom step intervals. ```rust use numkong::{RangeStep, SliceRange, Tensor}; let t = Tensor::::try_from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], &[3, 3]).unwrap(); let col = t.slice((.., 1_usize)).unwrap(); // t[:, 1] — column 1 let rows = t.slice((0..2_usize, ..)).unwrap(); // t[0:2, :] — first two rows let tail = t.slice((-2_isize.., ..)).unwrap(); // t[-2:, :] — last two rows let neg = t.slice((.., -2..-1_isize)).unwrap(); // t[:, -2:-1] let step = t.slice((.., RangeStep::new(0, 3, 2))).unwrap(); // t[:, ::2] // Explicit &[SliceRange] syntax also works let col = t.slice(&[SliceRange::full(), SliceRange::index(1)]).unwrap(); ``` -------------------------------- ### Disable Backends via Environment Variables Source: https://docs.rs/crate/numkong Use environment variables to explicitly disable specific backends during the build process. ```bash NK_TARGET_NEON=0 cargo build NK_TARGET_SVE=0 NK_TARGET_SME=0 cargo build ``` -------------------------------- ### Define 64-bit Architecture Flags Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Sets build defines for 64-bit architecture support (x86, ARM, RISC-V) and populates a flags map. This is typically part of build script configuration. ```rust build.define("NK_IS_64BIT_X86", "0"); build.define("NK_IS_64BIT_ARM", "1"); build.define("NK_IS_64BIT_RISCV", "0"); flags.insert("NK_IS_64BIT_X86".to_string(), false); flags.insert("NK_IS_64BIT_ARM".to_string(), true); flags.insert("NK_IS_64BIT_RISCV".to_string(), false); ``` ```rust build.define("NK_IS_64BIT_X86", "0"); build.define("NK_IS_64BIT_ARM", "0"); build.define("NK_IS_64BIT_RISCV", "1"); flags.insert("NK_IS_64BIT_X86".to_string(), false); flags.insert("NK_IS_64BIT_ARM".to_string(), false); flags.insert("NK_IS_64BIT_RISCV".to_string(), true); ``` ```rust build.define("NK_IS_64BIT_X86", "0"); build.define("NK_IS_64BIT_ARM", "0"); build.define("NK_IS_64BIT_RISCV", "0"); flags.insert("NK_IS_64BIT_X86".to_string(), false); flags.insert("NK_IS_64BIT_ARM".to_string(), false); flags.insert("NK_IS_64BIT_RISCV".to_string(), false); ``` -------------------------------- ### Converting Between Vector and Tensor Source: https://docs.rs/crate/numkong Demonstrates conversion between `Vector` and `Tensor` without data copying. The `try_into_tensor()` and `try_into_vector()` methods facilitate this. ```rust use numkong::{Vector, Tensor}; let v = Vector::::try_from_scalars(&[1.0, 2.0, 3.0]).unwrap(); let t: Tensor = v.try_into_tensor().unwrap(); assert_eq!(t.shape(), &[3]); let v2 = t.try_into_vector().unwrap(); assert_eq!(v2.dims(), 3); ``` -------------------------------- ### Creating VectorView from Raw Parts Source: https://docs.rs/crate/numkong Wraps raw, device-accessible, or externally allocated memory into a `VectorView` without taking ownership. Requires careful management of the memory's lifetime. ```rust use numkong::{VectorView, TensorView}; let embeddings_ptr: *const f32 = /* from CUDA, mmap, or FFI */; let embeddings = unsafe { VectorView::from_raw_parts(embeddings_ptr, 1024, std::mem::size_of::() as isize) }; ``` -------------------------------- ### Packed Matrix Multiplication (GEMM-like) Source: https://docs.rs/crate/numkong Utilize `PackedMatrix` for efficient GEMM-like workloads. Packing the matrix `B` once allows it to be reused across multiple matrix multiplications with different matrices `A`, optimizing performance by performing conversions and padding only during the initial packing. ```rust use numkong::{PackedMatrix, Tensor}; let a = Tensor::::try_full(&[1024, 512], 1.0).unwrap(); let b = Tensor::::try_full(&[256, 512], 1.0).unwrap(); let b_packed = PackedMatrix::try_pack(&b).unwrap(); let c = a.dots_packed(&b_packed); assert_eq!(c.shape(), &[1024, 256]); ``` -------------------------------- ### Probability Metrics (Kullback-Leibler and Jensen-Shannon) Source: https://docs.rs/crate/numkong Calculate Kullback-Leibler and Jensen-Shannon divergences between probability distributions. Note that KLD is asymmetric while JSD is symmetric. ```rust use numkong::{JensenShannon, KullbackLeibler}; let p = [0.2_f32, 0.3, 0.5], q = [0.1_f32, 0.3, 0.6]; let kl_forward = f32::kullbackleibler(&p, &q).unwrap(); let kl_reverse = f32::kullbackleibler(&q, &p).unwrap(); assert!(kl_forward != kl_reverse); // KLD is asymmetric let js_forward = f32::jensenshannon(&p, &q).unwrap(); let js_reverse = f32::jensenshannon(&q, &p).unwrap(); assert!((js_forward - js_reverse).abs() < 1e-6, "JSD is symmetric"); ``` -------------------------------- ### Moments Reductions in Numkong Source: https://docs.rs/crate/numkong Use `try_moments_all` for reductions that return both sum and sum-of-squares. This is useful for norms and variance-like calculations, providing wider outputs to prevent overflow with naive accumulation. ```rust use numkong::{ReduceMoments, Tensor}; let narrow = Tensor::::try_full(&[1024], 255).unwrap(); let (sum, sumsq) = narrow.try_moments_all().unwrap(); assert!(sum > 255); // a naive u8 accumulation would overflow immediately assert!(sumsq > 255u64); // same for sum-of-squares ``` -------------------------------- ### ARM Architecture Flags Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Determines which ARM-specific instruction set extensions (SME, SVE, NEON) are available based on the target OS. SME is available on Linux, FreeBSD, macOS, and Android. SVE is available on Linux, FreeBSD, and Android. NEON is universally available on ARM. ```rust let mut flags = Vec::new(); // SME is available on Linux, FreeBSD, macOS (M4+ with Clang 18+), and Android if is_linux || is_freebsd || is_macos || is_android { flags.extend_from_slice(&[ "NK_TARGET_SMELUT2", "NK_TARGET_SMEBF16", "NK_TARGET_SMEBI32", "NK_TARGET_SMEHALF", "NK_TARGET_SMEFA64", "NK_TARGET_SMEF64", "NK_TARGET_SME2P1", "NK_TARGET_SME2", "NK_TARGET_SME", ]); } // SVE is available on Linux, FreeBSD, and Android (not on Apple Silicon) if is_linux || is_freebsd || is_android { flags.extend_from_slice(&[ "NK_TARGET_SVE2P1", "NK_TARGET_SVE2", "NK_TARGET_SVESDOT", "NK_TARGET_SVEBFDOT", "NK_TARGET_SVEHALF", "NK_TARGET_SVE", ]); } // NEON is available on all ARM platforms flags.extend_from_slice(&[ "NK_TARGET_NEONFHM", "NK_TARGET_NEONBFDOT", "NK_TARGET_NEONSDOT", "NK_TARGET_NEONHALF", "NK_TARGET_NEON", ]); flags ``` -------------------------------- ### Configure Cargo build script triggers Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Use these instructions to trigger a rebuild when specific trigonometry header files or environment flags are modified. ```rust println!("cargo:rerun-if-changed=include/numkong/trigonometry/serial.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/haswell.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/skylake.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/ice.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/genoa.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/sierra.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/neon.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/neonbfdot.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry/neonsdot.h"); // Rerun if environment variables change for flag in flags_to_try.iter() { println!("cargo:rerun-if-env-changed={}", flag); } Ok(flags) } ``` -------------------------------- ### Configure Thread for CPU Acceleration Source: https://docs.rs/crate/numkong/7.1.1 Call `configure_thread` once per thread before using SIMD-accelerated operations. This function enables CPU-specific features like Intel AMX. It is idempotent and inexpensive to call multiple times. ```rust use numkong::{available, configure_thread, cap}; let caps = available(); configure_thread(); if caps & cap::SAPPHIREAMX != 0 { println!("AMX available"); } ``` -------------------------------- ### MaxSim Packed Matrix Scoring Source: https://docs.rs/crate/numkong Implement MaxSim (late-interaction primitive) using `MaxSimPackedMatrix`. This involves packing both query and document tensors and then computing a score, suitable for systems like ColBERT. The packing process optimizes for late-interaction scenarios. ```rust use numkong::{MaxSimPackedMatrix, Tensor}; let queries = Tensor::::try_full(&[4, 16], 1.0).unwrap(); let docs = Tensor::::try_full(&[8, 16], 1.0).unwrap(); let queries_packed = queries.view().try_maxsim_pack().unwrap(); let docs_packed = docs.view().try_maxsim_pack().unwrap(); let score = queries_packed.score(&docs_packed); assert!(score.is_finite()); ``` -------------------------------- ### Creating TensorView from Raw Parts Source: https://docs.rs/crate/numkong Constructs a `TensorView` from raw memory, shape, and strides. This is useful for interfacing with external memory allocations like those from CUDA or FFI, ensuring correct memory layout interpretation. ```rust use numkong::{VectorView, TensorView}; let embeddings_ptr: *const f32 = /* from CUDA, mmap, or FFI */; let shape = [32, 64]; let strides = [64 * 4, 4]; // row-major f32 let matrix = unsafe { TensorView::::from_raw_parts(embeddings_ptr, &shape, &strides) }; ``` -------------------------------- ### Detect Target OS Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Reads the CARGO_CFG_TARGET_OS environment variable to determine the target operating system. This is used for platform-specific optimizations. ```rust let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); let is_freebsd = target_os == "freebsd"; let is_linux = target_os == "linux"; let is_windows = target_os == "windows"; let is_macos = target_os == "macos"; let is_android = target_os == "android"; ``` -------------------------------- ### Disable SVE and SME Backends Source: https://docs.rs/crate/numkong/7.1.1 Disable both SVE and SME backends by setting NK_TARGET_SVE=0 and NK_TARGET_SME=0. This ensures compilation proceeds without these specific ARM architectures. ```bash NK_TARGET_SVE=0 NK_TARGET_SME=0 cargo build ``` -------------------------------- ### Conditional SIMD Backend Compilation Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs This code attempts to compile NumKong with all enabled SIMD backends. If compilation fails, it iteratively disables backends until a successful compilation is achieved, providing warnings for each step. ```rust flags.insert(flag.to_string(), true); } // Try compilation with all enabled backends if build.try_compile("numkong").is_err() { println!("cargo:warning=Failed to compile NumKong with all SIMD backends..."); // Fallback: disable backends one by one until compilation succeeds let mut compiled = false; for flag in flags_to_try.iter() { build.define(flag, "0"); flags.insert(flag.to_string(), false); if build.try_compile("numkong").is_ok() { println!( "cargo:warning=Successfully compiled after disabling {}", flag ); compiled = true; break; } println!( "cargo:warning=Failed to compile after disabling {}, trying next configuration...", flag ); } if !compiled { return Err("Failed to compile NumKong with any SIMD configuration".into()); } } ``` -------------------------------- ### Min/Max Reductions with Index Source: https://docs.rs/crate/numkong The `try_argmin_all` method returns a `MinMaxResult` containing both the minimum value and its flat index within the tensor. This is demonstrated by finding the index of the minimum value in a slice of a tensor. ```rust use numkong::Tensor; let t = Tensor::::try_from_slice(&[ 3.0, 0.0, 7.0, 1.0, 2.0, 5.0, 4.0, -1.0, 6.0, ], &[3, 3]).unwrap(); let second_column = t.slice((.., 1_usize)).unwrap(); // t[:, 1] let idx = second_column.try_argmin_all().unwrap(); assert_eq!(idx, 2); ``` -------------------------------- ### Configure Thread for AMX Operations Source: https://docs.rs/crate/numkong Initialize thread-specific acceleration features before performing AMX operations. This must be called once per worker thread. ```rust use numkong::{available, configure_thread, cap}; let caps = available(); configure_thread(); if caps & cap::SAPPHIREAMX != 0 { println!("AMX available"); } ``` -------------------------------- ### Symmetric Kernels for SYRK-Like Workloads Source: https://docs.rs/crate/numkong Employ `try_dots_symmetric` for SYRK-like workloads, which compute self-similarity or self-distance. This method avoids redundant calculations for pairs `(i, j)` and `(j, i)`, making it efficient for symmetric matrix operations. ```rust use numkong::Tensor; let vectors = Tensor::::try_full(&[100, 768], 1.0).unwrap(); let gram = vectors.view().try_dots_symmetric().unwrap(); assert_eq!(gram.shape(), &[100, 100]); ``` -------------------------------- ### Disable NEON Backend Compilation Source: https://docs.rs/crate/numkong/7.1.1 Use the NK_TARGET_NEON=0 environment variable to disable the NEON backend during compilation. This is useful if NEON is not supported or desired on the target architecture. ```bash NK_TARGET_NEON=0 cargo build ``` -------------------------------- ### Parallel Matrix Multiplication (GEMM-like) Source: https://docs.rs/crate/numkong Performs a parallel GEMM-like operation using a `ThreadPool` from `fork_union`. It partitions rows of the first tensor across threads and uses a packed second matrix. ```rust use numkong::{PackedMatrix, Tensor}; use fork_union::ThreadPool; let a = Tensor::::try_full(&[4096, 768], 1.0).unwrap(); let b = Tensor::::try_full(&[8192, 768], 1.0).unwrap(); let mut pool = ThreadPool::try_spawn(4).unwrap(); // GEMM-like: rows of A partitioned across threads, one shared packed B let b_packed = PackedMatrix::try_pack(&b).unwrap(); let c = a.dots_packed_parallel(&b_packed, &mut pool); assert_eq!(c.shape(), &[4096, 8192]); ``` -------------------------------- ### Perform Metric Calculations Source: https://docs.rs/crate/numkong Standard usage pattern for metric traits like Dot, Jaccard, and JensenShannon using storage types. ```rust use numkong::{Dot, JensenShannon, Jaccard, u1x8}; let a = [1.0_f32, 2.0, 3.0]; let b = [4.0_f32, 5.0, 6.0]; let dot = f32::dot(&a, &b).unwrap(); let bits_a = [u1x8(0b11110000), u1x8(0b00001111)]; let bits_b = [u1x8(0b11110000), u1x8(0b11110000)]; let jaccard = u1x8::jaccard(&bits_a, &bits_b).unwrap(); let p = [0.2_f32, 0.3, 0.5]; let q = [0.1_f32, 0.3, 0.6]; let jsd = f32::jensenshannon(&p, &q).unwrap(); println!("{dot} {jaccard} {jsd}"); ``` -------------------------------- ### Custom Allocator for Vector Source: https://docs.rs/crate/numkong Demonstrates implementing the `Allocator` trait for a custom CUDA memory allocator. This allows `Vector` to allocate memory directly on the GPU using managed memory. ```rust use std::alloc::{Allocator, AllocError, Layout}; use std::ptr::NonNull; use numkong::Vector; struct CudaAllocator; unsafe impl Allocator for CudaAllocator { fn allocate(&self, layout: Layout) -> Result, AllocError> { let raw = unsafe { cuda_malloc_managed(layout.size()) }; let base = NonNull::new(raw).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(base, layout.size())) } unsafe fn deallocate(&self, block: NonNull, _layout: Layout) { cuda_free(block.as_ptr()); } } let queries = Vector::::try_zeros_in(1024, CudaAllocator).unwrap(); ``` -------------------------------- ### Scalar and Vector Tolerance Check Source: https://docs.rs/crate/numkong Compares floating-point numbers and vectors for approximate equality using `is_close` and `allclose` with specified absolute and relative tolerances. ```rust use numkong::{is_close, Vector, Tensor}; // Scalar check assert!(is_close(1.0, 1.0 + 1e-8, 1e-6, 0.0)); // Vector tolerance check let a = Vector::::try_full(3, 1.0).unwrap(); let b = Vector::::try_full(3, 1.0 + 1e-7).unwrap(); assert!(a.allclose(&b, 1e-6, 0.0)); ``` -------------------------------- ### x86_64 Architecture Flags Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Determines which x86_64-specific instruction set extensions (AMX, AVX-512, Haswell) are available based on the target OS. AMX requires specific OS kernel support. AVX-512 is available on Linux, FreeBSD, and Windows. Haswell (AVX2) is universally available. ```rust let mut flags = Vec::new(); // AMX requires OS kernel support: Linux uses arch_prctl, Windows enables automatically. // FreeBSD and macOS lack tile permission support. if is_linux || is_windows { flags.extend_from_slice(&["NK_TARGET_GRANITEAMX", "NK_TARGET_SAPPHIREAMX"]); } // Advanced AVX-512 features available on Linux, FreeBSD, and Windows if is_linux || is_freebsd || is_windows { flags.extend_from_slice(&[ "NK_TARGET_ALDER", "NK_TARGET_SIERRA", "NK_TARGET_TURIN", "NK_TARGET_SAPPHIRE", "NK_TARGET_GENOA", "NK_TARGET_ICELAKE", "NK_TARGET_SKYLAKE", ]); } // Haswell (AVX2) is available on all x86_64 platforms flags.push("NK_TARGET_HASWELL"); flags ``` -------------------------------- ### Curved Metrics (Bilinear and Mahalanobis) Source: https://docs.rs/crate/numkong Calculate bilinear forms and Mahalanobis distances in curved spaces. Bilinear forms require complex numbers and a metric tensor, while Mahalanobis distance uses a vector and the inverse covariance matrix. ```rust use numkong::{Bilinear, Mahalanobis, f32c}; // Complex bilinear form: aᴴ M b let a = [f32c { re: 1.0, im: 0.0 }; 16]; let b = [f32c { re: 0.0, im: 1.0 }; 16]; let metric = [f32c { re: 1.0, im: 0.0 }; 16 * 16]; let bilinear = f32c::bilinear(&a, &b, &metric).unwrap(); // Real Mahalanobis distance: √((a−b)ᵀ M⁻¹ (a−b)) let x = [1.0_f32; 32]; let y = [2.0_f32; 32]; let mut inv_cov = vec![0.0_f32; 32 * 32]; for i in 0..32 { inv_cov[i * 32 + i] = 1.0; } // identity matrix let distance = f32::mahalanobis(&x, &y, &inv_cov).unwrap(); ``` -------------------------------- ### Trigonometric Operations on Tensors Source: https://docs.rs/crate/numkong Applies cosine and sine functions elementwise to a tensor. This demonstrates the availability of trigonometric kernels on tensor and view types. ```rust use numkong::Tensor; let a = Tensor::::try_from_slice(&[0.0, 1.0, 2.0, 3.0], &[2, 2]).unwrap(); let c = a.cos().unwrap(); let s = a.sin().unwrap(); assert_eq!(c.shape(), &[2, 2]); assert_eq!(s.shape(), &[2, 2]); ``` -------------------------------- ### Track File Dependencies for Cargo Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs These lines instruct Cargo to rerun the build script if any of the specified C or header files change. This ensures that the crate is recompiled when its source or header files are modified. ```rust println!("cargo:rerun-if-changed=c/dispatch.h"); println!("cargo:rerun-if-changed=c/dispatch_f64c.c"); println!("cargo:rerun-if-changed=c/dispatch_f32c.c"); println!("cargo:rerun-if-changed=c/dispatch_bf16c.c"); println!("cargo:rerun-if-changed=c/dispatch_f16c.c"); println!("cargo:rerun-if-changed=c/dispatch_f64.c"); println!("cargo:rerun-if-changed=c/dispatch_f32.c"); println!("cargo:rerun-if-changed=c/dispatch_bf16.c"); println!("cargo:rerun-if-changed=c/dispatch_f16.c"); println!("cargo:rerun-if-changed=c/dispatch_e5m2.c"); println!("cargo:rerun-if-changed=c/dispatch_e4m3.c"); println!("cargo:rerun-if-changed=c/dispatch_e3m2.c"); println!("cargo:rerun-if-changed=c/dispatch_e2m3.c"); println!("cargo:rerun-if-changed=c/dispatch_i64.c"); println!("cargo:rerun-if-changed=c/dispatch_i32.c"); println!("cargo:rerun-if-changed=c/dispatch_i16.c"); println!("cargo:rerun-if-changed=c/dispatch_i8.c"); println!("cargo:rerun-if-changed=c/dispatch_i4.c"); println!("cargo:rerun-if-changed=c/dispatch_u64.c"); println!("cargo:rerun-if-changed=c/dispatch_u32.c"); println!("cargo:rerun-if-changed=c/dispatch_u16.c"); println!("cargo:rerun-if-changed=c/dispatch_u8.c"); println!("cargo:rerun-if-changed=c/dispatch_u4.c"); println!("cargo:rerun-if-changed=c/dispatch_u1.c"); println!("cargo:rerun-if-changed=c/dispatch_other.c"); println!("cargo:rerun-if-changed=c/numkong.c"); // Top-level headers println!("cargo:rerun-if-changed=include/numkong/numkong.h"); println!("cargo:rerun-if-changed=include/numkong/types.h"); println!("cargo:rerun-if-changed=include/numkong/capabilities.h"); println!("cargo:rerun-if-changed=include/numkong/scalar.h"); println!("cargo:rerun-if-changed=include/numkong/cast.h"); println!("cargo:rerun-if-changed=include/numkong/set.h"); println!("cargo:rerun-if-changed=include/numkong/curved.h"); println!("cargo:rerun-if-changed=include/numkong/dot.h"); println!("cargo:rerun-if-changed=include/numkong/dots.h"); println!("cargo:rerun-if-changed=include/numkong/each.h"); println!("cargo:rerun-if-changed=include/numkong/geospatial.h"); println!("cargo:rerun-if-changed=include/numkong/maxsim.h"); println!("cargo:rerun-if-changed=include/numkong/mesh.h"); println!("cargo:rerun-if-changed=include/numkong/probability.h"); println!("cargo:rerun-if-changed=include/numkong/reduce.h"); println!("cargo:rerun-if-changed=include/numkong/sets.h"); println!("cargo:rerun-if-changed=include/numkong/sparse.h"); println!("cargo:rerun-if-changed=include/numkong/spatial.h"); println!("cargo:rerun-if-changed=include/numkong/spatials.h"); println!("cargo:rerun-if-changed=include/numkong/trigonometry.h"); // cast/ println!("cargo:rerun-if-changed=include/numkong/cast/serial.h"); println!("cargo:rerun-if-changed=include/numkong/cast/haswell.h"); println!("cargo:rerun-if-changed=include/numkong/cast/skylake.h"); println!("cargo:rerun-if-changed=include/numkong/cast/icelake.h"); println!("cargo:rerun-if-changed=include/numkong/cast/sapphire.h"); println!("cargo:rerun-if-changed=include/numkong/cast/neon.h"); println!("cargo:rerun-if-changed=include/numkong/cast/rvv.h"); println!("cargo:rerun-if-changed=include/numkong/cast/v128relaxed.h"); // curved/ println!("cargo:rerun-if-changed=include/numkong/curved/serial.h"); println!("cargo:rerun-if-changed=include/numkong/curved/haswell.h"); println!("cargo:rerun-if-changed=include/numkong/curved/skylake.h"); println!("cargo:rerun-if-changed=include/numkong/curved/genoa.h"); ``` -------------------------------- ### WebAssembly Architecture Flags Source: https://docs.rs/crate/numkong/7.1.1/source/build.rs Sets the NK_TARGET_V128RELAXED flag for WebAssembly targets (wasm32, wasm64). ```rust vec!["NK_TARGET_V128RELAXED"] ``` -------------------------------- ### Parallel Symmetric Rank-One Update (SYRK-like) Source: https://docs.rs/crate/numkong Executes a parallel SYRK-like operation using a `ThreadPool`. It partitions row windows of a square output tensor across threads for computation. ```rust use numkong::{PackedMatrix, Tensor}; use fork_union::ThreadPool; let a = Tensor::::try_full(&[4096, 768], 1.0).unwrap(); let b = Tensor::::try_full(&[8192, 768], 1.0).unwrap(); let mut pool = ThreadPool::try_spawn(4).unwrap(); // SYRK-like: row windows of one square output partitioned across threads let gram = a.dots_symmetric_parallel(&mut pool); assert_eq!(gram.shape(), &[4096, 4096]); ``` -------------------------------- ### In-place Compound Assignment for Tensors Source: https://docs.rs/crate/numkong Illustrates the use of compound assignment operators (`+=`, `-=`, `*=`) for in-place modification of a tensor's elements. ```rust use numkong::Tensor; let mut t = Tensor::::try_full(&[4], 1.0).unwrap(); t += 10.0; t -= 0.5; t *= 2.0; ``` -------------------------------- ### Elementwise Tensor Operations: Blend and Sine Source: https://docs.rs/crate/numkong Performs elementwise blending of two tensors and then calculates the sine of the resulting tensor. This utilizes tensor views for operations. ```rust use numkong::Tensor; let a = Tensor::::try_from_slice(&[1.0, 2.0, 3.0, 4.0], &[2, 2]).unwrap(); let b = Tensor::::try_full(&[2, 2], 2.0).unwrap(); let blended = a.view().try_blend_tensor(&b.view(), 0.25, 0.75).unwrap(); let sines = blended.sin().unwrap(); assert_eq!(sines.shape(), &[2, 2]); ``` -------------------------------- ### Calculate Complex Dot and VDot Products Source: https://docs.rs/crate/numkong/7.1.1 Compute dot and vdot products for complex numbers using `f32c`. The `vdot` operation performs conjugation, similar to numpy.vdot. ```rust use numkong::{Dot, VDot, f32c}; let a = [f32c { re: 1.0, im: 2.0 }, f32c { re: 3.0, im: 4.0 }]; let b = [f32c { re: 5.0, im: 6.0 }, f32c { re: 7.0, im: 8.0 }]; let dot = f32c::dot(&a, &b).unwrap(); let vdot = f32c::vdot(&a, &b).unwrap(); // like numpy.vdot, conjugated println!("{dot:?} {vdot:?}"); ``` -------------------------------- ### Calculate Complex Dot Products Source: https://docs.rs/crate/numkong Perform standard and conjugated dot products on complex number types. ```rust use numkong::{Dot, VDot, f32c}; let a = [f32c { re: 1.0, im: 2.0 }, f32c { re: 3.0, im: 4.0 }]; let b = [f32c { re: 5.0, im: 6.0 }, f32c { re: 7.0, im: 8.0 }]; let dot = f32c::dot(&a, &b).unwrap(); let vdot = f32c::vdot(&a, &b).unwrap(); // like numpy.vdot, conjugated println!("{dot:?} {vdot:?}"); ``` -------------------------------- ### Packed-Binary Set Similarity Source: https://docs.rs/crate/numkong Calculate Hamming and Jaccard similarity for packed binary data. Ensure inputs are of type u1x8. ```rust use numkong::{Hamming, Jaccard, u1x8}; let a = [u1x8(0b10101010), u1x8(0b11110000)]; let b = [u1x8(0b10101110), u1x8(0b11000000)]; let hamming = u1x8::hamming(&a, &b).unwrap(); let jaccard = u1x8::jaccard(&a, &b).unwrap(); ``` -------------------------------- ### Geospatial Distance Calculation (Haversine and Vincenty) Source: https://docs.rs/crate/numkong Compute distances between geographical coordinates using Haversine (spherical) and Vincenty (ellipsoidal) formulas. Inputs are in radians, and outputs are in meters. Supports both f64 and f32 precision. ```rust use numkong::{Haversine, Vincenty}; // Statue of Liberty (40.6892°N, 74.0445°W) → Big Ben (51.5007°N, 0.1246°W) let liberty_lat = [0.7101605100_f64], liberty_lon = [-1.2923203180_f64]; let big_ben_lat = [0.8988567821_f64], big_ben_lon = [-0.0021746802_f64]; let mut distance = [0.0_f64; 1]; f64::vincenty(&liberty_lat, &liberty_lon, &big_ben_lat, &big_ben_lon, &mut distance).unwrap(); // ≈ 5,589,857 m (ellipsoidal, baseline) f64::haversine(&liberty_lat, &liberty_lon, &big_ben_lat, &big_ben_lon, &mut distance).unwrap(); // ≈ 5,543,723 m (spherical, ~46 km less) // Vincenty in f32 — drifts ~2 m from f64 let liberty_lat32 = [0.7101605100_f32], liberty_lon32 = [-1.2923203180_f32]; let big_ben_lat32 = [0.8988567821_f32], big_ben_lon32 = [-0.0021746802_f32]; let mut distance_f32 = [0.0_f32; 1]; f32::vincenty(&liberty_lat32, &liberty_lon32, &big_ben_lat32, &big_ben_lon32, &mut distance_f32).unwrap(); // ≈ 5,589,859 m (+2 m drift) ``` -------------------------------- ### Calculate Euclidean Distance for Signed Integers Source: https://docs.rs/crate/numkong/7.1.1 Compute the Euclidean distance between two arrays of signed 8-bit integers. The output type is wider than `i8` to prevent overflow during accumulation. ```rust use numkong::Euclidean; let a = [1_i8, 2, 3, 4]; let b = [4_i8, 3, 2, 1]; let distance = i8::euclidean(&a, &b).unwrap(); // widened output, not int8 println!("{distance}"); ``` -------------------------------- ### Weighted Sparse Dot Product Source: https://docs.rs/crate/numkong Compute the weighted dot product of two sparse vectors using `sparse_dot`. This operation considers both the indices and their corresponding weights for the calculation. ```rust use numkong::{SparseIntersect, SparseDot}; let a_idx = [1_u32, 3, 5, 7], b_idx = [3_u32, 4, 5, 8]; let a_weights = [1.0_f32, 2.0, 3.0, 4.0], b_weights = [5.0_f32, 6.0, 7.0, 8.0]; let dot = u32::sparse_dot(&a_idx, &b_idx, &a_weights, &b_weights).unwrap(); assert!(dot > 0.0); // weighted dot over shared indices ``` -------------------------------- ### Tensor Tolerance Check Source: https://docs.rs/crate/numkong Performs approximate equality checks on tensors using the `allclose` method, requiring the `AllCloseOps` trait to be in scope for `TensorRef` implementors. ```rust use numkong::{is_close, Vector, Tensor}; // Tensor tolerance check let ta = Tensor::::try_full(&[2, 3], 1.0).unwrap(); let tb = Tensor::::try_full(&[2, 3], 1.0 + 1e-7).unwrap(); assert!(ta.allclose(&tb, 1e-6, 0.0)); ```