Repository navigation
Expand file tree
/
Copy pathsort.v
More file actions
117 lines (109 loc) · 3.11 KB
/
Copy pathsort.v
File metadata and controls
117 lines (109 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
module vtl
import math
// sort returns a copy sorted along the last axis, matching NumPy's default.
pub fn sort[T](t &Tensor[T]) !&Tensor[T] {
return sort_axis[T](t, -1)
}
// sort_axis returns a copy sorted in ascending order along axis. Floating-point
// NaNs sort after all non-NaN values, and equal values keep their input order.
pub fn sort_axis[T](t &Tensor[T], axis int) !&Tensor[T] {
axis_index := normalize_sort_axis(t, axis)!
mut result := empty[T](t.shape, memory: t.memory)
axis_size := t.shape[axis_index]
if t.size == 0 || axis_size == 0 {
return result
}
line_count := t.size / axis_size
mut index := []int{len: t.rank()}
mut values := []T{len: axis_size}
for line in 0 .. line_count {
decode_sort_line(line, t.shape, axis_index, mut index)
for position in 0 .. axis_size {
index[axis_index] = position
values[position] = t.get(index)
}
values.sort_with_compare(fn [T](a &T, b &T) int {
return compare_sort_values[T](*a, *b)
})
for position, value in values {
index[axis_index] = position
result.set(index, value)
}
}
return result
}
// argsort returns stable ascending sort indices along the last axis.
pub fn argsort[T](t &Tensor[T]) !&Tensor[int] {
return argsort_axis[T](t, -1)
}
// argsort_axis returns the stable ascending sort indices along axis. Returned
// indices are local to that axis; floating-point NaNs sort to the end.
pub fn argsort_axis[T](t &Tensor[T], axis int) !&Tensor[int] {
axis_index := normalize_sort_axis(t, axis)!
mut result := empty[int](t.shape, memory: t.memory)
axis_size := t.shape[axis_index]
if t.size == 0 || axis_size == 0 {
return result
}
line_count := t.size / axis_size
mut index := []int{len: t.rank()}
mut values := []T{len: axis_size}
mut positions := []int{len: axis_size}
for line in 0 .. line_count {
decode_sort_line(line, t.shape, axis_index, mut index)
for position in 0 .. axis_size {
index[axis_index] = position
values[position] = t.get(index)
positions[position] = position
}
positions.sort_with_compare(fn [values] (a &int, b &int) int {
return compare_sort_values(values[*a], values[*b])
})
for position, value in positions {
index[axis_index] = position
result.set(index, value)
}
}
return result
}
fn normalize_sort_axis[T](t &Tensor[T], axis int) !int {
rank := t.rank()
if rank == 0 {
return error('sort: tensor must have at least one dimension')
}
axis_index := if axis < 0 { axis + rank } else { axis }
if axis_index < 0 || axis_index >= rank {
return error('sort: axis ${axis} out of bounds for tensor with ${rank} dimensions')
}
return axis_index
}
fn decode_sort_line(line int, shape []int, axis int, mut index []int) {
mut remainder := line
for dim := shape.len - 1; dim >= 0; dim-- {
if dim == axis {
index[dim] = 0
continue
}
index[dim] = remainder % shape[dim]
remainder /= shape[dim]
}
}
fn compare_sort_values[T](a T, b T) int {
$if T is f32 || T is f64 {
a_nan := math.is_nan(f64(a))
b_nan := math.is_nan(f64(b))
if a_nan {
return if b_nan { 0 } else { 1 }
}
if b_nan {
return -1
}
}
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}