Working other base operation (sub, mul, div, ect)
This commit is contained in:
parent
7494595db4
commit
0ef19e18de
@ -98,6 +98,196 @@ pub fn Tensor(
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Element-wise sub. Dimensions must match; scales resolve to finer.
|
||||
/// RHS must have the same shape as self, or total == 1 (broadcast).
|
||||
pub inline fn sub(self: *const Self, alloc: Allocator, rhs: anytype) !Tensor(
|
||||
T,
|
||||
dims.argsOpt(),
|
||||
sh.finerScales(Self, @TypeOf(rhs)).argsOpt(),
|
||||
shape,
|
||||
) {
|
||||
const RhsType = @TypeOf(rhs);
|
||||
if (comptime !sh.isTensor(RhsType))
|
||||
@compileError("rhs can only be a Tensor ");
|
||||
if (comptime !dims.eql(RhsType.dims))
|
||||
@compileError("Dimension mismatch in sub: " ++ dims.str() ++ " vs " ++ RhsType.dims.str());
|
||||
if (comptime RhsType.total != 1 and !sh.shapeEql(shape, RhsType.shape))
|
||||
@compileError("Shape mismatch in sub: element-wise operations require identical shapes, or a scalar RHS.");
|
||||
|
||||
const TargetType = Tensor(T, dims.argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
const l: TargetType = try self.to(alloc, TargetType);
|
||||
defer l.deinit(alloc);
|
||||
const r: TargetType = try rhs.to(alloc, TargetType);
|
||||
defer r.deinit(alloc);
|
||||
|
||||
const result_vec = if (comptime sh.isInt(T))
|
||||
l.data.* -| r.data.*
|
||||
else
|
||||
l.data.* - r.data.*;
|
||||
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Element-wise multiply. Dimension exponents summed.
|
||||
/// Shape {1} RHS is automatically broadcast across all elements.
|
||||
pub inline fn mul(self: *const Self, alloc: Allocator, rhs: anytype) !Tensor(
|
||||
T,
|
||||
dims.add(@TypeOf(rhs).dims).argsOpt(),
|
||||
sh.finerScales(Self, @TypeOf(rhs)).argsOpt(),
|
||||
shape,
|
||||
) {
|
||||
const RhsType = @TypeOf(rhs);
|
||||
if (comptime !sh.isTensor(RhsType))
|
||||
@compileError("rhs can only be a Tensor ");
|
||||
if (comptime RhsType.total != 1 and !sh.shapeEql(shape, RhsType.shape))
|
||||
@compileError("Shape mismatch in mul: element-wise operations require identical shapes, or a scalar RHS.");
|
||||
|
||||
const SelfNorm = Tensor(T, dims.argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
const RhsNorm = Tensor(T, RhsType.dims.argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
const TargetType = Tensor(T, dims.add(RhsType.dims).argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
|
||||
const l: SelfNorm = try self.to(alloc, SelfNorm);
|
||||
defer l.deinit(alloc);
|
||||
const r: RhsNorm = try rhs.to(alloc, RhsNorm);
|
||||
defer r.deinit(alloc);
|
||||
|
||||
const result_vec = if (comptime sh.isInt(T))
|
||||
l.data.* *| r.data.*
|
||||
else
|
||||
l.data.* * r.data.*;
|
||||
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Element-wise divide. Dimension exponents subtracted.
|
||||
/// Shape {1} RHS is automatically broadcast across all elements.
|
||||
pub inline fn div(self: *const Self, alloc: Allocator, rhs: anytype) !Tensor(
|
||||
T,
|
||||
dims.sub(@TypeOf(rhs).dims).argsOpt(),
|
||||
sh.finerScales(Self, @TypeOf(rhs)).argsOpt(),
|
||||
shape,
|
||||
) {
|
||||
const RhsType = @TypeOf(rhs);
|
||||
if (comptime !sh.isTensor(RhsType))
|
||||
@compileError("rhs can only be a Tensor ");
|
||||
if (comptime RhsType.total != 1 and !sh.shapeEql(shape, RhsType.shape))
|
||||
@compileError("Shape mismatch in div: element-wise operations require identical shapes, or a scalar RHS.");
|
||||
|
||||
const SelfNorm = Tensor(T, dims.argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
const RhsNorm = Tensor(T, RhsType.dims.argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
const TargetType = Tensor(T, dims.sub(RhsType.dims).argsOpt(), sh.finerScales(Self, RhsType).argsOpt(), shape);
|
||||
|
||||
const l: SelfNorm = try self.to(alloc, SelfNorm);
|
||||
defer l.deinit(alloc);
|
||||
const r: RhsNorm = try rhs.to(alloc, RhsNorm);
|
||||
defer r.deinit(alloc);
|
||||
|
||||
const result_vec = if (comptime sh.isInt(T))
|
||||
@divTrunc(l.data.*, r.data.*)
|
||||
else
|
||||
l.data.* / r.data.*;
|
||||
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Absolute value of every element.
|
||||
pub inline fn abs(self: *const Self, alloc: Allocator) !Self {
|
||||
const result_vec = @as(Vec, @bitCast(@abs(self.data.*)));
|
||||
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
|
||||
return Self{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Raise every element to a comptime integer exponent.
|
||||
pub inline fn pow(self: *const Self, alloc: Allocator, comptime exp: comptime_int) !Tensor(
|
||||
T,
|
||||
dims.scale(exp).argsOpt(),
|
||||
scales.argsOpt(),
|
||||
shape,
|
||||
) {
|
||||
if (comptime exp < 0) @compileError("Pow only support exp >= 0");
|
||||
|
||||
const TargetType = Tensor(T, dims.scale(exp).argsOpt(), scales.argsOpt(), shape);
|
||||
|
||||
if (comptime exp == 0) {
|
||||
const result_vec: Vec = @splat(1);
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
if (comptime exp == 1) {
|
||||
// Copy allocation to ensure `.deinit(alloc)` works cleanly for the caller
|
||||
const vec_ptr = try alloc.create(Vec);
|
||||
vec_ptr.* = self.data.*;
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
var data: Vec = self.data.*;
|
||||
for (0..exp - 1) |_|
|
||||
data = data * self.data.*;
|
||||
|
||||
const vec_ptr = try alloc.create(@TypeOf(data));
|
||||
vec_ptr.* = data;
|
||||
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Square root of every element. All dimension exponents must be even.
|
||||
pub inline fn sqrt(self: *const Self, alloc: Allocator) !Tensor(
|
||||
T,
|
||||
dims.div(2).argsOpt(),
|
||||
scales.argsOpt(),
|
||||
shape,
|
||||
) {
|
||||
if (comptime !dims.isSquare())
|
||||
@compileError("Cannot take sqrt of " ++ dims.str() ++ ": exponents must be even.");
|
||||
|
||||
const TargetType = Tensor(T, dims.div(2).argsOpt(), scales.argsOpt(), shape);
|
||||
|
||||
if (comptime @typeInfo(T) == .float) {
|
||||
const result_vec = @sqrt(self.data.*);
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
const arr: [total]T = self.data.*;
|
||||
var res_arr: [total]T = undefined;
|
||||
const UnsignedT = @Int(.unsigned, @typeInfo(T).int.bits);
|
||||
|
||||
for (0..total) |i| {
|
||||
const v = arr[i];
|
||||
res_arr[i] = if (v < 0) 0 else @as(T, @intCast(std.math.sqrt(@as(UnsignedT, @intCast(v)))));
|
||||
}
|
||||
|
||||
const vec_ptr = try alloc.create(Vec);
|
||||
vec_ptr.* = res_arr;
|
||||
|
||||
return TargetType{ .data = vec_ptr };
|
||||
}
|
||||
|
||||
/// Negate every element.
|
||||
pub inline fn negate(self: *const Self, alloc: Allocator) !Self {
|
||||
const result_vec = -self.data.*;
|
||||
|
||||
const vec_ptr = try alloc.create(@TypeOf(result_vec));
|
||||
vec_ptr.* = result_vec;
|
||||
|
||||
return Self{ .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).
|
||||
@ -349,165 +539,221 @@ test "TensorAlloc | Scalar Add" {
|
||||
const added2 = try distance.add(alloc, distance3);
|
||||
try std.testing.expectEqual(2010, added2.data[0]);
|
||||
|
||||
const added3 = try (try distance3.add(alloc, distance)).to(alloc, KiloMeter);
|
||||
const added3_tmp = try distance3.add(alloc, distance);
|
||||
const added3 = try added3_tmp.to(alloc, KiloMeter);
|
||||
try std.testing.expectEqual(2, added3.data[0]);
|
||||
|
||||
const distance4 = try KiloMeter_f.splat(alloc, 2);
|
||||
const added4 = try (try distance4.add(alloc, distance)).to(alloc, KiloMeter_f);
|
||||
const added4_tmp = try distance4.add(alloc, distance);
|
||||
const added4 = try added4_tmp.to(alloc, KiloMeter_f);
|
||||
try std.testing.expectApproxEqAbs(2.01, added4.data[0], 0.000001);
|
||||
}
|
||||
|
||||
// test "TensorAlloc | Scalar Sub" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
// const KiloMeter_f = Tensor(f64, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
//
|
||||
// const a = Meter.splat(500);
|
||||
// const b = Meter.splat(200);
|
||||
// const diff = a.sub(b);
|
||||
// try std.testing.expectEqual(300, diff.data[0]);
|
||||
// const diff2 = b.sub(a);
|
||||
// try std.testing.expectEqual(-300, diff2.data[0]);
|
||||
//
|
||||
// const km_f = KiloMeter_f.splat(2.5);
|
||||
// const m_f = Meter.splat(500);
|
||||
// const diff3 = km_f.sub(m_f);
|
||||
// try std.testing.expectApproxEqAbs(2000, diff3.data[0], 1e-4);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar MulBy" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
// const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
//
|
||||
// const d = Meter.splat(3);
|
||||
// const t = Second.splat(4);
|
||||
// const at = d.mul(t);
|
||||
// try std.testing.expectEqual(12, at.data[0]);
|
||||
// try std.testing.expectEqual(1, @TypeOf(at).dims.get(.L));
|
||||
// try std.testing.expectEqual(1, @TypeOf(at).dims.get(.T));
|
||||
//
|
||||
// const d2 = Meter.splat(5);
|
||||
// const area = d.mul(d2);
|
||||
// try std.testing.expectEqual(15, area.data[0]);
|
||||
// try std.testing.expectEqual(2, @TypeOf(area).dims.get(.L));
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar MulBy with scale" {
|
||||
// const KiloMeter = Tensor(f32, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
// const KiloGram = Tensor(f32, .{ .M = 1 }, .{ .M = .k }, &.{1});
|
||||
//
|
||||
// const dist = KiloMeter.splat(2.0);
|
||||
// const mass = KiloGram.splat(3.0);
|
||||
// const prod = dist.mul(mass);
|
||||
// try std.testing.expectEqual(1, @TypeOf(prod).dims.get(.L));
|
||||
// try std.testing.expectEqual(1, @TypeOf(prod).dims.get(.M));
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar MulBy with type change" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
// const Second = Tensor(f64, .{ .T = 1 }, .{}, &.{1});
|
||||
// const KmSec = Tensor(i64, .{ .L = 1, .T = 1 }, .{ .L = .k }, &.{1});
|
||||
// const KmSec_f = Tensor(f32, .{ .L = 1, .T = 1 }, .{ .L = .k }, &.{1});
|
||||
//
|
||||
// const d = Meter.splat(3);
|
||||
// const t = Second.splat(4);
|
||||
//
|
||||
// try std.testing.expectEqual(12, d.mul(t).to(KmSec).data[0]);
|
||||
// try std.testing.expectApproxEqAbs(12.0, d.mul(t).to(KmSec_f).data[0], 0.0001);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar MulBy small" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{ .L = .n }, &.{1});
|
||||
// const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
// const d = Meter.splat(3);
|
||||
// const t = Second.splat(4);
|
||||
// try std.testing.expectEqual(12, d.mul(t).data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar MulBy dimensionless" {
|
||||
// const DimLess = Tensor(i128, .{}, .{}, &.{1});
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
// const d = Meter.splat(7);
|
||||
// const scaled = d.mul(DimLess.splat(3));
|
||||
// try std.testing.expectEqual(21, scaled.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar Sqrt" {
|
||||
// const MeterSquare = Tensor(i128, .{ .L = 2 }, .{}, &.{1});
|
||||
// const MeterSquare_f = Tensor(f64, .{ .L = 2 }, .{}, &.{1});
|
||||
//
|
||||
// var d = MeterSquare.splat(9);
|
||||
// var scaled = d.sqrt();
|
||||
// try std.testing.expectEqual(3, scaled.data[0]);
|
||||
// try std.testing.expectEqual(1, @TypeOf(scaled).dims.get(.L));
|
||||
//
|
||||
// d = MeterSquare.splat(-5);
|
||||
// scaled = d.sqrt();
|
||||
// try std.testing.expectEqual(0, scaled.data[0]);
|
||||
//
|
||||
// const d2 = MeterSquare_f.splat(20);
|
||||
// const scaled2 = d2.sqrt();
|
||||
// try std.testing.expectApproxEqAbs(4.472135955, scaled2.data[0], 1e-4);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar Chained: velocity and acceleration" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
// const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
//
|
||||
// const dist = Meter.splat(100);
|
||||
// const t1 = Second.splat(5);
|
||||
// const velocity = dist.div(t1);
|
||||
// try std.testing.expectEqual(20, velocity.data[0]);
|
||||
//
|
||||
// const t2 = Second.splat(4);
|
||||
// const accel = velocity.div(t2);
|
||||
// try std.testing.expectEqual(5, accel.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar DivBy integer exact" {
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
// const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
//
|
||||
// const dist = Meter.splat(120);
|
||||
// const time = Second.splat(4);
|
||||
// const vel = dist.div(time);
|
||||
// try std.testing.expectEqual(30, vel.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar Finer scales skip dim 0" {
|
||||
// const Dimless = Tensor(i128, .{}, .{}, &.{1});
|
||||
// const KiloMetre = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
//
|
||||
// const r = Dimless.splat(30);
|
||||
// const km = KiloMetre.splat(4);
|
||||
// const vel = r.mul(km);
|
||||
// try std.testing.expectEqual(120, vel.data[0]);
|
||||
// try std.testing.expectEqual(Scales.UnitScale.k, @TypeOf(vel).scales.get(.L));
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar Conversion chain: km -> m -> cm" {
|
||||
// const KiloMeter = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
// const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
// const CentiMeter = Tensor(i128, .{ .L = 1 }, .{ .L = .c }, &.{1});
|
||||
//
|
||||
// const km = KiloMeter.splat(15);
|
||||
// const m = km.to(Meter);
|
||||
// const cm = m.to(CentiMeter);
|
||||
// try std.testing.expectEqual(15_000, m.data[0]);
|
||||
// try std.testing.expectEqual(1_500_000, cm.data[0]);
|
||||
// }
|
||||
//
|
||||
// test "TensorAlloc | Scalar Conversion: hours -> minutes -> seconds" {
|
||||
// const Hour = Tensor(i128, .{ .T = 1 }, .{ .T = .hour }, &.{1});
|
||||
// const Minute = Tensor(i128, .{ .T = 1 }, .{ .T = .min }, &.{1});
|
||||
// const Second = Tensor(i128, .{ .T = 1 }, .{}, &.{1});
|
||||
//
|
||||
// const h = Hour.splat(1);
|
||||
// const min = h.to(Minute);
|
||||
// const sec = min.to(Second);
|
||||
// try std.testing.expectEqual(60, min.data[0]);
|
||||
// try std.testing.expectEqual(3600, sec.data[0]);
|
||||
// }
|
||||
//
|
||||
test "TensorAlloc | Scalar Sub" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
const KiloMeter_f = Tensor(f64, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
|
||||
const a = try Meter.splat(alloc, 500);
|
||||
const b = try Meter.splat(alloc, 200);
|
||||
const diff = try a.sub(alloc, b);
|
||||
try std.testing.expectEqual(300, diff.data[0]);
|
||||
const diff2 = try b.sub(alloc, a);
|
||||
try std.testing.expectEqual(-300, diff2.data[0]);
|
||||
|
||||
const km_f = try KiloMeter_f.splat(alloc, 2.5);
|
||||
const m_f = try Meter.splat(alloc, 500);
|
||||
const diff3 = try km_f.sub(alloc, m_f);
|
||||
try std.testing.expectApproxEqAbs(2000.0, diff3.data[0], 1e-4);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar MulBy" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
|
||||
const d = try Meter.splat(alloc, 3);
|
||||
const t = try Second.splat(alloc, 4);
|
||||
const at = try d.mul(alloc, t);
|
||||
try std.testing.expectEqual(12, at.data[0]);
|
||||
try std.testing.expectEqual(1, @TypeOf(at).dims.get(.L));
|
||||
try std.testing.expectEqual(1, @TypeOf(at).dims.get(.T));
|
||||
|
||||
const d2 = try Meter.splat(alloc, 5);
|
||||
const area = try d.mul(alloc, d2);
|
||||
try std.testing.expectEqual(15, area.data[0]);
|
||||
try std.testing.expectEqual(2, @TypeOf(area).dims.get(.L));
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar MulBy with scale" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const KiloMeter = Tensor(f32, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
const KiloGram = Tensor(f32, .{ .M = 1 }, .{ .M = .k }, &.{1});
|
||||
|
||||
const dist = try KiloMeter.splat(alloc, 2.0);
|
||||
const mass = try KiloGram.splat(alloc, 3.0);
|
||||
const prod = try dist.mul(alloc, mass);
|
||||
try std.testing.expectEqual(1, @TypeOf(prod).dims.get(.L));
|
||||
try std.testing.expectEqual(1, @TypeOf(prod).dims.get(.M));
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar MulBy with type change" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
const Second = Tensor(f64, .{ .T = 1 }, .{}, &.{1});
|
||||
const KmSec = Tensor(i64, .{ .L = 1, .T = 1 }, .{ .L = .k }, &.{1});
|
||||
const KmSec_f = Tensor(f32, .{ .L = 1, .T = 1 }, .{ .L = .k }, &.{1});
|
||||
|
||||
const d = try Meter.splat(alloc, 3);
|
||||
const t = try Second.splat(alloc, 4);
|
||||
const dt_prod = try d.mul(alloc, t);
|
||||
|
||||
const kmsec_val = try dt_prod.to(alloc, KmSec);
|
||||
try std.testing.expectEqual(12, kmsec_val.data[0]);
|
||||
|
||||
const kmsec_f_val = try dt_prod.to(alloc, KmSec_f);
|
||||
try std.testing.expectApproxEqAbs(12.0, kmsec_f_val.data[0], 0.0001);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar MulBy small" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{ .L = .n }, &.{1});
|
||||
const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
const d = try Meter.splat(alloc, 3);
|
||||
const t = try Second.splat(alloc, 4);
|
||||
const dt = try d.mul(alloc, t);
|
||||
try std.testing.expectEqual(12, dt.data[0]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar MulBy dimensionless" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const DimLess = Tensor(i128, .{}, .{}, &.{1});
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
const d = try Meter.splat(alloc, 7);
|
||||
const dl = try DimLess.splat(alloc, 3);
|
||||
const scaled = try d.mul(alloc, dl);
|
||||
try std.testing.expectEqual(21, scaled.data[0]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar Sqrt" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const MeterSquare = Tensor(i128, .{ .L = 2 }, .{}, &.{1});
|
||||
const MeterSquare_f = Tensor(f64, .{ .L = 2 }, .{}, &.{1});
|
||||
|
||||
var d = try MeterSquare.splat(alloc, 9);
|
||||
var scaled = try d.sqrt(alloc);
|
||||
try std.testing.expectEqual(3, scaled.data[0]);
|
||||
try std.testing.expectEqual(1, @TypeOf(scaled).dims.get(.L));
|
||||
|
||||
d = try MeterSquare.splat(alloc, -5);
|
||||
scaled = try d.sqrt(alloc);
|
||||
try std.testing.expectEqual(0, scaled.data[0]);
|
||||
|
||||
const d2 = try MeterSquare_f.splat(alloc, 20);
|
||||
const scaled2 = try d2.sqrt(alloc);
|
||||
try std.testing.expectApproxEqAbs(4.472135955, scaled2.data[0], 1e-4);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar Chained: velocity and acceleration" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
|
||||
const dist = try Meter.splat(alloc, 100);
|
||||
const t1 = try Second.splat(alloc, 5);
|
||||
const velocity = try dist.div(alloc, t1);
|
||||
try std.testing.expectEqual(20, velocity.data[0]);
|
||||
|
||||
const t2 = try Second.splat(alloc, 4);
|
||||
const accel = try velocity.div(alloc, t2);
|
||||
try std.testing.expectEqual(5, accel.data[0]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar DivBy integer exact" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
const Second = Tensor(f32, .{ .T = 1 }, .{}, &.{1});
|
||||
|
||||
const dist = try Meter.splat(alloc, 120);
|
||||
const time = try Second.splat(alloc, 4);
|
||||
const vel = try dist.div(alloc, time);
|
||||
try std.testing.expectEqual(30, vel.data[0]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar Finer scales skip dim 0" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Dimless = Tensor(i128, .{}, .{}, &.{1});
|
||||
const KiloMetre = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
|
||||
const r = try Dimless.splat(alloc, 30);
|
||||
const km = try KiloMetre.splat(alloc, 4);
|
||||
const vel = try r.mul(alloc, km);
|
||||
try std.testing.expectEqual(120, vel.data[0]);
|
||||
try std.testing.expectEqual(Scales.UnitScale.k, @TypeOf(vel).scales.get(.L));
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar Conversion chain: km -> m -> cm" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const KiloMeter = Tensor(i128, .{ .L = 1 }, .{ .L = .k }, &.{1});
|
||||
const Meter = Tensor(i128, .{ .L = 1 }, .{}, &.{1});
|
||||
const CentiMeter = Tensor(i128, .{ .L = 1 }, .{ .L = .c }, &.{1});
|
||||
|
||||
const km = try KiloMeter.splat(alloc, 15);
|
||||
const m = try km.to(alloc, Meter);
|
||||
const cm = try m.to(alloc, CentiMeter);
|
||||
try std.testing.expectEqual(15_000, m.data[0]);
|
||||
try std.testing.expectEqual(1_500_000, cm.data[0]);
|
||||
}
|
||||
|
||||
test "TensorAlloc | Scalar Conversion: hours -> minutes -> seconds" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const Hour = Tensor(i128, .{ .T = 1 }, .{ .T = .hour }, &.{1});
|
||||
const Minute = Tensor(i128, .{ .T = 1 }, .{ .T = .min }, &.{1});
|
||||
const Second = Tensor(i128, .{ .T = 1 }, .{}, &.{1});
|
||||
|
||||
const h = try Hour.splat(alloc, 1);
|
||||
const min = try h.to(alloc, Minute);
|
||||
const sec = try min.to(alloc, Second);
|
||||
try std.testing.expectEqual(60, min.data[0]);
|
||||
try std.testing.expectEqual(3600, sec.data[0]);
|
||||
}
|
||||
|
||||
// test "TensorAlloc | Scalar Format" {
|
||||
// const MeterPerSecondSq = Tensor(f32, .{ .L = 1, .T = -2 }, .{ .T = .n }, &.{1});
|
||||
// const Meter = Tensor(f32, .{ .L = 1 }, .{}, &.{1});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user