Skip to content

Commit

Permalink
Merge pull request #1707 from xlsynth:cdleary/2024-11-11-std-distinct
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 695875384
  • Loading branch information
copybara-github committed Nov 12, 2024
2 parents 77efbf1 + afe585b commit 47f3f29
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
22 changes: 21 additions & 1 deletion docs_src/dslx_std.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn test_array_size() {
}
```

### `widening_cast` and `checked_cast`
### `widening_cast`, `checked_cast`

`widening_cast` and `checked_cast` cast bits-type values to bits-type values
with additional checks compared to casting with `as`.
Expand Down Expand Up @@ -1194,6 +1194,26 @@ index is used in a match expression (which will eagerly evaluate all of its
arms), to prevent it from creating an error at simulation time if the value is
ultimately discarded from the unselected match arm.

#### `std::distinct`

```dslx-snippet
pub fn distinct<COUNT: u32, N: u32, S: bool>(items: xN[S][N][COUNT], valid: bool[COUNT]) -> bool
```

Returns whether all the `items` are distinct (i.e. there are no duplicate
items) after the `valid` mask is applied.

```dslx
import std;
#[test]
fn test_distinct_with_invalid() {
let items = u8[4]:[1, 2, 3, 1];
let valid = bool[4]:[true, true, true, false];
assert_eq(std::distinct(items, valid), true);
}
```

## `import acm_random`

Port of
Expand Down
60 changes: 60 additions & 0 deletions xls/dslx/stdlib/std.x
Original file line number Diff line number Diff line change
Expand Up @@ -1309,3 +1309,63 @@ fn clzt_test() {

#[quickcheck]
fn prop_clzt_same_as_clz(x: u64) -> bool { clz(x) == clzt(x) as u64 }

/// Returns whether all the `items` are distinct (i.e. there are no duplicate
/// items) after the `valid` mask is applied.
pub fn distinct<COUNT: u32, N: u32, S: bool>(items: xN[S][N][COUNT], valid: bool[COUNT]) -> bool {
const INIT_ALL_DISTINCT = true;
for (i, all_distinct) in range(u32:0, COUNT) {
for (j, all_distinct) in range(u32:0, COUNT) {
if i != j && valid[i] && valid[j] && items[i] == items[j] {
false
} else {
all_distinct
}
}(all_distinct)
}(INIT_ALL_DISTINCT)
}

#[test]
fn test_simple_nondistinct() { assert_eq(distinct(u2[2]:[1, 1], bool[2]:[true, true]), false) }

#[test]
fn test_distinct_unsigned() {
let items = u8[4]:[1, 2, 3, 2];
let valid = bool[4]:[true, true, true, true];
assert_eq(distinct(items, valid), false);
}

#[test]
fn test_distinct_signed() {
let items = s8[3]:[-1, 0, 1];
let valid = bool[3]:[true, true, true];
assert_eq(distinct(items, valid), true);
}

#[test]
fn test_distinct_with_invalid() {
let items = u8[4]:[1, 2, 3, 1];
let valid = bool[4]:[true, true, true, false];
assert_eq(distinct(items, valid), true);
}

#[quickcheck]
fn quickcheck_forced_duplicate(xs: u4[4], to_dupe: u2) -> bool {
const ALL_VALID = bool[4]:[true, ...];
let forced_dupe = update(xs, (to_dupe as u32 + u32:1) % u32:4, xs[to_dupe]);
distinct(forced_dupe, ALL_VALID) == false
}

#[quickcheck]
fn quickcheck_distinct_all_valid_items_same(value: u4, valid: bool[4]) -> bool {
let items = u4[4]:[value, ...]; // All items are the same.
let num_valid = popcount(valid as u4) as u32;

if num_valid <= u32:1 {
// With 0 or 1 valid items, they are trivially distinct.
distinct(items, valid) == true
} else {
// Since all valid items are the same, 'distinct' should return false.
distinct(items, valid) == false
}
}

0 comments on commit 47f3f29

Please sign in to comment.