1
1
"""Metaclasses for defining transforms acting on benchmark records."""
2
2
3
+ from abc import ABC , abstractmethod
3
4
from typing import Sequence
4
5
5
6
from nnbench .types import BenchmarkRecord
8
9
class Transform :
9
10
"""The basic transform which every transform has to inherit from."""
10
11
11
- pass
12
-
13
-
14
- class OneToOneTransform (Transform ):
15
12
invertible : bool = True
16
13
"""
17
14
Whether this transform is invertible,
18
15
i.e. records can be converted back and forth with no changes or data loss.
19
16
"""
17
+ pass
20
18
19
+
20
+ class OneToOneTransform (ABC , Transform ):
21
+ @abstractmethod
21
22
def apply (self , record : BenchmarkRecord ) -> BenchmarkRecord :
22
- """
23
- Apply this transform to a benchmark record.
23
+ """Apply this transform to a benchmark record.
24
24
25
25
Parameters
26
26
----------
@@ -34,8 +34,7 @@ def apply(self, record: BenchmarkRecord) -> BenchmarkRecord:
34
34
"""
35
35
36
36
def iapply (self , record : BenchmarkRecord ) -> BenchmarkRecord :
37
- """
38
- Apply the inverse of this transform.
37
+ """Apply the inverse of this transform.
39
38
40
39
In general, applying the inverse on a record not previously transformed
41
40
may yield unexpected results.
@@ -49,25 +48,26 @@ def iapply(self, record: BenchmarkRecord) -> BenchmarkRecord:
49
48
-------
50
49
BenchmarkRecord
51
50
The inversely transformed benchmark record.
51
+
52
+ Raises
53
+ ------
54
+ RuntimeError
55
+ If the `Transform.invertible` attribute is set to `False`.
52
56
"""
57
+ if not self .invertible :
58
+ raise RuntimeError (f"{ self .__class__ .__name__ } () is marked as not invertible" )
59
+ raise NotImplementedError
53
60
54
61
55
62
class ManyToOneTransform (Transform ):
56
- """
57
- A many-to-one transform reducing a collection of records to a single record.
63
+ """A many-to-one transform reducing a collection of records to a single record.
58
64
59
65
This is useful for computing statistics on a collection of runs.
60
66
"""
61
67
62
- invertible : bool = True
63
- """
64
- Whether this transform is invertible,
65
- i.e. records can be converted back and forth with no changes or data loss.
66
- """
67
-
68
+ @abstractmethod
68
69
def apply (self , record : Sequence [BenchmarkRecord ]) -> BenchmarkRecord :
69
- """
70
- Apply this transform to a benchmark record.
70
+ """Apply this transform to a benchmark record.
71
71
72
72
Parameters
73
73
----------
@@ -82,8 +82,7 @@ def apply(self, record: Sequence[BenchmarkRecord]) -> BenchmarkRecord:
82
82
"""
83
83
84
84
def iapply (self , record : BenchmarkRecord ) -> Sequence [BenchmarkRecord ]:
85
- """
86
- Apply the inverse of this transform.
85
+ """Apply the inverse of this transform.
87
86
88
87
In general, applying the inverse on a record not previously transformed
89
88
may yield unexpected results.
@@ -97,31 +96,32 @@ def iapply(self, record: BenchmarkRecord) -> Sequence[BenchmarkRecord]:
97
96
-------
98
97
Sequence[BenchmarkRecord]
99
98
The inversely transformed benchmark record sequence.
99
+
100
+ Raises
101
+ ------
102
+ RuntimeError
103
+ If the `Transform.invertible` attribute is set to `False`.
100
104
"""
101
- # TODO: Does this even make sense? Can't hurt to allow it on paper, though.
105
+ if not self .invertible :
106
+ raise RuntimeError (f"{ self .__class__ .__name__ } () is marked as not invertible" )
107
+ raise NotImplementedError
102
108
103
109
104
110
class ManyToManyTransform (Transform ):
105
- """
106
- A many-to-many transform mapping an input record collection to an output collection.
111
+ """A many-to-many transform mapping an input record collection to an output collection.
107
112
108
113
Use this to programmatically wrangle metadata or types in records, or to
109
114
convert parameters into database-ready representations.
110
115
"""
111
116
112
- invertible : bool = True
113
- """
114
- Whether this transform is invertible,
115
- i.e. records can be converted back and forth with no changes or data loss.
116
- """
117
117
length_invariant : bool = True
118
118
"""
119
119
Whether this transform preserves the number of records, i.e. no records are dropped.
120
120
"""
121
121
122
+ @abstractmethod
122
123
def apply (self , record : Sequence [BenchmarkRecord ]) -> Sequence [BenchmarkRecord ]:
123
- """
124
- Apply this transform to a benchmark record.
124
+ """Apply this transform to a benchmark record.
125
125
126
126
Parameters
127
127
----------
@@ -135,8 +135,7 @@ def apply(self, record: Sequence[BenchmarkRecord]) -> Sequence[BenchmarkRecord]:
135
135
"""
136
136
137
137
def iapply (self , record : Sequence [BenchmarkRecord ]) -> Sequence [BenchmarkRecord ]:
138
- """
139
- Apply the inverse of this transform.
138
+ """Apply the inverse of this transform.
140
139
141
140
In general, applying the inverse on a record not previously transformed
142
141
may yield unexpected results.
@@ -150,4 +149,12 @@ def iapply(self, record: Sequence[BenchmarkRecord]) -> Sequence[BenchmarkRecord]
150
149
-------
151
150
Sequence[BenchmarkRecord]
152
151
The inversely transformed benchmark record sequence.
152
+
153
+ Raises
154
+ ------
155
+ RuntimeError
156
+ If the `Transform.invertible` attribute is set to `False`.
153
157
"""
158
+ if not self .invertible :
159
+ raise RuntimeError (f"{ self .__class__ .__name__ } () is marked as not invertible" )
160
+ raise NotImplementedError
0 commit comments