lib/accy/src/axis/roles.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 pub const Failure = enum {
 4     out_of_range,
 5     duplicate,
 6 };
 7 
 8 fn appearsInPriorGroup(
 9     groups: []const []const i64,
10     group_index: usize,
11     axis: i64,
12 ) bool {
13     for (groups[0..group_index]) |prior| {
14         for (prior) |seen| {
15             if (seen == axis) return true;
16         }
17     }
18     return false;
19 }
20 
21 pub fn check(
22     rank: usize,
23     groups: []const []const i64,
24 ) ?Failure {
25     for (groups, 0..) |group, group_index| {
26         for (group, 0..) |axis, axis_index| {
27             const index = std.math.cast(usize, axis) orelse
28                 return .out_of_range;
29             if (index >= rank) return .out_of_range;
30             if (appearsInPriorGroup(groups, group_index, axis)) {
31                 return .duplicate;
32             }
33             for (group[0..axis_index]) |seen| {
34                 if (seen == axis) return .duplicate;
35             }
36         }
37     }
38     return null;
39 }
40 
41 pub fn groupsOverlap(groups: []const []const i64) bool {
42     for (groups, 0..) |group, group_index| {
43         for (group) |axis| {
44             if (appearsInPriorGroup(groups, group_index, axis)) return true;
45         }
46     }
47     return false;
48 }
49 
50 test "axis role groups form a partial permutation" {
51     try std.testing.expect(check(4, &.{ &.{ 2, 0 }, &.{3} }) == null);
52     try std.testing.expectEqual(
53         Failure.out_of_range,
54         check(2, &.{&.{-1}}).?,
55     );
56     try std.testing.expectEqual(
57         Failure.out_of_range,
58         check(2, &.{&.{2}}).?,
59     );
60     try std.testing.expectEqual(
61         Failure.duplicate,
62         check(2, &.{&.{ 0, 0 }}).?,
63     );
64     try std.testing.expectEqual(
65         Failure.duplicate,
66         check(2, &.{ &.{0}, &.{0} }).?,
67     );
68     try std.testing.expect(!groupsOverlap(&.{ &.{ 2, 0 }, &.{3} }));
69     try std.testing.expect(groupsOverlap(&.{ &.{0}, &.{0} }));
70 }