Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7a3c5ac
feat(fft): implement 1D FFT/IFFT and frequency helpers
sonusharma6-dsa May 29, 2026
9d2b2e9
fix(fft): handle zero-length FFT/IFFT and correct rfftfreq
sonusharma6-dsa May 29, 2026
89c95c3
fix(fft): correct fftfreq Nyquist sign for even n
sonusharma6-dsa May 29, 2026
4219497
chore(dtype): address clippy lints (doc spacing, FromStr impl, unnece…
sonusharma6-dsa May 29, 2026
2544e58
ci: ignore cargo-machete unused-deps for mohu-fft (partial impl)
sonusharma6-dsa May 29, 2026
d1f9012
style: apply rustfmt-like formatting fixes for reporter, test_utils, …
sonusharma6-dsa May 29, 2026
9d5a58f
style: apply rustfmt fixes reported by CI
sonusharma6-dsa May 29, 2026
73c4483
style: apply rustfmt fixes reported by CI
sonusharma6-dsa May 29, 2026
a9acc32
feat(io): add CSV I/O (Fixes #228)
sonusharma6-dsa May 29, 2026
f14e789
Potential fix for pull request finding
sonusharma6-dsa May 29, 2026
dd94e4a
Potential fix for pull request finding
sonusharma6-dsa May 29, 2026
c7c1edc
Potential fix for pull request finding
sonusharma6-dsa May 29, 2026
d7c2914
fix csv writer reuse for standard line terminators
Copilot May 29, 2026
ed6ce00
document custom terminator fallback in csv writer
Copilot May 29, 2026
04006f2
fix(ci): pin dco-check action
sonusharma6-dsa May 29, 2026
ebdb5d4
fix(ci): pin dco-check action
sonusharma6-dsa May 29, 2026
0048bbd
fix(ci): pin dco-check action
sonusharma6-dsa May 29, 2026
4f24443
feat(io): add csv read/write support
sonusharma6-dsa May 29, 2026
d4f975f
chore(windows): add llvm-mingw helper
sonusharma6-dsa May 29, 2026
a9171cf
fix(testing): add assert_allclose macro
sonusharma6-dsa May 29, 2026
bcb2617
style: rustfmt workspace
sonusharma6-dsa May 29, 2026
e51f953
chore: apply automatic clippy fixes
sonusharma6-dsa May 29, 2026
07b2a42
chore: remove accidental embedded repo entry
sonusharma6-dsa May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: christophebedard/dco-check@v0.5.0
- uses: christophebedard/dco-check@0.5.1
with:
token: ${{ secrets.GITHUB_TOKEN }}

Expand Down
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ serde = { version = "1", features = ["derive"] }

# ── I/O ───────────────────────────────────────────────────────────────────────
memmap2 = "0.9"
csv = "1.4"

# ── Python bindings ───────────────────────────────────────────────────────────
pyo3 = { version = "0.23", features = ["extension-module"] }
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ Polars proved you can rewrite the data layer in Rust and win. mohu is that same

Early. The foundation is being laid. If you believe the Python numerical stack deserves a rewrite, watch this repo or contribute.

## windows

On Windows, use `scripts/use-llvm-mingw.ps1` to run the `mohu-io` test target
with the LLVM-MinGW linker setup that works in this workspace.

```powershell
.\scripts\use-llvm-mingw.ps1
```

## built with

- [Rust](https://rust-lang.org)
Expand Down
1 change: 1 addition & 0 deletions crates/mohu-array/src/array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/mohu-array/src/iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/mohu-array/src/shape.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/mohu-array/src/slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/mohu-array/src/view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

47 changes: 31 additions & 16 deletions crates/mohu-buffer/examples/alloc_and_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
// directly, but is critical for high-performance scientific computing.

use mohu_buffer::{
AllocHandle, AllocStats, Strategy,
BufferPool, PoolStats, GLOBAL_POOL,
SIMD_ALIGN, CACHE_LINE,
Buffer,
AllocHandle, AllocStats, Buffer, CACHE_LINE, GLOBAL_POOL, SIMD_ALIGN,
Strategy,
};
use mohu_dtype::DType;

Expand All @@ -22,22 +20,32 @@ fn main() {
// ── Direct allocation with AllocHandle ─────────────────────────────────
println!("\n── AllocHandle (raw aligned allocation) ──");
let handle = AllocHandle::alloc(1024, SIMD_ALIGN).unwrap();
println!("Allocated: len={}, align={}, strategy={:?}",
handle.len(), handle.align(), handle.strategy());
println!(
"Allocated: len={}, align={}, strategy={:?}",
handle.len(),
handle.align(),
handle.strategy()
);
println!(" Pointer: {:p}", handle.as_ptr());
println!(" Aligned to 64 bytes: {}", handle.is_aligned_to(64));
assert!(matches!(handle.strategy(), Strategy::Heap));

// Zeroed allocation
let zeroed = AllocHandle::alloc_zeroed(512, SIMD_ALIGN).unwrap();
println!("\nZeroed alloc: len={}, all zeros: {}",
println!(
"\nZeroed alloc: len={}, all zeros: {}",
zeroed.len(),
zeroed.as_byte_slice().iter().all(|&b| b == 0));
zeroed.as_byte_slice().iter().all(|&b| b == 0)
);

// Zero-size allocation
let empty = AllocHandle::alloc(0, SIMD_ALIGN).unwrap();
println!("Zero-size: len={}, is_empty={}, strategy={:?}",
empty.len(), empty.is_empty(), empty.strategy());
println!(
"Zero-size: len={}, is_empty={}, strategy={:?}",
empty.len(),
empty.is_empty(),
empty.strategy()
);

// ── Global allocation stats ────────────────────────────────────────────
println!("\n── Allocation stats (global) ──");
Expand Down Expand Up @@ -89,13 +97,17 @@ fn main() {
println!("\n── Pool warm-up ──");
pool.warm(&[8192, 32768], 2).unwrap();
let after_warm = pool.stats();
println!("After warm-up: cached={} bytes, blocks={}",
after_warm.cached_bytes, after_warm.cached_blocks);
println!(
"After warm-up: cached={} bytes, blocks={}",
after_warm.cached_bytes, after_warm.cached_blocks
);

// Per-size-class breakdown
for sc in pool.size_class_stats() {
println!(" Class {:>8} bytes: {} handles ({} bytes cached)",
sc.size_class, sc.cached_handles, sc.cached_bytes);
println!(
" Class {:>8} bytes: {} handles ({} bytes cached)",
sc.size_class, sc.cached_handles, sc.cached_bytes
);
}

// ── Pool trim (reduce memory footprint) ────────────────────────────────
Expand All @@ -106,8 +118,11 @@ fn main() {
println!("\n── Buffer reuse pattern ──");
for i in 0..3 {
let buf = Buffer::zeros(DType::F32, &[1000]).unwrap();
println!(" Iteration {i}: allocated {} elements, {} bytes",
buf.len(), buf.nbytes());
println!(
" Iteration {i}: allocated {} elements, {} bytes",
buf.len(),
buf.nbytes()
);
// buf is dropped here, its allocation returns to the pool
}
println!(" Pool after loop: {} cached bytes", pool.cached_bytes());
Expand Down
42 changes: 33 additions & 9 deletions crates/mohu-buffer/examples/buffer_basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@

use mohu_buffer::{
Buffer, SliceArg,
strides::{c_strides, f_strides, NdIndexIter, unravel_index, ravel_multi_index},
strides::{NdIndexIter, c_strides, f_strides, ravel_multi_index, unravel_index},
};
use mohu_dtype::DType;

fn main() {
// ── Buffer creation from a Rust slice ──────────────────────────────────
// NumPy: a = np.array([1.0, 2.0, 3.0, 4.0, 5.0], dtype=np.float32)
let a = Buffer::from_slice::<f32>(&[1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
println!("from_slice: dtype={}, shape={:?}, len={}", a.dtype(), a.shape(), a.len());
println!(
"from_slice: dtype={}, shape={:?}, len={}",
a.dtype(),
a.shape(),
a.len()
);

// Read elements back
let v: f32 = a.get(&[2]).unwrap();
Expand All @@ -30,7 +35,11 @@ fn main() {
// NumPy: a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float64)
let rows: &[&[f64]] = &[&[1.0, 2.0, 3.0], &[4.0, 5.0, 6.0]];
let a2d = Buffer::from_slice_2d(rows).unwrap();
println!("\nfrom_slice_2d: shape={:?}, strides={:?}", a2d.shape(), a2d.strides());
println!(
"\nfrom_slice_2d: shape={:?}, strides={:?}",
a2d.shape(),
a2d.strides()
);
let v: f64 = a2d.get(&[1, 2]).unwrap();
println!(" a[1,2] = {v}"); // 6.0

Expand Down Expand Up @@ -79,7 +88,11 @@ fn main() {
// ── Transpose (zero-copy view operation) ───────────────────────────────
// NumPy: a.T
let t = a2d.transpose();
println!("\nTranspose: shape={:?}, strides={:?}", t.shape(), t.strides());
println!(
"\nTranspose: shape={:?}, strides={:?}",
t.shape(),
t.strides()
);
let v: f64 = t.get(&[2, 1]).unwrap(); // was a2d[1,2] = 6.0
println!(" a.T[2,1] = {v}"); // 6.0

Expand All @@ -93,14 +106,25 @@ fn main() {
// ── Slicing (zero-copy view with adjusted strides) ─────────────────────
// NumPy: a[::2] (every other element)
let five = Buffer::from_slice::<f32>(&[10.0, 20.0, 30.0, 40.0, 50.0]).unwrap();
let sliced = five.slice_axis(0, SliceArg { start: Some(0), stop: None, step: Some(2) }).unwrap();
let sliced = five
.slice_axis(
0,
SliceArg {
start: Some(0),
stop: None,
step: Some(2),
},
)
.unwrap();
let data = sliced.to_vec::<f32>().unwrap();
println!("\nslice [::2]: {:?}", data); // [10.0, 30.0, 50.0]

// ── Broadcast (zero-copy virtual replication) ──────────────────────────
// NumPy: np.broadcast_to(np.array([1, 2, 3]), (3, 3))
let row = Buffer::from_slice::<f32>(&[1.0, 2.0, 3.0]).unwrap()
.expand_dims(0).unwrap();
let row = Buffer::from_slice::<f32>(&[1.0, 2.0, 3.0])
.unwrap()
.expand_dims(0)
.unwrap();
let bc = row.broadcast_to(&[3, 3]).unwrap();
println!("\nBroadcast to (3,3): shape={:?}", bc.shape());
for i in 0..3 {
Expand All @@ -115,8 +139,8 @@ fn main() {
println!("\n── Layout inspection ──");
println!("a2d C-contiguous: {}", a2d.is_c_contiguous());
println!("a2d F-contiguous: {}", a2d.is_f_contiguous());
println!("a2d.T C-contiguous: {}", t.is_c_contiguous()); // false after transpose
println!("a2d.T F-contiguous: {}", t.is_f_contiguous()); // true
println!("a2d.T C-contiguous: {}", t.is_c_contiguous()); // false after transpose
println!("a2d.T F-contiguous: {}", t.is_f_contiguous()); // true

// ── Stride arithmetic ──────────────────────────────────────────────────
println!("\n── Stride arithmetic ──");
Expand Down
Loading
Loading