Added everything to TensorAlloc
This commit is contained in:
parent
ff21f0ac8b
commit
ceff8ff1bd
@ -301,6 +301,68 @@ pub fn Tensor(
|
||||
return Self{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Extract sub-tensor by half-open ranges [start, end) per axis.
|
||||
/// All bounds comptime. Dims and scales preserved.
|
||||
/// Negative indices count from end: -1 = last element.
|
||||
pub inline fn slice(
|
||||
self: *const Self,
|
||||
alloc: Allocator,
|
||||
comptime ranges: [rank]struct { start: ?isize = null, end: ?isize = null },
|
||||
) !blk: {
|
||||
var ns: [rank]comptime_int = undefined;
|
||||
for (0..rank) |i| {
|
||||
const dim = @as(isize, @intCast(shape[i]));
|
||||
const s: isize = blk2: {
|
||||
const raw = ranges[i].start orelse 0;
|
||||
break :blk2 if (raw < 0) raw + dim else raw;
|
||||
};
|
||||
const e: isize = blk2: {
|
||||
const raw = ranges[i].end orelse dim;
|
||||
break :blk2 if (raw < 0) raw + dim else raw;
|
||||
};
|
||||
if (s < 0) @compileError("slice: start out of bounds after normalization");
|
||||
if (e < 0) @compileError("slice: end out of bounds after normalization");
|
||||
if (s >= e) @compileError("slice: start must be < end");
|
||||
if (e > dim) @compileError("slice: end exceeds shape");
|
||||
ns[i] = e - s;
|
||||
}
|
||||
const new_shape: [rank]comptime_int = ns;
|
||||
break :blk Tensor(T, dims.argsOpt(), scales.argsOpt(), &new_shape);
|
||||
} {
|
||||
const new_shape: [rank]comptime_int = comptime blk: {
|
||||
var ns: [rank]comptime_int = undefined;
|
||||
for (0..rank) |i| {
|
||||
const dim = @as(isize, @intCast(shape[i]));
|
||||
const raw_s = ranges[i].start orelse 0;
|
||||
const raw_e = ranges[i].end orelse dim;
|
||||
const s: isize = if (raw_s < 0) raw_s + dim else raw_s;
|
||||
const e: isize = if (raw_e < 0) raw_e + dim else raw_e;
|
||||
ns[i] = e - s;
|
||||
}
|
||||
break :blk ns;
|
||||
};
|
||||
const ResultType = Tensor(T, dims.argsOpt(), scales.argsOpt(), &new_shape);
|
||||
const DestVec = @Vector(ResultType.total, T);
|
||||
|
||||
const src: [total]T = self.data.*;
|
||||
var dst: [ResultType.total]T = undefined;
|
||||
for (0..ResultType.total) |flat| {
|
||||
var src_flat: usize = 0;
|
||||
inline for (0..rank) |i| {
|
||||
const dim = @as(isize, @intCast(shape[i]));
|
||||
const raw_s = ranges[i].start orelse 0;
|
||||
const s: isize = if (raw_s < 0) raw_s + dim else raw_s;
|
||||
const coord = (flat / ResultType.strides_arr[i]) % new_shape[i];
|
||||
src_flat += (coord + @as(usize, @intCast(s))) * strides_arr[i];
|
||||
}
|
||||
dst[flat] = src[src_flat];
|
||||
}
|
||||
|
||||
const vec_ptr = try alloc.create(DestVec);
|
||||
vec_ptr.* = dst;
|
||||
return ResultType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Convert to a compatible Tensor type.
|
||||
/// • Dimension mismatch → compile error.
|
||||
/// • Dest.shape must equal self.shape, or total == 1 -> splat to Dest shape (scalar pattern).
|
||||
@ -1389,262 +1451,295 @@ test "TensorAlloc | Tensor strides_arr correctness" {
|
||||
try std.testing.expectEqual(4, T3.strides_arr[1]);
|
||||
try std.testing.expectEqual(1, T3.strides_arr[2]);
|
||||
}
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D basic" {
|
||||
// const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
// var v = Vec{ .data = .{ 10, 20, 30, 40, 50 } };
|
||||
// const s = v.slice(.{.{ .start = 1, .end = 4 }});
|
||||
// try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(20, s.data[0]);
|
||||
// try std.testing.expectEqual(30, s.data[1]);
|
||||
// try std.testing.expectEqual(40, s.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D full range" {
|
||||
// const Vec = Tensor(f32, .{}, .{}, &.{4});
|
||||
// const v = Vec{ .data = .{ 1.0, 2.0, 3.0, 4.0 } };
|
||||
// const s = v.slice(.{.{ .start = 0, .end = 4 }});
|
||||
// try std.testing.expectEqual(4, @TypeOf(s).total);
|
||||
// inline for (0..4) |i| try std.testing.expectEqual(v.data[i], s.data[i]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D single element" {
|
||||
// const Vec = Tensor(i64, .{}, .{}, &.{6});
|
||||
// const v = Vec{ .data = .{ 5, 10, 15, 20, 25, 30 } };
|
||||
// const s = v.slice(.{.{ .start = 3, .end = 4 }});
|
||||
// try std.testing.expectEqual(1, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(20, s.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D preserves dims and scales" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{5});
|
||||
// const v = Meter{ .data = .{ 1, 2, 3, 4, 5 } };
|
||||
// const s = v.slice(.{.{ .start = 0, .end = 3 }});
|
||||
// const S = @TypeOf(s);
|
||||
// try std.testing.expectEqual(1, S.dims.get(.L));
|
||||
// try std.testing.expectEqual(Meter.scales.get(.L), S.scales.get(.L));
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 2D rows" {
|
||||
// const Mat = Tensor(i32, .{}, .{}, &.{ 4, 3 });
|
||||
// const m = Mat{ .data = .{
|
||||
// 1, 2, 3,
|
||||
// 4, 5, 6,
|
||||
// 7, 8, 9,
|
||||
// 10, 11, 12,
|
||||
// } };
|
||||
// // rows [1,3), all cols
|
||||
// const s = m.slice(.{ .{ .start = 1, .end = 3 }, .{ .start = 0, .end = 3 } });
|
||||
// try std.testing.expectEqual(6, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(4, s.data[0]);
|
||||
// try std.testing.expectEqual(5, s.data[1]);
|
||||
// try std.testing.expectEqual(6, s.data[2]);
|
||||
// try std.testing.expectEqual(7, s.data[3]);
|
||||
// try std.testing.expectEqual(8, s.data[4]);
|
||||
// try std.testing.expectEqual(9, s.data[5]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 2D cols" {
|
||||
// const Mat = Tensor(i32, .{}, .{}, &.{ 3, 4 });
|
||||
// const m = Mat{ .data = .{
|
||||
// 1, 2, 3, 4,
|
||||
// 5, 6, 7, 8,
|
||||
// 9, 10, 11, 12,
|
||||
// } };
|
||||
// // all rows, cols [1,3)
|
||||
// const s = m.slice(.{ .{ .start = 0, .end = 3 }, .{ .start = 1, .end = 3 } });
|
||||
// const S = @TypeOf(s);
|
||||
// try std.testing.expectEqual(3, S.shape[0]);
|
||||
// try std.testing.expectEqual(2, S.shape[1]);
|
||||
// try std.testing.expectEqual(2, s.data[0]);
|
||||
// try std.testing.expectEqual(3, s.data[1]);
|
||||
// try std.testing.expectEqual(6, s.data[2]);
|
||||
// try std.testing.expectEqual(7, s.data[3]);
|
||||
// try std.testing.expectEqual(10, s.data[4]);
|
||||
// try std.testing.expectEqual(11, s.data[5]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 2D subblock" {
|
||||
// const Mat = Tensor(f64, .{}, .{}, &.{ 4, 4 });
|
||||
// const m = Mat{ .data = .{
|
||||
// 1, 2, 3, 4,
|
||||
// 5, 6, 7, 8,
|
||||
// 9, 10, 11, 12,
|
||||
// 13, 14, 15, 16,
|
||||
// } };
|
||||
// // centre 2x2
|
||||
// const s = m.slice(.{ .{ .start = 1, .end = 3 }, .{ .start = 1, .end = 3 } });
|
||||
// try std.testing.expectEqual(4, @TypeOf(s).total);
|
||||
// try std.testing.expectApproxEqAbs(6.0, s.data[0], 1e-9);
|
||||
// try std.testing.expectApproxEqAbs(7.0, s.data[1], 1e-9);
|
||||
// try std.testing.expectApproxEqAbs(10.0, s.data[2], 1e-9);
|
||||
// try std.testing.expectApproxEqAbs(11.0, s.data[3], 1e-9);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice then add" {
|
||||
// const Meter = Tensor(i32, .{ .L = 1 }, .{}, &.{5});
|
||||
// const a = Meter{ .data = .{ 1, 2, 3, 4, 5 } };
|
||||
// const b = Meter{ .data = .{ 10, 20, 30, 40, 50 } };
|
||||
// const sa = a.slice(.{.{ .start = 0, .end = 3 }});
|
||||
// const sb = b.slice(.{.{ .start = 2, .end = 5 }});
|
||||
// const r = sa.add(sb);
|
||||
// try std.testing.expectEqual(31, r.data[0]); // 1+30
|
||||
// try std.testing.expectEqual(42, r.data[1]); // 2+40
|
||||
// try std.testing.expectEqual(53, r.data[2]); // 3+50
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice then scale convert" {
|
||||
// const KiloMeter = Tensor(i64, .{ .L = 1 }, .{ .L = .k }, &.{4});
|
||||
// const Meter = Tensor(i64, .{ .L = 1 }, .{}, &.{2});
|
||||
// const v = KiloMeter{ .data = .{ 1, 2, 3, 4 } };
|
||||
// const s = v.slice(.{.{ .start = 1, .end = 3 }}); // {2, 3} km
|
||||
// const converted = s.to(Meter);
|
||||
// try std.testing.expectEqual(2000, converted.data[0]);
|
||||
// try std.testing.expectEqual(3000, converted.data[1]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D negative start" {
|
||||
// const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
// const v = Vec{ .data = .{ 10, 20, 30, 40, 50 } };
|
||||
// const s = v.slice(.{.{ .start = -3, .end = 5 }}); // [2,5) → 30,40,50
|
||||
// try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(30, s.data[0]);
|
||||
// try std.testing.expectEqual(40, s.data[1]);
|
||||
// try std.testing.expectEqual(50, s.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D negative end" {
|
||||
// const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
// const v = Vec{ .data = .{ 10, 20, 30, 40, 50 } };
|
||||
// const s = v.slice(.{.{ .start = 1, .end = -1 }}); // [1,4) → 20,30,40
|
||||
// try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(20, s.data[0]);
|
||||
// try std.testing.expectEqual(30, s.data[1]);
|
||||
// try std.testing.expectEqual(40, s.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D both negative" {
|
||||
// const Vec = Tensor(i64, .{}, .{}, &.{6});
|
||||
// const v = Vec{ .data = .{ 5, 10, 15, 20, 25, 30 } };
|
||||
// const s = v.slice(.{.{ .start = -4, .end = -1 }}); // [2,5) → 15,20,25
|
||||
// try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(15, s.data[0]);
|
||||
// try std.testing.expectEqual(20, s.data[1]);
|
||||
// try std.testing.expectEqual(25, s.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D null start" {
|
||||
// const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
// const v = Vec{ .data = .{ 10, 20, 30, 40, 50 } };
|
||||
// const s = v.slice(.{.{ .end = -2 }}); // [:-2] → 10,20,30
|
||||
// try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(10, s.data[0]);
|
||||
// try std.testing.expectEqual(20, s.data[1]);
|
||||
// try std.testing.expectEqual(30, s.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 1D null end" {
|
||||
// const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
// const v = Vec{ .data = .{ 10, 20, 30, 40, 50 } };
|
||||
// const s = v.slice(.{.{ .start = -3 }}); // [-3:] → 30,40,50
|
||||
// try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(30, s.data[0]);
|
||||
// try std.testing.expectEqual(40, s.data[1]);
|
||||
// try std.testing.expectEqual(50, s.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Slice 2D negative & null indices" {
|
||||
// const Mat = Tensor(i32, .{}, .{}, &.{ 4, 4 });
|
||||
// const m = Mat{ .data = .{
|
||||
// 1, 2, 3, 4,
|
||||
// 5, 6, 7, 8,
|
||||
// 9, 10, 11, 12,
|
||||
// 13, 14, 15, 16,
|
||||
// } };
|
||||
// // last 2 rows, last 2 cols → same as subblock test [2,4)x[2,4)
|
||||
// const s = m.slice(.{ .{ .start = -2, .end = 4 }, .{ .start = -2 } });
|
||||
// try std.testing.expectEqual(4, @TypeOf(s).total);
|
||||
// try std.testing.expectEqual(11, s.data[0]);
|
||||
// try std.testing.expectEqual(12, s.data[1]);
|
||||
// try std.testing.expectEqual(15, s.data[2]);
|
||||
// try std.testing.expectEqual(16, s.data[3]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | RLS heap basic" {
|
||||
// const allocator = std.testing.allocator;
|
||||
// const Meter = Tensor(f32, .{ .L = 1 }, .{}, &.{1});
|
||||
//
|
||||
// const c = try allocator.create(Meter);
|
||||
// defer allocator.destroy(c);
|
||||
// c.* = Meter.splat(42.0);
|
||||
//
|
||||
// try std.testing.expectEqual(42.0, c.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | RLS heap add vec3" {
|
||||
// const allocator = std.testing.allocator;
|
||||
// const Meter = Tensor(f32, .{ .L = 1 }, .{}, &.{3});
|
||||
//
|
||||
// const a = Meter{ .data = .{ 1.0, 2.0, 3.0 } };
|
||||
// const b = Meter{ .data = .{ 10.0, 20.0, 30.0 } };
|
||||
//
|
||||
// const c = try allocator.create(@TypeOf(a.add(b)));
|
||||
// defer allocator.destroy(c);
|
||||
// c.* = a.add(b); // RLS: direct into heap
|
||||
//
|
||||
// try std.testing.expectEqual(11.0, c.data[0]);
|
||||
// try std.testing.expectEqual(22.0, c.data[1]);
|
||||
// try std.testing.expectEqual(33.0, c.data[2]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | RLS heap cross-scale add" {
|
||||
// const allocator = std.testing.allocator;
|
||||
// const Meter = Tensor(i64, .{ .L = 1 }, .{}, &.{1});
|
||||
// const KiloMeter = Tensor(i64, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
//
|
||||
// const c = try allocator.create(@TypeOf(Meter.splat(0).add(KiloMeter.splat(0))));
|
||||
// defer allocator.destroy(c);
|
||||
// c.* = Meter.splat(500).add(KiloMeter.splat(1)); // 500 + 1000 = 1500m
|
||||
//
|
||||
// try std.testing.expectEqual(1500, c.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | RLS heap matmul" {
|
||||
// const allocator = std.testing.allocator;
|
||||
// const A = Tensor(f32, .{}, .{}, &.{ 2, 3 });
|
||||
// const B = Tensor(f32, .{}, .{}, &.{ 3, 2 });
|
||||
//
|
||||
// const a = A{ .data = .{ 1, 2, 3, 4, 5, 6 } };
|
||||
// const b = B{ .data = .{ 7, 8, 9, 10, 11, 12 } };
|
||||
//
|
||||
// const c = try allocator.create(@TypeOf(a.contract(b, 1, 0)));
|
||||
// defer allocator.destroy(c);
|
||||
// c.* = a.contract(b, 1, 0); // RLS: direct into heap
|
||||
//
|
||||
// const R = Tensor(f32, .{}, .{}, &.{ 2, 2 });
|
||||
// try std.testing.expectEqual(58.0, c.data[R.idx(.{ 0, 0 })]);
|
||||
// try std.testing.expectEqual(64.0, c.data[R.idx(.{ 0, 1 })]);
|
||||
// try std.testing.expectEqual(139.0, c.data[R.idx(.{ 1, 0 })]);
|
||||
// try std.testing.expectEqual(154.0, c.data[R.idx(.{ 1, 1 })]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | RLS heap big tensor (near 1MB limit)" {
|
||||
// const allocator = std.testing.allocator;
|
||||
// // 31249 * 32bits = 999_968 bits — just under compile error
|
||||
// const BigVec = Tensor(f32, .{ .L = 1 }, .{}, &.{31249});
|
||||
//
|
||||
// const a = try allocator.create(BigVec);
|
||||
// defer allocator.destroy(a);
|
||||
// a.* = BigVec.splat(1.0);
|
||||
//
|
||||
// const b = try allocator.create(BigVec);
|
||||
// defer allocator.destroy(b);
|
||||
// b.* = BigVec.splat(2.0);
|
||||
//
|
||||
// const c = try allocator.create(@TypeOf(a.add(b.*)));
|
||||
// defer allocator.destroy(c);
|
||||
// c.* = a.add(b.*); // RLS: ~125KB result direct into heap
|
||||
//
|
||||
// try std.testing.expectEqual(3.0, c.data[0]);
|
||||
// try std.testing.expectEqual(3.0, c.data[31248]);
|
||||
// }
|
||||
|
||||
test "TensorAlloc | Slice 1D basic" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
var v = try Vec.load(alloc, &.{ 10, 20, 30, 40, 50 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = 1, .end = 4 }});
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(20, s.data[0]);
|
||||
try std.testing.expectEqual(30, s.data[1]);
|
||||
try std.testing.expectEqual(40, s.data[2]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D full range" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(f32, .{}, .{}, &.{4});
|
||||
const v = try Vec.load(alloc, &.{ 1.0, 2.0, 3.0, 4.0 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = 0, .end = 4 }});
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(4, @TypeOf(s).total);
|
||||
inline for (0..4) |i| try std.testing.expectEqual(v.data[i], s.data[i]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D single element" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(i64, .{}, .{}, &.{6});
|
||||
const v = try Vec.load(alloc, &.{ 5, 10, 15, 20, 25, 30 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = 3, .end = 4 }});
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(1, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(20, s.data[0]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D preserves dims and scales" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{5});
|
||||
const v = try Meter.load(alloc, &.{ 1, 2, 3, 4, 5 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = 0, .end = 3 }});
|
||||
defer s.deinit(alloc);
|
||||
|
||||
const S = @TypeOf(s);
|
||||
try std.testing.expectEqual(1, S.dims.get(.L));
|
||||
try std.testing.expectEqual(Meter.scales.get(.L), S.scales.get(.L));
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 2D rows" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Mat = Tensor(i32, .{}, .{}, &.{ 4, 3 });
|
||||
const m = try Mat.load(alloc, &.{
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
10, 11, 12,
|
||||
});
|
||||
defer m.deinit(alloc);
|
||||
|
||||
// rows [1,3), all cols
|
||||
const s = try m.slice(alloc, .{ .{ .start = 1, .end = 3 }, .{ .start = 0, .end = 3 } });
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(6, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(4, s.data[0]);
|
||||
try std.testing.expectEqual(5, s.data[1]);
|
||||
try std.testing.expectEqual(6, s.data[2]);
|
||||
try std.testing.expectEqual(7, s.data[3]);
|
||||
try std.testing.expectEqual(8, s.data[4]);
|
||||
try std.testing.expectEqual(9, s.data[5]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 2D cols" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Mat = Tensor(i32, .{}, .{}, &.{ 3, 4 });
|
||||
const m = try Mat.load(alloc, &.{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
});
|
||||
defer m.deinit(alloc);
|
||||
|
||||
// all rows, cols [1,3)
|
||||
const s = try m.slice(alloc, .{ .{ .start = 0, .end = 3 }, .{ .start = 1, .end = 3 } });
|
||||
defer s.deinit(alloc);
|
||||
|
||||
const S = @TypeOf(s);
|
||||
try std.testing.expectEqual(3, S.shape[0]);
|
||||
try std.testing.expectEqual(2, S.shape[1]);
|
||||
try std.testing.expectEqual(2, s.data[0]);
|
||||
try std.testing.expectEqual(3, s.data[1]);
|
||||
try std.testing.expectEqual(6, s.data[2]);
|
||||
try std.testing.expectEqual(7, s.data[3]);
|
||||
try std.testing.expectEqual(10, s.data[4]);
|
||||
try std.testing.expectEqual(11, s.data[5]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 2D subblock" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Mat = Tensor(f64, .{}, .{}, &.{ 4, 4 });
|
||||
const m = try Mat.load(alloc, &.{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
});
|
||||
defer m.deinit(alloc);
|
||||
|
||||
// centre 2x2
|
||||
const s = try m.slice(alloc, .{ .{ .start = 1, .end = 3 }, .{ .start = 1, .end = 3 } });
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(4, @TypeOf(s).total);
|
||||
try std.testing.expectApproxEqAbs(6.0, s.data[0], 1e-9);
|
||||
try std.testing.expectApproxEqAbs(7.0, s.data[1], 1e-9);
|
||||
try std.testing.expectApproxEqAbs(10.0, s.data[2], 1e-9);
|
||||
try std.testing.expectApproxEqAbs(11.0, s.data[3], 1e-9);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice then add" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Meter = Tensor(i32, .{ .L = 1 }, .{}, &.{5});
|
||||
const a = try Meter.load(alloc, &.{ 1, 2, 3, 4, 5 });
|
||||
defer a.deinit(alloc);
|
||||
const b = try Meter.load(alloc, &.{ 10, 20, 30, 40, 50 });
|
||||
defer b.deinit(alloc);
|
||||
|
||||
const sa = try a.slice(alloc, .{.{ .start = 0, .end = 3 }});
|
||||
defer sa.deinit(alloc);
|
||||
const sb = try b.slice(alloc, .{.{ .start = 2, .end = 5 }});
|
||||
defer sb.deinit(alloc);
|
||||
|
||||
const r = try sa.add(alloc, sb);
|
||||
defer r.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(31, r.data[0]); // 1+30
|
||||
try std.testing.expectEqual(42, r.data[1]); // 2+40
|
||||
try std.testing.expectEqual(53, r.data[2]); // 3+50
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice then scale convert" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const KiloMeter = Tensor(i64, .{ .L = 1 }, .{ .L = .k }, &.{4});
|
||||
const Meter = Tensor(i64, .{ .L = 1 }, .{}, &.{2});
|
||||
const v = try KiloMeter.load(alloc, &.{ 1, 2, 3, 4 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = 1, .end = 3 }}); // {2, 3} km
|
||||
defer s.deinit(alloc);
|
||||
|
||||
const converted = try s.to(alloc, Meter);
|
||||
defer converted.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(2000, converted.data[0]);
|
||||
try std.testing.expectEqual(3000, converted.data[1]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D negative start" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
const v = try Vec.load(alloc, &.{ 10, 20, 30, 40, 50 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = -3, .end = 5 }}); // [2,5) → 30,40,50
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(30, s.data[0]);
|
||||
try std.testing.expectEqual(40, s.data[1]);
|
||||
try std.testing.expectEqual(50, s.data[2]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D negative end" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
const v = try Vec.load(alloc, &.{ 10, 20, 30, 40, 50 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = 1, .end = -1 }}); // [1,4) → 20,30,40
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(20, s.data[0]);
|
||||
try std.testing.expectEqual(30, s.data[1]);
|
||||
try std.testing.expectEqual(40, s.data[2]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D both negative" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(i64, .{}, .{}, &.{6});
|
||||
const v = try Vec.load(alloc, &.{ 5, 10, 15, 20, 25, 30 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = -4, .end = -1 }}); // [2,5) → 15,20,25
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(15, s.data[0]);
|
||||
try std.testing.expectEqual(20, s.data[1]);
|
||||
try std.testing.expectEqual(25, s.data[2]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D null start" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
const v = try Vec.load(alloc, &.{ 10, 20, 30, 40, 50 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .end = -2 }}); // [:-2] → 10,20,30
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(10, s.data[0]);
|
||||
try std.testing.expectEqual(20, s.data[1]);
|
||||
try std.testing.expectEqual(30, s.data[2]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 1D null end" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Vec = Tensor(i32, .{}, .{}, &.{5});
|
||||
const v = try Vec.load(alloc, &.{ 10, 20, 30, 40, 50 });
|
||||
defer v.deinit(alloc);
|
||||
|
||||
const s = try v.slice(alloc, .{.{ .start = -3 }}); // [-3:] → 30,40,50
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(3, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(30, s.data[0]);
|
||||
try std.testing.expectEqual(40, s.data[1]);
|
||||
try std.testing.expectEqual(50, s.data[2]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Slice 2D negative & null indices" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const Mat = Tensor(i32, .{}, .{}, &.{ 4, 4 });
|
||||
const m = try Mat.load(alloc, &.{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
});
|
||||
defer m.deinit(alloc);
|
||||
|
||||
// last 2 rows, last 2 cols → same as subblock test [2,4)x[2,4)
|
||||
const s = try m.slice(alloc, .{ .{ .start = -2, .end = 4 }, .{ .start = -2 } });
|
||||
defer s.deinit(alloc);
|
||||
|
||||
try std.testing.expectEqual(4, @TypeOf(s).total);
|
||||
try std.testing.expectEqual(11, s.data[0]);
|
||||
try std.testing.expectEqual(12, s.data[1]);
|
||||
try std.testing.expectEqual(15, s.data[2]);
|
||||
try std.testing.expectEqual(16, s.data[3]);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user