Skip to content

Commit f9783f8

Browse files
authored
Merge pull request #1 from Madmegsox1/axis-sum
[Addition] Added Summination along an axis
2 parents e4ea7fa + ac21694 commit f9783f8

File tree

3 files changed

+251
-0
lines changed

3 files changed

+251
-0
lines changed

src/helper.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ pub fn normalizeDim(dim: isize, n_dims: usize) !usize {
1111
return @as(usize, @intCast(adjusted));
1212
}
1313
}
14+
15+
pub fn product(arr: []usize) usize {
16+
var result: usize = 1;
17+
for (arr) |value| {
18+
result *= value;
19+
}
20+
return result;
21+
}

src/tensor.zig

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,49 @@ pub fn Tensor(comptime DataType: type) type {
472472
return result;
473473
}
474474

475+
/// Calculates the Sum along a given axis.
476+
///
477+
/// Prameters:
478+
/// - `Axis`: The axis which you want to sum.
479+
///
480+
/// Returns:
481+
/// - A `Tensor` in the resulting shape of the summination.
482+
pub fn sumAlongAxis(self: *Self, axis: usize) !Tensor(DataType) {
483+
if (axis >= self.shape.len) return error.IncorrectAxis;
484+
485+
// calculates the size of the result
486+
const resultSize = helper.product(self.shape[0..axis]) * helper.product(self.shape[axis + 1 ..]);
487+
const axisSize = self.shape[axis];
488+
489+
// calculates the resulting shap of the summed tensor
490+
const result_shape = try self.allocator.alloc(usize, self.shape.len - 1);
491+
defer self.allocator.free(result_shape);
492+
var res_idx: usize = 0;
493+
for (self.shape, 0..) |dim, i| {
494+
if (i != axis) {
495+
result_shape[res_idx] = dim;
496+
res_idx += 1;
497+
}
498+
}
499+
500+
var tensor = try Tensor(DataType).init(self.allocator, result_shape);
501+
502+
const stride = helper.product(self.shape[axis + 1 ..]);
503+
504+
for (0..resultSize) |i| {
505+
const innerIndex = i / stride * axisSize * stride + i % stride;
506+
var sum: DataType = 0;
507+
508+
for (0..axisSize) |j| {
509+
sum += self.data[innerIndex + j * stride];
510+
}
511+
512+
tensor.data[i] = sum;
513+
}
514+
515+
return tensor;
516+
}
517+
475518
/// Calculates the index based on the given parameters.
476519
///
477520
/// This function takes two parameters, `base` and `offset`, and returns the

src/tests.zig

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2987,3 +2987,203 @@ test "matmul numerical stability" {
29872987
}
29882988
}
29892989
}
2990+
2991+
test "sumAxis - i32 sum along axis 0" {
2992+
const allocator = testing.allocator;
2993+
2994+
var t = try Tensor(i32).init(allocator, &[_]usize {3, 3});
2995+
defer t.deinit();
2996+
2997+
t.data[0] = 1;
2998+
t.data[1] = 2;
2999+
t.data[2] = 3;
3000+
3001+
t.data[3] = 4;
3002+
t.data[4] = 5;
3003+
t.data[5] = 6;
3004+
3005+
t.data[6] = 7;
3006+
t.data[7] = 8;
3007+
t.data[8] = 9;
3008+
3009+
var sum = try t.sumAlongAxis(0);
3010+
defer sum.deinit();
3011+
3012+
try testing.expectEqualSlices(usize, &[_]usize {3}, sum.shape);
3013+
try testing.expect(sum.data[0] == 12);
3014+
try testing.expect(sum.data[1] == 15);
3015+
try testing.expect(sum.data[2] == 18);
3016+
}
3017+
3018+
test "sumAxis - i32 sum along axis 1" {
3019+
const allocator = testing.allocator;
3020+
3021+
var t = try Tensor(i32).init(allocator, &[_]usize {3, 3});
3022+
defer t.deinit();
3023+
3024+
t.data[0] = 1;
3025+
t.data[1] = 2;
3026+
t.data[2] = 3;
3027+
3028+
t.data[3] = 4;
3029+
t.data[4] = 5;
3030+
t.data[5] = 6;
3031+
3032+
t.data[6] = 7;
3033+
t.data[7] = 8;
3034+
t.data[8] = 9;
3035+
3036+
var sum = try t.sumAlongAxis(1);
3037+
defer sum.deinit();
3038+
3039+
try testing.expectEqualSlices(usize, &[_]usize {3}, sum.shape);
3040+
try testing.expect(sum.data[0] == 6);
3041+
try testing.expect(sum.data[1] == 15);
3042+
try testing.expect(sum.data[2] == 24);
3043+
}
3044+
3045+
test "sumAxis - f32 sum along axis 0" {
3046+
const allocator = testing.allocator;
3047+
3048+
var t = try Tensor(f32).init(allocator, &[_]usize {3, 3});
3049+
defer t.deinit();
3050+
3051+
t.data[0] = 1.5;
3052+
t.data[1] = 2.0;
3053+
t.data[2] = 3.0;
3054+
3055+
t.data[3] = 4.5;
3056+
t.data[4] = 5.0;
3057+
t.data[5] = 6.0;
3058+
3059+
t.data[6] = 7.5;
3060+
t.data[7] = 8.0;
3061+
t.data[8] = 9.0;
3062+
3063+
var sum = try t.sumAlongAxis(0);
3064+
defer sum.deinit();
3065+
3066+
try testing.expectEqualSlices(usize, &[_]usize {3}, sum.shape);
3067+
try testing.expect(sum.data[0] == 13.5);
3068+
try testing.expect(sum.data[1] == 15);
3069+
try testing.expect(sum.data[2] == 18);
3070+
}
3071+
3072+
test "sumAxis - f32 sum along axis 1" {
3073+
const allocator = testing.allocator;
3074+
3075+
var t = try Tensor(f32).init(allocator, &[_]usize {3, 3});
3076+
defer t.deinit();
3077+
3078+
t.data[0] = 1.5;
3079+
t.data[1] = 2.0;
3080+
t.data[2] = 3.0;
3081+
3082+
t.data[3] = 4.5;
3083+
t.data[4] = 5.0;
3084+
t.data[5] = 6.0;
3085+
3086+
t.data[6] = 7.5;
3087+
t.data[7] = 8.0;
3088+
t.data[8] = 9.0;
3089+
3090+
var sum = try t.sumAlongAxis(1);
3091+
defer sum.deinit();
3092+
3093+
try testing.expectEqualSlices(usize, &[_]usize {3}, sum.shape);
3094+
try testing.expect(sum.data[0] == 6.5);
3095+
try testing.expect(sum.data[1] == 15.5);
3096+
try testing.expect(sum.data[2] == 24.5);
3097+
}
3098+
3099+
test "sumAxis - sum uneven tensor on axis 0" {
3100+
const allocator = testing.allocator;
3101+
3102+
var t = try Tensor(i32).init(allocator, &[_]usize {4, 3});
3103+
defer t.deinit();
3104+
3105+
t.fill(1);
3106+
3107+
var sum = try t.sumAlongAxis(0);
3108+
defer sum.deinit();
3109+
3110+
try testing.expectEqualSlices(usize, &[_]usize {3}, sum.shape);
3111+
try testing.expect(sum.data[0] == 4);
3112+
try testing.expect(sum.data[1] == 4);
3113+
try testing.expect(sum.data[2] == 4);
3114+
}
3115+
3116+
test "sumAxis - sum uneven tensor on axis 1" {
3117+
const allocator = testing.allocator;
3118+
3119+
var t = try Tensor(i32).init(allocator, &[_]usize {4, 3});
3120+
defer t.deinit();
3121+
3122+
t.fill(1);
3123+
3124+
var sum = try t.sumAlongAxis(1);
3125+
defer sum.deinit();
3126+
3127+
3128+
try testing.expectEqualSlices(usize, &[_]usize {4}, sum.shape);
3129+
try testing.expect(sum.data[0] == 3);
3130+
try testing.expect(sum.data[1] == 3);
3131+
try testing.expect(sum.data[2] == 3);
3132+
try testing.expect(sum.data[3] == 3);
3133+
}
3134+
3135+
test "sumAxis - sum 3d tesor on axis 0" {
3136+
const allocator = testing.allocator;
3137+
3138+
var t = try Tensor(i32).init(allocator, &[_]usize {2, 3, 3});
3139+
defer t.deinit();
3140+
3141+
t.fill(1);
3142+
3143+
var sum = try t.sumAlongAxis(0);
3144+
defer sum.deinit();
3145+
3146+
3147+
try testing.expectEqualSlices(usize, &[_]usize {3,3}, sum.shape);
3148+
for (sum.data) |value| {
3149+
try testing.expect(value == 2);
3150+
}
3151+
}
3152+
3153+
test "sumAxis - sum 3d tesor on axis 1" {
3154+
const allocator = testing.allocator;
3155+
3156+
var t = try Tensor(i32).init(allocator, &[_]usize {2, 3, 3});
3157+
defer t.deinit();
3158+
3159+
t.fill(1);
3160+
3161+
var sum = try t.sumAlongAxis(1);
3162+
defer sum.deinit();
3163+
3164+
try testing.expectEqualSlices(usize, &[_]usize {2,3}, sum.shape);
3165+
for (sum.data) |value| {
3166+
try testing.expect(value == 3);
3167+
}
3168+
}
3169+
3170+
test "sumAxis - sum 3d tesor on axis 2" {
3171+
const allocator = testing.allocator;
3172+
3173+
var t = try Tensor(i32).init(allocator, &[_]usize {2, 3, 3});
3174+
defer t.deinit();
3175+
3176+
t.fill(1);
3177+
3178+
var sum = try t.sumAlongAxis(2);
3179+
defer sum.deinit();
3180+
3181+
3182+
try testing.expectEqualSlices(usize, &[_]usize {2,3}, sum.shape);
3183+
for (sum.data) |value| {
3184+
try testing.expect(value == 3);
3185+
}
3186+
3187+
}
3188+
3189+

0 commit comments

Comments
 (0)